mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-31 07:20:13 +00:00
API for adding init containers
This commit is contained in:
parent
fee8a55943
commit
6685715c4c
@ -131,6 +131,17 @@ func UpdatePodCondition(status *PodStatus, condition *PodCondition) bool {
|
||||
}
|
||||
}
|
||||
|
||||
// GetPodCondition extracts the provided condition from the given status and returns that.
|
||||
// Returns nil if the condition is not present.
|
||||
func GetPodCondition(status PodStatus, t PodConditionType) *PodCondition {
|
||||
for i, c := range status.Conditions {
|
||||
if c.Type == t {
|
||||
return &status.Conditions[i]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsNodeReady returns true if a node is ready; false otherwise.
|
||||
func IsNodeReady(node *Node) bool {
|
||||
for _, c := range node.Status.Conditions {
|
||||
|
@ -67,6 +67,9 @@ func TestUniversalDeserializer(t *testing.T) {
|
||||
func TestProtobufRoundTrip(t *testing.T) {
|
||||
obj := &v1.Pod{}
|
||||
apitesting.FuzzerFor(t, v1.SchemeGroupVersion, rand.NewSource(benchmarkSeed)).Fuzz(obj)
|
||||
// InitContainers are turned into annotations by conversion.
|
||||
obj.Spec.InitContainers = nil
|
||||
obj.Status.InitContainerStatuses = nil
|
||||
data, err := obj.Marshal()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -77,7 +80,7 @@ func TestProtobufRoundTrip(t *testing.T) {
|
||||
}
|
||||
if !api.Semantic.Equalities.DeepEqual(out, obj) {
|
||||
t.Logf("marshal\n%s", hex.Dump(data))
|
||||
t.Fatalf("Unmarshal is unequal\n%s", diff.ObjectGoPrintSideBySide(out, obj))
|
||||
t.Fatalf("Unmarshal is unequal\n%s", diff.ObjectGoPrintDiff(out, obj))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1076,6 +1076,8 @@ const (
|
||||
// PodReady means the pod is able to service requests and should be added to the
|
||||
// load balancing pools of all matching services.
|
||||
PodReady PodConditionType = "Ready"
|
||||
// PodInitialized means that all init containers in the pod have started successfully.
|
||||
PodInitialized PodConditionType = "Initialized"
|
||||
)
|
||||
|
||||
type PodCondition struct {
|
||||
@ -1309,7 +1311,9 @@ type PreferredSchedulingTerm struct {
|
||||
// PodSpec is a description of a pod
|
||||
type PodSpec struct {
|
||||
Volumes []Volume `json:"volumes"`
|
||||
// Required: there must be at least one container in a pod.
|
||||
// List of initialization containers belonging to the pod.
|
||||
InitContainers []Container `json:"-"`
|
||||
// List of containers belonging to the pod.
|
||||
Containers []Container `json:"containers"`
|
||||
RestartPolicy RestartPolicy `json:"restartPolicy,omitempty"`
|
||||
// Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request.
|
||||
@ -1416,6 +1420,11 @@ type PodStatus struct {
|
||||
// This is before the Kubelet pulled the container image(s) for the pod.
|
||||
StartTime *unversioned.Time `json:"startTime,omitempty"`
|
||||
|
||||
// The list has one entry per init container in the manifest. The most recent successful
|
||||
// init container will have ready = true, the most recently started container will have
|
||||
// startTime set.
|
||||
// More info: http://releases.k8s.io/HEAD/docs/user-guide/pod-states.md#container-statuses
|
||||
InitContainerStatuses []ContainerStatus `json:"-"`
|
||||
// The list has one entry per container in the manifest. Each entry is
|
||||
// currently the output of `docker inspect`. This output format is *not*
|
||||
// final and should not be relied upon.
|
||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
inf "gopkg.in/inf.v0"
|
||||
@ -258,6 +259,75 @@ func Convert_v1_ReplicationControllerSpec_To_api_ReplicationControllerSpec(in *R
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_api_PodStatusResult_To_v1_PodStatusResult(in *api.PodStatusResult, out *PodStatusResult, s conversion.Scope) error {
|
||||
if err := autoConvert_api_PodStatusResult_To_v1_PodStatusResult(in, out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(out.Status.InitContainerStatuses) > 0 {
|
||||
if out.Annotations == nil {
|
||||
out.Annotations = make(map[string]string)
|
||||
}
|
||||
value, err := json.Marshal(out.Status.InitContainerStatuses)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out.Annotations[PodInitContainerStatusesAnnotationKey] = string(value)
|
||||
} else {
|
||||
delete(in.Annotations, PodInitContainerStatusesAnnotationKey)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_v1_PodStatusResult_To_api_PodStatusResult(in *PodStatusResult, out *api.PodStatusResult, s conversion.Scope) error {
|
||||
// TODO: when we move init container to beta, remove these conversions
|
||||
if value := in.Annotations[PodInitContainerStatusesAnnotationKey]; len(value) > 0 {
|
||||
delete(in.Annotations, PodInitContainerStatusesAnnotationKey)
|
||||
var values []ContainerStatus
|
||||
if err := json.Unmarshal([]byte(value), &values); err != nil {
|
||||
return err
|
||||
}
|
||||
in.Status.InitContainerStatuses = values
|
||||
}
|
||||
|
||||
return autoConvert_v1_PodStatusResult_To_api_PodStatusResult(in, out, s)
|
||||
}
|
||||
|
||||
func Convert_api_PodTemplateSpec_To_v1_PodTemplateSpec(in *api.PodTemplateSpec, out *PodTemplateSpec, s conversion.Scope) error {
|
||||
if err := autoConvert_api_PodTemplateSpec_To_v1_PodTemplateSpec(in, out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: when we move init container to beta, remove these conversions
|
||||
if len(out.Spec.InitContainers) > 0 {
|
||||
if out.Annotations == nil {
|
||||
out.Annotations = make(map[string]string)
|
||||
}
|
||||
value, err := json.Marshal(out.Spec.InitContainers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out.Annotations[PodInitContainersAnnotationKey] = string(value)
|
||||
} else {
|
||||
delete(out.Annotations, PodInitContainersAnnotationKey)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(in *PodTemplateSpec, out *api.PodTemplateSpec, s conversion.Scope) error {
|
||||
// TODO: when we move init container to beta, remove these conversions
|
||||
if value := in.Annotations[PodInitContainersAnnotationKey]; len(value) > 0 {
|
||||
delete(in.Annotations, PodInitContainersAnnotationKey)
|
||||
var values []Container
|
||||
if err := json.Unmarshal([]byte(value), &values); err != nil {
|
||||
return err
|
||||
}
|
||||
in.Spec.InitContainers = values
|
||||
}
|
||||
|
||||
return autoConvert_v1_PodTemplateSpec_To_api_PodTemplateSpec(in, out, s)
|
||||
}
|
||||
|
||||
// The following two PodSpec conversions are done here to support ServiceAccount
|
||||
// as an alias for ServiceAccountName.
|
||||
func Convert_api_PodSpec_To_v1_PodSpec(in *api.PodSpec, out *PodSpec, s conversion.Scope) error {
|
||||
@ -271,6 +341,16 @@ func Convert_api_PodSpec_To_v1_PodSpec(in *api.PodSpec, out *PodSpec, s conversi
|
||||
} else {
|
||||
out.Volumes = nil
|
||||
}
|
||||
if in.InitContainers != nil {
|
||||
out.InitContainers = make([]Container, len(in.InitContainers))
|
||||
for i := range in.InitContainers {
|
||||
if err := Convert_api_Container_To_v1_Container(&in.InitContainers[i], &out.InitContainers[i], s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.InitContainers = nil
|
||||
}
|
||||
if in.Containers != nil {
|
||||
out.Containers = make([]Container, len(in.Containers))
|
||||
for i := range in.Containers {
|
||||
@ -346,6 +426,16 @@ func Convert_v1_PodSpec_To_api_PodSpec(in *PodSpec, out *api.PodSpec, s conversi
|
||||
} else {
|
||||
out.Volumes = nil
|
||||
}
|
||||
if in.InitContainers != nil {
|
||||
out.InitContainers = make([]api.Container, len(in.InitContainers))
|
||||
for i := range in.InitContainers {
|
||||
if err := Convert_v1_Container_To_api_Container(&in.InitContainers[i], &out.InitContainers[i], s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.InitContainers = nil
|
||||
}
|
||||
if in.Containers != nil {
|
||||
out.Containers = make([]api.Container, len(in.Containers))
|
||||
for i := range in.Containers {
|
||||
@ -419,6 +509,33 @@ func Convert_api_Pod_To_v1_Pod(in *api.Pod, out *Pod, s conversion.Scope) error
|
||||
if err := autoConvert_api_Pod_To_v1_Pod(in, out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: when we move init container to beta, remove these conversions
|
||||
if len(out.Spec.InitContainers) > 0 {
|
||||
if out.Annotations == nil {
|
||||
out.Annotations = make(map[string]string)
|
||||
}
|
||||
value, err := json.Marshal(out.Spec.InitContainers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out.Annotations[PodInitContainersAnnotationKey] = string(value)
|
||||
} else {
|
||||
delete(out.Annotations, PodInitContainersAnnotationKey)
|
||||
}
|
||||
if len(out.Status.InitContainerStatuses) > 0 {
|
||||
if out.Annotations == nil {
|
||||
out.Annotations = make(map[string]string)
|
||||
}
|
||||
value, err := json.Marshal(out.Status.InitContainerStatuses)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out.Annotations[PodInitContainerStatusesAnnotationKey] = string(value)
|
||||
} else {
|
||||
delete(in.Annotations, PodInitContainerStatusesAnnotationKey)
|
||||
}
|
||||
|
||||
// We need to reset certain fields for mirror pods from pre-v1.1 kubelet
|
||||
// (#15960).
|
||||
// TODO: Remove this code after we drop support for v1.0 kubelets.
|
||||
@ -434,6 +551,24 @@ func Convert_api_Pod_To_v1_Pod(in *api.Pod, out *Pod, s conversion.Scope) error
|
||||
}
|
||||
|
||||
func Convert_v1_Pod_To_api_Pod(in *Pod, out *api.Pod, s conversion.Scope) error {
|
||||
// TODO: when we move init container to beta, remove these conversions
|
||||
if value := in.Annotations[PodInitContainersAnnotationKey]; len(value) > 0 {
|
||||
delete(in.Annotations, PodInitContainersAnnotationKey)
|
||||
var values []Container
|
||||
if err := json.Unmarshal([]byte(value), &values); err != nil {
|
||||
return err
|
||||
}
|
||||
in.Spec.InitContainers = values
|
||||
}
|
||||
if value := in.Annotations[PodInitContainerStatusesAnnotationKey]; len(value) > 0 {
|
||||
delete(in.Annotations, PodInitContainerStatusesAnnotationKey)
|
||||
var values []ContainerStatus
|
||||
if err := json.Unmarshal([]byte(value), &values); err != nil {
|
||||
return err
|
||||
}
|
||||
in.Status.InitContainerStatuses = values
|
||||
}
|
||||
|
||||
return autoConvert_v1_Pod_To_api_Pod(in, out, s)
|
||||
}
|
||||
|
||||
|
@ -1106,7 +1106,7 @@ type Container struct {
|
||||
// Cannot be updated.
|
||||
// More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#resources
|
||||
Resources ResourceRequirements `json:"resources,omitempty" protobuf:"bytes,8,opt,name=resources"`
|
||||
// Pod volumes to mount into the container's filesyste.
|
||||
// Pod volumes to mount into the container's filesystem.
|
||||
// Cannot be updated.
|
||||
VolumeMounts []VolumeMount `json:"volumeMounts,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,9,rep,name=volumeMounts"`
|
||||
// Periodic probe of container liveness.
|
||||
@ -1541,11 +1541,36 @@ type PreferredSchedulingTerm struct {
|
||||
Preference NodeSelectorTerm `json:"preference" protobuf:"bytes,2,opt,name=preference"`
|
||||
}
|
||||
|
||||
const (
|
||||
// This annotation key will be used to contain an array of v1 JSON encoded Containers
|
||||
// for init containers. The annotation will be placed into the internal type and cleared.
|
||||
PodInitContainersAnnotationKey = "pod.alpha.kubernetes.io/init-containers"
|
||||
// This annotation key will be used to contain an array of v1 JSON encoded
|
||||
// ContainerStatuses for init containers. The annotation will be placed into the internal
|
||||
// type and cleared.
|
||||
PodInitContainerStatusesAnnotationKey = "pod.alpha.kubernetes.io/init-container-statuses"
|
||||
)
|
||||
|
||||
// PodSpec is a description of a pod.
|
||||
type PodSpec struct {
|
||||
// List of volumes that can be mounted by containers belonging to the pod.
|
||||
// More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md
|
||||
Volumes []Volume `json:"volumes,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,1,rep,name=volumes"`
|
||||
// List of initialization containers belonging to the pod.
|
||||
// Init containers are executed in order prior to containers being started. If any
|
||||
// init container fails, the pod is considered to have failed and is handled according
|
||||
// to its restartPolicy. The name for an init container or normal container must be
|
||||
// unique among all containers.
|
||||
// Init containers may not have Lifecycle actions, Readiness probes, or Liveness probes.
|
||||
// The resourceRequirements of an init container are taken into account during scheduling
|
||||
// by finding the highest request/limit for each resource type, and then using the max of
|
||||
// of that value or the sum of the normal containers. Limits are applied to init containers
|
||||
// in a similar fashion.
|
||||
// Init containers cannot currently be added or removed.
|
||||
// Init containers are in alpha state and may change without notice.
|
||||
// Cannot be updated.
|
||||
// More info: http://releases.k8s.io/HEAD/docs/user-guide/containers.md
|
||||
InitContainers []Container `json:"-" patchStrategy:"merge" patchMergeKey:"name"`
|
||||
// List of containers belonging to the pod.
|
||||
// Containers cannot currently be added or removed.
|
||||
// There must be at least one container in a Pod.
|
||||
@ -1679,6 +1704,12 @@ type PodStatus struct {
|
||||
// This is before the Kubelet pulled the container image(s) for the pod.
|
||||
StartTime *unversioned.Time `json:"startTime,omitempty" protobuf:"bytes,7,opt,name=startTime"`
|
||||
|
||||
// The list has one entry per init container in the manifest. The most recent successful
|
||||
// init container will have ready = true, the most recently started container will have
|
||||
// startTime set.
|
||||
// Init containers are in alpha state and may change without notice.
|
||||
// More info: http://releases.k8s.io/HEAD/docs/user-guide/pod-states.md#container-statuses
|
||||
InitContainerStatuses []ContainerStatus `json:"-"`
|
||||
// The list has one entry per container in the manifest. Each entry is currently the output
|
||||
// of `docker inspect`.
|
||||
// More info: http://releases.k8s.io/HEAD/docs/user-guide/pod-states.md#container-statuses
|
||||
|
@ -1326,6 +1326,37 @@ func validatePullPolicy(policy api.PullPolicy, fldPath *field.Path) field.ErrorL
|
||||
return allErrors
|
||||
}
|
||||
|
||||
func validateInitContainers(containers, otherContainers []api.Container, volumes sets.String, fldPath *field.Path) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
if len(containers) > 0 {
|
||||
allErrs = append(allErrs, validateContainers(containers, volumes, fldPath)...)
|
||||
}
|
||||
|
||||
allNames := sets.String{}
|
||||
for _, ctr := range otherContainers {
|
||||
allNames.Insert(ctr.Name)
|
||||
}
|
||||
for i, ctr := range containers {
|
||||
idxPath := fldPath.Index(i)
|
||||
if allNames.Has(ctr.Name) {
|
||||
allErrs = append(allErrs, field.Duplicate(idxPath.Child("name"), ctr.Name))
|
||||
}
|
||||
if len(ctr.Name) > 0 {
|
||||
allNames.Insert(ctr.Name)
|
||||
}
|
||||
if ctr.Lifecycle != nil {
|
||||
allErrs = append(allErrs, field.Invalid(idxPath.Child("lifecycle"), ctr.Lifecycle, "must not be set for init containers"))
|
||||
}
|
||||
if ctr.LivenessProbe != nil {
|
||||
allErrs = append(allErrs, field.Invalid(idxPath.Child("livenessProbe"), ctr.LivenessProbe, "must not be set for init containers"))
|
||||
}
|
||||
if ctr.ReadinessProbe != nil {
|
||||
allErrs = append(allErrs, field.Invalid(idxPath.Child("readinessProbe"), ctr.ReadinessProbe, "must not be set for init containers"))
|
||||
}
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateContainers(containers []api.Container, volumes sets.String, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
@ -1451,6 +1482,7 @@ func ValidatePodSpec(spec *api.PodSpec, fldPath *field.Path) field.ErrorList {
|
||||
allVolumes, vErrs := validateVolumes(spec.Volumes, fldPath.Child("volumes"))
|
||||
allErrs = append(allErrs, vErrs...)
|
||||
allErrs = append(allErrs, validateContainers(spec.Containers, allVolumes, fldPath.Child("containers"))...)
|
||||
allErrs = append(allErrs, validateInitContainers(spec.InitContainers, spec.Containers, allVolumes, fldPath.Child("initContainers"))...)
|
||||
allErrs = append(allErrs, validateRestartPolicy(&spec.RestartPolicy, fldPath.Child("restartPolicy"))...)
|
||||
allErrs = append(allErrs, validateDNSPolicy(&spec.DNSPolicy, fldPath.Child("dnsPolicy"))...)
|
||||
allErrs = append(allErrs, unversionedvalidation.ValidateLabels(spec.NodeSelector, fldPath.Child("nodeSelector"))...)
|
||||
|
Loading…
Reference in New Issue
Block a user