Created
April 22, 2020 11:43
-
-
Save danielchg/7c32cdf0b272143046db86b9620b61a5 to your computer and use it in GitHub Desktop.
drone runner kube
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Copyright 2019 Drone.IO Inc. All rights reserved. | |
| // Use of this source code is governed by the Polyform License | |
| // that can be found in the LICENSE file. | |
| package engine | |
| import ( | |
| "strings" | |
| v1 "k8s.io/api/core/v1" | |
| "k8s.io/apimachinery/pkg/api/resource" | |
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | |
| ) | |
| func toPod(spec *Spec) *v1.Pod { | |
| var RunAsUID int64 = 1000 | |
| var FSGuid int64 = 1000 | |
| return &v1.Pod{ | |
| ObjectMeta: metav1.ObjectMeta{ | |
| Name: spec.PodSpec.Name, | |
| Namespace: spec.PodSpec.Namespace, | |
| Annotations: spec.PodSpec.Annotations, | |
| Labels: spec.PodSpec.Labels, | |
| }, | |
| Spec: v1.PodSpec{ | |
| ServiceAccountName: spec.PodSpec.ServiceAccountName, | |
| SecurityContext: &v1.PodSecurityContext{ | |
| RunAsUser: &RunAsUID, | |
| FSGroup: &FSGuid, | |
| }, | |
| RestartPolicy: v1.RestartPolicyNever, | |
| Volumes: toVolumes(spec), | |
| Containers: toContainers(spec), | |
| NodeName: spec.PodSpec.NodeName, | |
| NodeSelector: spec.PodSpec.NodeSelector, | |
| Tolerations: toTolerations(spec), | |
| ImagePullSecrets: toImagePullSecrets(spec), | |
| HostAliases: toHostAliases(spec), | |
| DNSConfig: toDnsConfig(spec), | |
| }, | |
| } | |
| } | |
| func toDnsConfig(spec *Spec) *v1.PodDNSConfig { | |
| var dnsOptions []v1.PodDNSConfigOption | |
| if len(spec.PodSpec.DnsConfig.Options) > 0 { | |
| for _, option := range spec.PodSpec.DnsConfig.Options { | |
| o := v1.PodDNSConfigOption{ | |
| Name: option.Name, | |
| Value: option.Value, | |
| } | |
| dnsOptions = append(dnsOptions, o) | |
| } | |
| } | |
| return &v1.PodDNSConfig{ | |
| Nameservers: spec.PodSpec.DnsConfig.Nameservers, | |
| Searches: spec.PodSpec.DnsConfig.Searches, | |
| Options: dnsOptions, | |
| } | |
| } | |
| func toHostAliases(spec *Spec) []v1.HostAlias { | |
| var hostAliases []v1.HostAlias | |
| for _, hostAlias := range spec.PodSpec.HostAliases { | |
| if len(hostAlias.Hostnames) > 0 { | |
| hostAliases = append(hostAliases, v1.HostAlias{ | |
| IP: hostAlias.IP, | |
| Hostnames: hostAlias.Hostnames, | |
| }) | |
| } | |
| } | |
| return hostAliases | |
| } | |
| func toTolerations(spec *Spec) []v1.Toleration { | |
| var tolerations []v1.Toleration | |
| for _, toleration := range spec.PodSpec.Tolerations { | |
| t := v1.Toleration{ | |
| Key: toleration.Key, | |
| Operator: v1.TolerationOperator(toleration.Operator), | |
| Effect: v1.TaintEffect(toleration.Effect), | |
| Value: toleration.Value, | |
| } | |
| if toleration.TolerationSeconds != nil { | |
| t.TolerationSeconds = int64ptr(int64(*toleration.TolerationSeconds)) | |
| } | |
| tolerations = append(tolerations, t) | |
| } | |
| return tolerations | |
| } | |
| func toVolumes(spec *Spec) []v1.Volume { | |
| var volumes []v1.Volume | |
| for _, v := range spec.Volumes { | |
| if v.EmptyDir != nil { | |
| source := &v1.EmptyDirVolumeSource{} | |
| if strings.EqualFold(v.EmptyDir.Medium, "memory") { | |
| source.Medium = v1.StorageMediumMemory | |
| if v.EmptyDir.SizeLimit > int64(0) { | |
| source.SizeLimit = resource.NewQuantity(v.EmptyDir.SizeLimit, resource.BinarySI) | |
| } | |
| } | |
| volume := v1.Volume{ | |
| Name: v.EmptyDir.ID, | |
| VolumeSource: v1.VolumeSource{ | |
| EmptyDir: source, | |
| }, | |
| } | |
| volumes = append(volumes, volume) | |
| } | |
| if v.HostPath != nil { | |
| hostPathType := v1.HostPathDirectoryOrCreate | |
| volume := v1.Volume{ | |
| Name: v.HostPath.ID, | |
| VolumeSource: v1.VolumeSource{ | |
| HostPath: &v1.HostPathVolumeSource{ | |
| Path: v.HostPath.Path, | |
| Type: &hostPathType, | |
| }, | |
| }, | |
| } | |
| volumes = append(volumes, volume) | |
| } | |
| if v.Claim != nil { | |
| volume := v1.Volume{ | |
| Name: v.Claim.ID, | |
| VolumeSource: v1.VolumeSource{ | |
| PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ | |
| ClaimName: v.Claim.ClaimName, | |
| ReadOnly: v.Claim.ReadOnly, | |
| }, | |
| }, | |
| } | |
| volumes = append(volumes, volume) | |
| } | |
| if v.DownwardAPI != nil { | |
| var items []v1.DownwardAPIVolumeFile | |
| for _, item := range v.DownwardAPI.Items { | |
| items = append(items, v1.DownwardAPIVolumeFile{ | |
| Path: item.Path, | |
| FieldRef: &v1.ObjectFieldSelector{ | |
| FieldPath: item.FieldPath, | |
| }, | |
| }) | |
| } | |
| volume := v1.Volume{ | |
| Name: v.DownwardAPI.ID, | |
| VolumeSource: v1.VolumeSource{ | |
| DownwardAPI: &v1.DownwardAPIVolumeSource{ | |
| Items: items, | |
| }, | |
| }, | |
| } | |
| volumes = append(volumes, volume) | |
| } | |
| } | |
| return volumes | |
| } | |
| func toContainers(spec *Spec) []v1.Container { | |
| var containers []v1.Container | |
| var allowScalation bool = true | |
| for _, s := range spec.Steps { | |
| container := v1.Container{ | |
| Name: s.ID, | |
| Image: s.Placeholder, | |
| Command: s.Entrypoint, | |
| Args: s.Command, | |
| ImagePullPolicy: toPullPolicy(s.Pull), | |
| WorkingDir: s.WorkingDir, | |
| Resources: toResources(s.Resources), | |
| SecurityContext: &v1.SecurityContext{ | |
| Privileged: boolptr(s.Privileged), | |
| AllowPrivilegeEscalation: &allowScalation, | |
| }, | |
| VolumeMounts: toVolumeMounts(spec, s), | |
| Env: toEnv(spec, s), | |
| } | |
| containers = append(containers, container) | |
| } | |
| return containers | |
| } | |
| func toEnv(spec *Spec, step *Step) []v1.EnvVar { | |
| var envVars []v1.EnvVar | |
| for k, v := range step.Envs { | |
| envVars = append(envVars, v1.EnvVar{ | |
| Name: k, | |
| Value: v, | |
| }) | |
| } | |
| for _, secret := range step.Secrets { | |
| envVars = append(envVars, v1.EnvVar{ | |
| Name: secret.Env, | |
| ValueFrom: &v1.EnvVarSource{ | |
| SecretKeyRef: &v1.SecretKeySelector{ | |
| LocalObjectReference: v1.LocalObjectReference{ | |
| Name: spec.PodSpec.Name, | |
| }, | |
| Key: secret.Name, | |
| Optional: boolptr(true), | |
| }, | |
| }, | |
| }) | |
| } | |
| envVars = append(envVars, v1.EnvVar{ | |
| Name: "KUBERNETES_NODE", | |
| ValueFrom: &v1.EnvVarSource{ | |
| FieldRef: &v1.ObjectFieldSelector{ | |
| FieldPath: "spec.nodeName", | |
| }, | |
| }, | |
| }) | |
| return envVars | |
| } | |
| func toEnvFrom(step *Step) []v1.EnvFromSource { | |
| return []v1.EnvFromSource{ | |
| { | |
| SecretRef: &v1.SecretEnvSource{ | |
| LocalObjectReference: v1.LocalObjectReference{ | |
| Name: step.ID, | |
| }, | |
| }, | |
| }, | |
| } | |
| } | |
| func toSecret(spec *Spec) *v1.Secret { | |
| stringData := make(map[string]string) | |
| for _, secret := range spec.Secrets { | |
| stringData[secret.Name] = secret.Data | |
| } | |
| return &v1.Secret{ | |
| ObjectMeta: metav1.ObjectMeta{ | |
| Name: spec.PodSpec.Name, | |
| }, | |
| Type: "Opaque", | |
| StringData: stringData, | |
| } | |
| } | |
| func toDockerConfigSecret(spec *Spec) *v1.Secret { | |
| return &v1.Secret{ | |
| ObjectMeta: metav1.ObjectMeta{ | |
| Name: spec.PullSecret.Name, | |
| }, | |
| Type: "kubernetes.io/dockerconfigjson", | |
| StringData: map[string]string{ | |
| ".dockerconfigjson": spec.PullSecret.Data, | |
| }, | |
| } | |
| } | |
| func toImagePullSecrets(spec *Spec) []v1.LocalObjectReference { | |
| var pullSecrets []v1.LocalObjectReference | |
| if spec.PullSecret != nil { | |
| pullSecrets = []v1.LocalObjectReference{{ | |
| Name: spec.PullSecret.Name, | |
| }} | |
| } | |
| return pullSecrets | |
| } | |
| func toVolumeMounts(spec *Spec, step *Step) []v1.VolumeMount { | |
| var volumeMounts []v1.VolumeMount | |
| for _, v := range step.Volumes { | |
| id, ok := lookupVolumeID(spec, v.Name) | |
| if !ok { | |
| continue | |
| } | |
| volumeMounts = append(volumeMounts, v1.VolumeMount{ | |
| Name: id, | |
| MountPath: v.Path, | |
| ReadOnly: v.ReadOnly, | |
| }) | |
| } | |
| return volumeMounts | |
| } | |
| func toResources(src Resources) v1.ResourceRequirements { | |
| var dst v1.ResourceRequirements | |
| if src.Limits.Memory > 0 || src.Limits.CPU > 0 { | |
| dst.Limits = v1.ResourceList{} | |
| if src.Limits.Memory > int64(0) { | |
| dst.Limits[v1.ResourceMemory] = *resource.NewQuantity( | |
| src.Limits.Memory, resource.BinarySI) | |
| } | |
| if src.Limits.CPU > int64(0) { | |
| dst.Limits[v1.ResourceCPU] = *resource.NewMilliQuantity( | |
| src.Limits.CPU, resource.DecimalSI) | |
| } | |
| } | |
| if src.Requests.Memory > 0 || src.Requests.CPU > 0 { | |
| dst.Requests = v1.ResourceList{} | |
| if src.Requests.Memory > int64(0) { | |
| dst.Requests[v1.ResourceMemory] = *resource.NewQuantity( | |
| src.Requests.Memory, resource.BinarySI) | |
| } | |
| if src.Requests.CPU > int64(0) { | |
| dst.Requests[v1.ResourceCPU] = *resource.NewMilliQuantity( | |
| src.Requests.CPU, resource.DecimalSI) | |
| } | |
| } | |
| return dst | |
| } | |
| // LookupVolume is a helper function that will lookup | |
| // the id for a volume. | |
| func lookupVolumeID(spec *Spec, name string) (string, bool) { | |
| for _, v := range spec.Volumes { | |
| if v.EmptyDir != nil && v.EmptyDir.Name == name { | |
| return v.EmptyDir.ID, true | |
| } | |
| if v.HostPath != nil && v.HostPath.Name == name { | |
| return v.HostPath.ID, true | |
| } | |
| if v.Claim != nil && v.Claim.Name == name { | |
| return v.Claim.ID, true | |
| } | |
| if v.DownwardAPI != nil && v.DownwardAPI.Name == name { | |
| return v.DownwardAPI.ID, true | |
| } | |
| } | |
| return "", false | |
| } | |
| func toPullPolicy(policy PullPolicy) v1.PullPolicy { | |
| switch policy { | |
| case PullAlways: | |
| return v1.PullAlways | |
| case PullNever: | |
| return v1.PullNever | |
| case PullIfNotExists: | |
| return v1.PullIfNotPresent | |
| default: | |
| return v1.PullIfNotPresent | |
| } | |
| } | |
| func int64ptr(v int64) *int64 { | |
| return &v | |
| } | |
| func boolptr(v bool) *bool { | |
| return &v | |
| } | |
| func stringptr(v string) *string { | |
| return &v | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment