// StructuredGenerate outputs a deployment object using the configured fields func (s *DeploymentBasicGeneratorV1) StructuredGenerate() (runtime.Object, error) { if err := s.validate(); err != nil { return nil, err } podSpec := api.PodSpec{Containers: []api.Container{}} for _, imageString := range s.Images { imageSplit := strings.Split(imageString, "/") name := imageSplit[len(imageSplit)-1] podSpec.Containers = append(podSpec.Containers, api.Container{Name: name, Image: imageString}) } // setup default label and selector labels := map[string]string{} labels["app"] = s.Name selector := metav1.LabelSelector{MatchLabels: labels} deployment := extensions.Deployment{ ObjectMeta: api.ObjectMeta{ Name: s.Name, Labels: labels, }, Spec: extensions.DeploymentSpec{ Replicas: 1, Selector: &selector, Template: api.PodTemplateSpec{ ObjectMeta: api.ObjectMeta{ Labels: labels, }, Spec: podSpec, }, }, } return &deployment, nil }
func podSpec(containerImages ...string) kapi.PodSpec { spec := kapi.PodSpec{ Containers: []kapi.Container{}, } for _, image := range containerImages { container := kapi.Container{ Image: image, } spec.Containers = append(spec.Containers, container) } return spec }
func testPodNodeConstraintsPodSpec(nodeName string, nodeSelector map[string]string) kapi.PodSpec { spec := kapi.PodSpec{} spec.RestartPolicy = kapi.RestartPolicyAlways spec.NodeName = nodeName spec.NodeSelector = nodeSelector spec.Containers = []kapi.Container{ { Name: "container", Image: "test/image", }, } return spec }
func (v *VolumeOptions) addVolumeToSpec(spec *kapi.PodSpec, info *resource.Info, singleResource bool) error { opts := v.AddOpts if len(v.Name) == 0 { var err error v.Name, err = v.getVolumeName(spec, singleResource) if err != nil { return err } } newVolume := &kapi.Volume{ Name: v.Name, } setSource := true for i, vol := range spec.Volumes { if v.Name == vol.Name { if !opts.Overwrite { return fmt.Errorf("volume '%s' already exists. Use --overwrite to replace", v.Name) } if !opts.TypeChanged && len(opts.Source) == 0 { newVolume.VolumeSource = vol.VolumeSource setSource = false } spec.Volumes = append(spec.Volumes[:i], spec.Volumes[i+1:]...) break } } if setSource { err := v.setVolumeSource(newVolume) if err != nil { return err } } spec.Volumes = append(spec.Volumes, *newVolume) if len(opts.MountPath) > 0 { err := v.setVolumeMount(spec, info) if err != nil { return err } } return nil }
func Convert_v1_PodSpec_To_api_PodSpec(in *PodSpec, out *api.PodSpec, s conversion.Scope) error { if err := autoConvert_v1_PodSpec_To_api_PodSpec(in, out, s); err != nil { return err } // We support DeprecatedServiceAccount as an alias for ServiceAccountName. // If both are specified, ServiceAccountName (the new field) wins. if in.ServiceAccountName == "" { out.ServiceAccountName = in.DeprecatedServiceAccount } // the host namespace fields have to be handled specially for backward compatibility // with v1.0.0 if out.SecurityContext == nil { out.SecurityContext = new(api.PodSecurityContext) } out.SecurityContext.HostNetwork = in.HostNetwork out.SecurityContext.HostPID = in.HostPID out.SecurityContext.HostIPC = in.HostIPC return nil }
// EnsurePodSpecHasSecretVolume ensures that there is a volume with the given name and secret func EnsurePodSpecHasSecretVolume(podSpec *api.PodSpec, name string, secretName string) bool { for _, vm := range podSpec.Volumes { if vm.Name == name { vm.Secret = &api.SecretVolumeSource{ SecretName: secretName, } return true } } podSpec.Volumes = append(podSpec.Volumes, api.Volume{ Name: name, VolumeSource: api.VolumeSource{ Secret: &api.SecretVolumeSource{ SecretName: secretName, }, }, }) return false }
func (v *VolumeOptions) removeVolumeFromSpec(spec *kapi.PodSpec, info *resource.Info) error { containers, skippedContainers := selectContainers(spec.Containers, v.Containers) if len(containers) == 0 && v.Containers != "*" { fmt.Fprintf(v.Err, "warning: %s/%s does not have any containers matching %q\n", info.Mapping.Resource, info.Name, v.Containers) return nil } if len(v.Name) == 0 { for _, c := range containers { c.VolumeMounts = []kapi.VolumeMount{} } spec.Volumes = []kapi.Volume{} } else { err := v.removeSpecificVolume(spec, containers, skippedContainers) if err != nil { return err } } return nil }
// EnsurePodSpecHasGitVolume ensures that there is a volume with the given name and git repo and revision func EnsurePodSpecHasGitVolume(podSpec *api.PodSpec, name string, gitRepo string, gitRevision string) bool { for _, vm := range podSpec.Volumes { if vm.Name == name { vm.GitRepo = &api.GitRepoVolumeSource{ Repository: gitRepo, Revision: gitRevision, } return true } } podSpec.Volumes = append(podSpec.Volumes, api.Volume{ Name: name, VolumeSource: api.VolumeSource{ GitRepo: &api.GitRepoVolumeSource{ Repository: gitRepo, Revision: gitRevision, }, }, }) return false }
func (v *VolumeOptions) removeSpecificVolume(spec *kapi.PodSpec, containers, skippedContainers []*kapi.Container) error { for _, c := range containers { for i, m := range c.VolumeMounts { if v.Name == m.Name { c.VolumeMounts = append(c.VolumeMounts[:i], c.VolumeMounts[i+1:]...) break } } } // Remove volume if no container is using it found := false for _, c := range skippedContainers { for _, m := range c.VolumeMounts { if v.Name == m.Name { found = true break } } if found { break } } if !found { foundVolume := false for i, vol := range spec.Volumes { if v.Name == vol.Name { spec.Volumes = append(spec.Volumes[:i], spec.Volumes[i+1:]...) foundVolume = true break } } if !foundVolume { return fmt.Errorf("volume '%s' not found", v.Name) } } return nil }
func Convert_v1_PodSpec_To_api_PodSpec(in *v1.PodSpec, out *api.PodSpec, s conversion.Scope) error { if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { defaulting.(func(*v1.PodSpec))(in) } if in.Volumes != nil { out.Volumes = make([]api.Volume, len(in.Volumes)) for i := range in.Volumes { if err := Convert_v1_Volume_To_api_Volume(&in.Volumes[i], &out.Volumes[i], s); err != nil { return err } } } else { out.Volumes = nil } if in.Containers != nil { out.Containers = make([]api.Container, len(in.Containers)) for i := range in.Containers { if err := Convert_v1_Container_To_api_Container(&in.Containers[i], &out.Containers[i], s); err != nil { return err } } } else { out.Containers = nil } out.RestartPolicy = api.RestartPolicy(in.RestartPolicy) if in.TerminationGracePeriodSeconds != nil { out.TerminationGracePeriodSeconds = new(int64) *out.TerminationGracePeriodSeconds = *in.TerminationGracePeriodSeconds } else { out.TerminationGracePeriodSeconds = nil } if in.ActiveDeadlineSeconds != nil { out.ActiveDeadlineSeconds = new(int64) *out.ActiveDeadlineSeconds = *in.ActiveDeadlineSeconds } else { out.ActiveDeadlineSeconds = nil } out.DNSPolicy = api.DNSPolicy(in.DNSPolicy) if in.NodeSelector != nil { out.NodeSelector = make(map[string]string) for key, val := range in.NodeSelector { out.NodeSelector[key] = val } } else { out.NodeSelector = nil } // We support DeprecatedServiceAccount as an alias for ServiceAccountName. // If both are specified, ServiceAccountName (the new field) wins. out.ServiceAccountName = in.ServiceAccountName if in.ServiceAccountName == "" { out.ServiceAccountName = in.DeprecatedServiceAccount } out.NodeName = in.NodeName if in.SecurityContext != nil { out.SecurityContext = new(api.PodSecurityContext) if err := Convert_v1_PodSecurityContext_To_api_PodSecurityContext(in.SecurityContext, out.SecurityContext, s); err != nil { return err } } if out.SecurityContext == nil { out.SecurityContext = new(api.PodSecurityContext) } out.SecurityContext.HostNetwork = in.HostNetwork out.SecurityContext.HostPID = in.HostPID out.SecurityContext.HostIPC = in.HostIPC if in.ImagePullSecrets != nil { out.ImagePullSecrets = make([]api.LocalObjectReference, len(in.ImagePullSecrets)) for i := range in.ImagePullSecrets { if err := Convert_v1_LocalObjectReference_To_api_LocalObjectReference(&in.ImagePullSecrets[i], &out.ImagePullSecrets[i], s); err != nil { return err } } } else { out.ImagePullSecrets = nil } return nil }
// DeploymentConfig creates a deploymentConfig resource from the deployment configuration reference // // TODO: take a pod template spec as argument func (r *DeploymentConfigRef) DeploymentConfig() (*deployapi.DeploymentConfig, error) { if len(r.Name) == 0 { suggestions := NameSuggestions{} for i := range r.Images { suggestions = append(suggestions, r.Images[i]) } name, ok := suggestions.SuggestName() if !ok { return nil, fmt.Errorf("unable to suggest a name for this DeploymentConfig") } r.Name = name } selector := map[string]string{ "deploymentconfig": r.Name, } if len(r.Labels) > 0 { if err := util.MergeInto(selector, r.Labels, 0); err != nil { return nil, err } } triggers := []deployapi.DeploymentTriggerPolicy{ // By default, always deploy on change { Type: deployapi.DeploymentTriggerOnConfigChange, }, } annotations := make(map[string]string) template := kapi.PodSpec{} for i := range r.Images { c, containerTriggers, err := r.Images[i].DeployableContainer() if err != nil { return nil, err } triggers = append(triggers, containerTriggers...) template.Containers = append(template.Containers, *c) if cmd, ok := r.Images[i].Command(); ok { imageapi.SetContainerImageEntrypointAnnotation(annotations, c.Name, cmd) } } // Create EmptyDir volumes for all container volume mounts for _, c := range template.Containers { for _, v := range c.VolumeMounts { template.Volumes = append(template.Volumes, kapi.Volume{ Name: v.Name, VolumeSource: kapi.VolumeSource{ EmptyDir: &kapi.EmptyDirVolumeSource{Medium: kapi.StorageMediumDefault}, }, }) } } for i := range template.Containers { template.Containers[i].Env = append(template.Containers[i].Env, r.Env.List()...) } dc := &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{ Name: r.Name, }, Spec: deployapi.DeploymentConfigSpec{ Replicas: 1, Test: r.AsTest, Selector: selector, Template: &kapi.PodTemplateSpec{ ObjectMeta: kapi.ObjectMeta{ Labels: selector, Annotations: annotations, }, Spec: template, }, Triggers: triggers, }, } if r.PostHook != nil { //dc.Spec.Strategy.Type = "Rolling" if len(r.PostHook.Shell) > 0 { dc.Spec.Strategy.RecreateParams = &deployapi.RecreateDeploymentStrategyParams{ Post: &deployapi.LifecycleHook{ ExecNewPod: &deployapi.ExecNewPodHook{ Command: []string{"/bin/sh", "-c", r.PostHook.Shell}, }, }, } } } return dc, nil }
func Convert_v1_PodSpec_To_api_PodSpec(in *PodSpec, out *api.PodSpec, s conversion.Scope) error { SetDefaults_PodSpec(in) if in.Volumes != nil { out.Volumes = make([]api.Volume, len(in.Volumes)) for i := range in.Volumes { if err := Convert_v1_Volume_To_api_Volume(&in.Volumes[i], &out.Volumes[i], s); err != nil { return err } } } 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 { if err := Convert_v1_Container_To_api_Container(&in.Containers[i], &out.Containers[i], s); err != nil { return err } } } else { out.Containers = nil } out.RestartPolicy = api.RestartPolicy(in.RestartPolicy) out.TerminationGracePeriodSeconds = in.TerminationGracePeriodSeconds out.ActiveDeadlineSeconds = in.ActiveDeadlineSeconds out.DNSPolicy = api.DNSPolicy(in.DNSPolicy) out.NodeSelector = in.NodeSelector // We support DeprecatedServiceAccount as an alias for ServiceAccountName. // If both are specified, ServiceAccountName (the new field) wins. out.ServiceAccountName = in.ServiceAccountName if in.ServiceAccountName == "" { out.ServiceAccountName = in.DeprecatedServiceAccount } out.NodeName = in.NodeName if in.SecurityContext != nil { out.SecurityContext = new(api.PodSecurityContext) if err := Convert_v1_PodSecurityContext_To_api_PodSecurityContext(in.SecurityContext, out.SecurityContext, s); err != nil { return err } } // the host namespace fields have to be handled specially for backward compatibility // with v1.0.0 if out.SecurityContext == nil { out.SecurityContext = new(api.PodSecurityContext) } out.SecurityContext.HostNetwork = in.HostNetwork out.SecurityContext.HostPID = in.HostPID out.SecurityContext.HostIPC = in.HostIPC if in.ImagePullSecrets != nil { out.ImagePullSecrets = make([]api.LocalObjectReference, len(in.ImagePullSecrets)) for i := range in.ImagePullSecrets { if err := Convert_v1_LocalObjectReference_To_api_LocalObjectReference(&in.ImagePullSecrets[i], &out.ImagePullSecrets[i], s); err != nil { return err } } } else { out.ImagePullSecrets = nil } out.Hostname = in.Hostname out.Subdomain = in.Subdomain return nil }
func convert_v1beta3_PodSpec_To_api_PodSpec(in *PodSpec, out *api.PodSpec, s conversion.Scope) error { if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { defaulting.(func(*PodSpec))(in) } if in.Volumes != nil { out.Volumes = make([]api.Volume, len(in.Volumes)) for i := range in.Volumes { if err := convert_v1beta3_Volume_To_api_Volume(&in.Volumes[i], &out.Volumes[i], s); err != nil { return err } } } else { out.Volumes = nil } if in.Containers != nil { out.Containers = make([]api.Container, len(in.Containers)) for i := range in.Containers { if err := convert_v1beta3_Container_To_api_Container(&in.Containers[i], &out.Containers[i], s); err != nil { return err } } } else { out.Containers = nil } out.RestartPolicy = api.RestartPolicy(in.RestartPolicy) if in.TerminationGracePeriodSeconds != nil { out.TerminationGracePeriodSeconds = new(int64) *out.TerminationGracePeriodSeconds = *in.TerminationGracePeriodSeconds } else { out.TerminationGracePeriodSeconds = nil } if in.ActiveDeadlineSeconds != nil { out.ActiveDeadlineSeconds = new(int64) *out.ActiveDeadlineSeconds = *in.ActiveDeadlineSeconds } else { out.ActiveDeadlineSeconds = nil } out.DNSPolicy = api.DNSPolicy(in.DNSPolicy) if in.NodeSelector != nil { out.NodeSelector = make(map[string]string) for key, val := range in.NodeSelector { out.NodeSelector[key] = val } } else { out.NodeSelector = nil } out.ServiceAccountName = in.ServiceAccount out.NodeName = in.Host out.HostNetwork = in.HostNetwork if in.ImagePullSecrets != nil { out.ImagePullSecrets = make([]api.LocalObjectReference, len(in.ImagePullSecrets)) for i := range in.ImagePullSecrets { if err := convert_v1beta3_LocalObjectReference_To_api_LocalObjectReference(&in.ImagePullSecrets[i], &out.ImagePullSecrets[i], s); err != nil { return err } } } else { out.ImagePullSecrets = nil } return nil }
// DeploymentConfig creates a deploymentConfig resource from the deployment configuration reference // // TODO: take a pod template spec as argument func (r *DeploymentConfigRef) DeploymentConfig() (*deployapi.DeploymentConfig, error) { if len(r.Name) == 0 { suggestions := NameSuggestions{} for i := range r.Images { suggestions = append(suggestions, r.Images[i]) } name, ok := suggestions.SuggestName() if !ok { return nil, fmt.Errorf("unable to suggest a name for this DeploymentConfig") } r.Name = name } selector := map[string]string{ "deploymentconfig": r.Name, } if len(r.Labels) > 0 { if err := util.MergeInto(selector, r.Labels, 0); err != nil { return nil, err } } triggers := []deployapi.DeploymentTriggerPolicy{ // By default, always deploy on change { Type: deployapi.DeploymentTriggerOnConfigChange, }, } template := kapi.PodSpec{} for i := range r.Images { c, containerTriggers, err := r.Images[i].DeployableContainer() if err != nil { return nil, err } triggers = append(triggers, containerTriggers...) template.Containers = append(template.Containers, *c) } // Create EmptyDir volumes for all container volume mounts for _, c := range template.Containers { for _, v := range c.VolumeMounts { template.Volumes = append(template.Volumes, kapi.Volume{ Name: v.Name, VolumeSource: kapi.VolumeSource{ EmptyDir: &kapi.EmptyDirVolumeSource{Medium: kapi.StorageMediumDefault}, }, }) } } for i := range template.Containers { template.Containers[i].Env = append(template.Containers[i].Env, r.Env.List()...) } return &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{ Name: r.Name, }, Template: deployapi.DeploymentTemplate{ ControllerTemplate: kapi.ReplicationControllerSpec{ Replicas: 1, Selector: selector, Template: &kapi.PodTemplateSpec{ ObjectMeta: kapi.ObjectMeta{ Labels: selector, }, Spec: template, }, }, }, Triggers: triggers, }, nil }
// Deploys an app based on the given configuration. The app is deployed using the given client. // App deployment consists of a replication controller and an optional service. Both of them share // common labels. func DeployApp(spec *AppDeploymentSpec, client client.Interface) error { log.Printf("Deploying %s application into %s namespace", spec.Name, spec.Namespace) annotations := map[string]string{} if spec.Description != nil { annotations[DescriptionAnnotationKey] = *spec.Description } labels := getLabelsMap(spec.Labels) objectMeta := api.ObjectMeta{ Annotations: annotations, Name: spec.Name, Labels: labels, } containerSpec := api.Container{ Name: spec.Name, Image: spec.ContainerImage, SecurityContext: &api.SecurityContext{ Privileged: &spec.RunAsPrivileged, }, Resources: api.ResourceRequirements{ Requests: make(map[api.ResourceName]resource.Quantity), }, Env: convertEnvVarsSpec(spec.Variables), } if spec.ContainerCommand != nil { containerSpec.Command = []string{*spec.ContainerCommand} } if spec.ContainerCommandArgs != nil { containerSpec.Args = []string{*spec.ContainerCommandArgs} } if spec.CpuRequirement != nil { containerSpec.Resources.Requests[api.ResourceCPU] = *spec.CpuRequirement } if spec.MemoryRequirement != nil { containerSpec.Resources.Requests[api.ResourceMemory] = *spec.MemoryRequirement } podSpec := api.PodSpec{ Containers: []api.Container{containerSpec}, } if spec.ImagePullSecret != nil { podSpec.ImagePullSecrets = []api.LocalObjectReference{{Name: *spec.ImagePullSecret}} } podTemplate := &api.PodTemplateSpec{ ObjectMeta: objectMeta, Spec: podSpec, } replicationController := &api.ReplicationController{ ObjectMeta: objectMeta, Spec: api.ReplicationControllerSpec{ Replicas: spec.Replicas, Selector: labels, Template: podTemplate, }, } _, err := client.ReplicationControllers(spec.Namespace).Create(replicationController) if err != nil { // TODO(bryk): Roll back created resources in case of error. return err } if len(spec.PortMappings) > 0 { service := &api.Service{ ObjectMeta: objectMeta, Spec: api.ServiceSpec{ Selector: labels, }, } if spec.IsExternal { service.Spec.Type = api.ServiceTypeLoadBalancer } else { service.Spec.Type = api.ServiceTypeClusterIP } for _, portMapping := range spec.PortMappings { servicePort := api.ServicePort{ Protocol: portMapping.Protocol, Port: portMapping.Port, Name: generatePortMappingName(portMapping), TargetPort: intstr.IntOrString{ Type: intstr.Int, IntVal: portMapping.TargetPort, }, } service.Spec.Ports = append(service.Spec.Ports, servicePort) } _, err = client.Services(spec.Namespace).Create(service) // TODO(bryk): Roll back created resources in case of error. return err } else { return nil } }
func buildPodSpec(podSpecs []interface{}) api.PodSpec { if len(podSpecs) == 0 { return api.PodSpec{} } userPodSpec := podSpecs[0].(map[string]interface{}) podSpec := api.PodSpec{ Containers: buildContainers(userPodSpec["containers"].([]interface{})), ActiveDeadlineSeconds: nil, TerminationGracePeriodSeconds: nil, } if _, ok := userPodSpec["node_selector"]; ok { podSpec.NodeSelector = convertMapTypeToStringMap(userPodSpec["node_selector"].(map[string]interface{})) } if _, ok := userPodSpec["node_name"]; ok { podSpec.NodeName = userPodSpec["node_name"].(string) } if _, ok := userPodSpec["service_account_name"]; ok { podSpec.ServiceAccountName = userPodSpec["service_account_name"].(string) } if _, ok := userPodSpec["host_network"]; ok { podSpec.HostNetwork = userPodSpec["host_network"].(bool) } if _, ok := userPodSpec["termination_grace_period"]; ok { helper := int64(userPodSpec["termination_grace_period"].(int)) podSpec.TerminationGracePeriodSeconds = &helper if helper > 0 { podSpec.TerminationGracePeriodSeconds = &helper } else { podSpec.TerminationGracePeriodSeconds = nil } } else { podSpec.TerminationGracePeriodSeconds = nil } if _, ok := userPodSpec["active_deadline_seconds"]; ok { helper := int64(userPodSpec["active_deadline_seconds"].(int)) if helper > 0 { podSpec.ActiveDeadlineSeconds = &helper } else { podSpec.ActiveDeadlineSeconds = nil } } else { podSpec.ActiveDeadlineSeconds = nil } if _, ok := userPodSpec["restart_policy"]; ok { podSpec.RestartPolicy = api.RestartPolicy(userPodSpec["restart_policy"].(string)) } return podSpec }
func deepCopy_api_PodSpec(in api.PodSpec, out *api.PodSpec, c *conversion.Cloner) error { if in.Volumes != nil { out.Volumes = make([]api.Volume, len(in.Volumes)) for i := range in.Volumes { if err := deepCopy_api_Volume(in.Volumes[i], &out.Volumes[i], c); err != nil { return err } } } else { out.Volumes = nil } if in.Containers != nil { out.Containers = make([]api.Container, len(in.Containers)) for i := range in.Containers { if err := deepCopy_api_Container(in.Containers[i], &out.Containers[i], c); err != nil { return err } } } else { out.Containers = nil } out.RestartPolicy = in.RestartPolicy if in.TerminationGracePeriodSeconds != nil { out.TerminationGracePeriodSeconds = new(int64) *out.TerminationGracePeriodSeconds = *in.TerminationGracePeriodSeconds } else { out.TerminationGracePeriodSeconds = nil } if in.ActiveDeadlineSeconds != nil { out.ActiveDeadlineSeconds = new(int64) *out.ActiveDeadlineSeconds = *in.ActiveDeadlineSeconds } else { out.ActiveDeadlineSeconds = nil } out.DNSPolicy = in.DNSPolicy if in.NodeSelector != nil { out.NodeSelector = make(map[string]string) for key, val := range in.NodeSelector { out.NodeSelector[key] = val } } else { out.NodeSelector = nil } out.ServiceAccountName = in.ServiceAccountName out.NodeName = in.NodeName out.HostNetwork = in.HostNetwork out.HostPID = in.HostPID out.HostIPC = in.HostIPC if in.ImagePullSecrets != nil { out.ImagePullSecrets = make([]api.LocalObjectReference, len(in.ImagePullSecrets)) for i := range in.ImagePullSecrets { if err := deepCopy_api_LocalObjectReference(in.ImagePullSecrets[i], &out.ImagePullSecrets[i], c); err != nil { return err } } } else { out.ImagePullSecrets = nil } return nil }