Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add lifecycle type and encoding/decoding support #491

Merged
merged 1 commit into from
Aug 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
188 changes: 165 additions & 23 deletions pkg/models/appconfiguration/workload/container/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
)

// Container describes how the Application's tasks are expected to be run.
type Container struct {
// Image to run for this container
Image string `yaml:"image" json:"image"`
Expand All @@ -19,12 +20,36 @@ type Container struct {
Env map[string]string `yaml:"env,omitempty" json:"env,omitempty"`
// The current working directory of the running process defined in entrypoint.
WorkingDir string `yaml:"workingDir,omitempty" json:"workingDir,omitempty"`
// Resource requirements for this container.
Resources map[string]string `yaml:"resources,omitempty" json:"resources,omitempty"`
// Files configures one or more files to be created in the container.
Files map[string]FileSpec `yaml:"files,omitempty" json:"files,omitempty"`
// Dirs configures one or more volumes to be mounted to the specified folder.
Dirs map[string]string `yaml:"dirs,omitempty" json:"dirs,omitempty"`
// Periodic probe of container liveness.
LivenessProbe *Probe `yaml:"livenessProbe,omitempty" json:"livenessProbe,omitempty"`
// Periodic probe of container service readiness.
ReadinessProbe *Probe `yaml:"readinessProbe,omitempty" json:"readinessProbe,omitempty"`
// StartupProbe indicates that the Pod has successfully initialized.
StartupProbe *Probe `yaml:"startupProbe,omitempty" json:"startupProbe,omitempty"`
// Actions that the management system should take in response to container lifecycle events.
Lifecycle *Lifecycle `yaml:"lifecycle,omitempty" json:"lifecycle,omitempty"`
}

// FileSpec defines the target file in a Container
type FileSpec struct {
// The content of target file in plain text.
Content string `yaml:"content,omitempty" json:"content,omitempty"`
// Source for the file content, might be a reference to a secret value.
ContentFrom string `yaml:"contentFrom,omitempty" json:"contentFrom,omitempty"`
// Mode bits used to set permissions on this file.
Mode string `yaml:"mode" json:"mode"`
}

// TypeWrapper is a thin wrapper to make YAML decoder happy.
type TypeWrapper struct {
// Type of action to be taken.
Type string `yaml:"_type" json:"_type"`
}

// Probe describes a health check to be performed against a container to determine whether it is
Expand All @@ -44,16 +69,11 @@ type Probe struct {
FailureThreshold int32 `yaml:"failureThreshold,omitempty" json:"failureThreshold,omitempty"`
}

type ProbeType struct {
// Type of action to be taken.
Type string `yaml:"_type" json:"_type"`
}

// ProbeHandler defines a specific action that should be taken in a probe.
// One and only one of the fields must be specified.
type ProbeHandler struct {
// Type of action to be taken.
ProbeType `yaml:"_type" json:"_type"`
TypeWrapper `yaml:"_type" json:"_type"`
// Exec specifies the action to take.
// +optional
*ExecAction `yaml:",inline" json:",inline"`
Expand Down Expand Up @@ -87,31 +107,55 @@ type TCPSocketAction struct {
URL string `yaml:"url,omitempty" json:"url,omitempty"`
}

// Lifecycle describes actions that the management system should take in response
// to container lifecycle events.
type Lifecycle struct {
// PreStop is called immediately before a container is terminated due to an
// API request or management event such as liveness/startup probe failure,
// preemption, resource contention, etc.
PreStop *LifecycleHandler `yaml:"preStop,omitempty" json:"preStop,omitempty"`
// PostStart is called immediately after a container is created.
PostStart *LifecycleHandler `yaml:"postStart,omitempty" json:"postStart,omitempty"`
}

// LifecycleHandler defines a specific action that should be taken in a lifecycle
// hook. One and only one of the fields, except TCPSocket must be specified.
type LifecycleHandler struct {
// Type of action to be taken.
TypeWrapper `yaml:"_type" json:"_type"`
// Exec specifies the action to take.
// +optional
*ExecAction `yaml:",inline" json:",inline"`
// HTTPGet specifies the http request to perform.
// +optional
*HTTPGetAction `yaml:",inline" json:",inline"`
}

// MarshalJSON implements the json.Marshaler interface for ProbeHandler.
func (p *ProbeHandler) MarshalJSON() ([]byte, error) {
switch p.Type {
case "Http":
return json.Marshal(struct {
ProbeType `json:",inline"`
TypeWrapper `json:",inline"`
*HTTPGetAction `json:",inline"`
}{
ProbeType: ProbeType{p.Type},
TypeWrapper: TypeWrapper{p.Type},
HTTPGetAction: p.HTTPGetAction,
})
case "Exec":
return json.Marshal(struct {
ProbeType `json:",inline"`
TypeWrapper `json:",inline"`
*ExecAction `json:",inline"`
}{
ProbeType: ProbeType{p.Type},
ExecAction: p.ExecAction,
TypeWrapper: TypeWrapper{p.Type},
ExecAction: p.ExecAction,
})
case "Tcp":
return json.Marshal(struct {
ProbeType `json:",inline"`
TypeWrapper `json:",inline"`
*TCPSocketAction `json:",inline"`
}{
ProbeType: ProbeType{p.Type},
TypeWrapper: TypeWrapper{p.Type},
TCPSocketAction: p.TCPSocketAction,
})
default:
Expand All @@ -121,7 +165,7 @@ func (p *ProbeHandler) MarshalJSON() ([]byte, error) {

// UnmarshalJSON implements the json.Unmarshaller interface for ProbeHandler.
func (p *ProbeHandler) UnmarshalJSON(data []byte) error {
var probeType ProbeType
var probeType TypeWrapper
err := json.Unmarshal(data, &probeType)
if err != nil {
return err
Expand Down Expand Up @@ -153,26 +197,26 @@ func (p *ProbeHandler) MarshalYAML() (interface{}, error) {
switch p.Type {
case "Http":
return struct {
ProbeType `yaml:",inline" json:",inline"`
TypeWrapper `yaml:",inline" json:",inline"`
HTTPGetAction `yaml:",inline" json:",inline"`
}{
ProbeType: ProbeType{Type: "Http"},
TypeWrapper: TypeWrapper{Type: p.Type},
HTTPGetAction: *p.HTTPGetAction,
}, nil
case "Exec":
return struct {
ProbeType `yaml:",inline" json:",inline"`
ExecAction `yaml:",inline" json:",inline"`
TypeWrapper `yaml:",inline" json:",inline"`
ExecAction `yaml:",inline" json:",inline"`
}{
ProbeType: ProbeType{Type: "Exec"},
ExecAction: *p.ExecAction,
TypeWrapper: TypeWrapper{Type: p.Type},
ExecAction: *p.ExecAction,
}, nil
case "Tcp":
return struct {
ProbeType `yaml:",inline" json:",inline"`
TypeWrapper `yaml:",inline" json:",inline"`
TCPSocketAction `yaml:",inline" json:",inline"`
}{
ProbeType: ProbeType{Type: "Tcp"},
TypeWrapper: TypeWrapper{Type: p.Type},
TCPSocketAction: *p.TCPSocketAction,
}, nil
}
Expand All @@ -182,7 +226,7 @@ func (p *ProbeHandler) MarshalYAML() (interface{}, error) {

// UnmarshalYAML implements the yaml.Unmarshaler interface for ProbeHandler.
func (p *ProbeHandler) UnmarshalYAML(unmarshal func(interface{}) error) error {
var probeType ProbeType
var probeType TypeWrapper
err := unmarshal(&probeType)
if err != nil {
return err
Expand All @@ -208,3 +252,101 @@ func (p *ProbeHandler) UnmarshalYAML(unmarshal func(interface{}) error) error {

return err
}

// MarshalJSON implements the json.Marshaler interface for LifecycleHandler.
func (l *LifecycleHandler) MarshalJSON() ([]byte, error) {
switch l.Type {
case "Http":
return json.Marshal(struct {
TypeWrapper `json:",inline"`
*HTTPGetAction `json:",inline"`
}{
TypeWrapper: TypeWrapper{l.Type},
HTTPGetAction: l.HTTPGetAction,
})
case "Exec":
return json.Marshal(struct {
TypeWrapper `json:",inline"`
*ExecAction `json:",inline"`
}{
TypeWrapper: TypeWrapper{l.Type},
ExecAction: l.ExecAction,
})
default:
return nil, errors.New("unrecognized lifecycle handler type")
}
}

// UnmarshalJSON implements the json.Unmarshaller interface for LifecycleHandler.
func (l *LifecycleHandler) UnmarshalJSON(data []byte) error {
var handlerType TypeWrapper
err := json.Unmarshal(data, &handlerType)
if err != nil {
return err
}

l.Type = handlerType.Type
switch l.Type {
case "Http":
handler := &HTTPGetAction{}
err = json.Unmarshal(data, handler)
l.HTTPGetAction = handler
case "Exec":
handler := &ExecAction{}
err = json.Unmarshal(data, handler)
l.ExecAction = handler
default:
return errors.New("unrecognized lifecycle handler type")
}

return err
}

// MarshalYAML implements the yaml.Marshaler interface for LifecycleHandler.
func (l *LifecycleHandler) MarshalYAML() (interface{}, error) {
switch l.Type {
case "Http":
return struct {
TypeWrapper `yaml:",inline" json:",inline"`
HTTPGetAction `yaml:",inline" json:",inline"`
}{
TypeWrapper: TypeWrapper{Type: l.Type},
HTTPGetAction: *l.HTTPGetAction,
}, nil
case "Exec":
return struct {
TypeWrapper `yaml:",inline" json:",inline"`
ExecAction `yaml:",inline" json:",inline"`
}{
TypeWrapper: TypeWrapper{Type: l.Type},
ExecAction: *l.ExecAction,
}, nil
default:
return nil, errors.New("unrecognized lifecycle handler type")
}
}

// UnmarshalYAML implements the yaml.Unmarshaler interface for LifecycleHandler.
func (l *LifecycleHandler) UnmarshalYAML(unmarshal func(interface{}) error) error {
var handlerType TypeWrapper
err := unmarshal(&handlerType)
if err != nil {
return err
}

l.Type = handlerType.Type
switch l.Type {
case "Http":
handler := &HTTPGetAction{}
err = unmarshal(handler)
l.HTTPGetAction = handler
case "Exec":
handler := &ExecAction{}
err = unmarshal(handler)
l.ExecAction = handler
default:
return errors.New("unrecognized lifecycle handler type")
}

return err
}
Loading
Loading