github.com/ali-iotechsys/cli@v20.10.0+incompatible/cli/command/stack/kubernetes/stack.go (about) 1 package kubernetes 2 3 import ( 4 "io/ioutil" 5 "path/filepath" 6 "sort" 7 8 latest "github.com/docker/compose-on-kubernetes/api/compose/v1alpha3" 9 "github.com/docker/compose-on-kubernetes/api/labels" 10 apiv1 "k8s.io/api/core/v1" 11 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 12 corev1 "k8s.io/client-go/kubernetes/typed/core/v1" 13 ) 14 15 // Stack is the main type used by stack commands so they remain independent from kubernetes compose component version. 16 type Stack struct { 17 Name string 18 Namespace string 19 ComposeFile string 20 Spec *latest.StackSpec 21 } 22 23 type childResource interface { 24 setOwner(metav1.OwnerReference) error 25 delete() // does not report error, as if a deletion failed, we want to continue deleting other child resources 26 } 27 28 func deleteChildResources(childResources []childResource) { 29 for _, cr := range childResources { 30 cr.delete() 31 } 32 } 33 34 func setChildResourcesOwner(childResources []childResource, owner metav1.OwnerReference) error { 35 for _, cr := range childResources { 36 if err := cr.setOwner(owner); err != nil { 37 return err 38 } 39 } 40 return nil 41 } 42 43 // getServices returns all the stack service names, sorted lexicographically 44 func (s *Stack) getServices() []string { 45 services := make([]string, len(s.Spec.Services)) 46 for i, service := range s.Spec.Services { 47 services[i] = service.Name 48 } 49 sort.Strings(services) 50 return services 51 } 52 53 // createFileBasedConfigMaps creates a Kubernetes ConfigMap for each Compose global file-based config. 54 func (s *Stack) createFileBasedConfigMaps(configMaps corev1.ConfigMapInterface) ([]childResource, error) { 55 var resources []childResource 56 for name, config := range s.Spec.Configs { 57 if config.File == "" { 58 continue 59 } 60 61 fileName := filepath.Base(config.File) 62 content, err := ioutil.ReadFile(config.File) 63 if err != nil { 64 return resources, err 65 } 66 67 configMap, err := configMaps.Create(toConfigMap(s.Name, name, fileName, content)) 68 if err != nil { 69 return resources, err 70 } 71 resources = append(resources, &configMapChildResource{client: configMaps, configMap: configMap}) 72 } 73 return resources, nil 74 } 75 76 type configMapChildResource struct { 77 client corev1.ConfigMapInterface 78 configMap *apiv1.ConfigMap 79 } 80 81 func (r *configMapChildResource) setOwner(ref metav1.OwnerReference) error { 82 r.configMap.OwnerReferences = append(r.configMap.OwnerReferences, ref) 83 _, err := r.client.Update(r.configMap) 84 return err 85 } 86 87 func (r *configMapChildResource) delete() { 88 r.client.Delete(r.configMap.Name, nil) 89 } 90 91 // toConfigMap converts a Compose Config to a Kube ConfigMap. 92 func toConfigMap(stackName, name, key string, content []byte) *apiv1.ConfigMap { 93 return &apiv1.ConfigMap{ 94 TypeMeta: metav1.TypeMeta{ 95 Kind: "ConfigMap", 96 APIVersion: "v1", 97 }, 98 ObjectMeta: metav1.ObjectMeta{ 99 Name: name, 100 Labels: map[string]string{ 101 labels.ForStackName: stackName, 102 }, 103 }, 104 Data: map[string]string{ 105 key: string(content), 106 }, 107 } 108 } 109 110 // createFileBasedSecrets creates a Kubernetes Secret for each Compose global file-based secret. 111 func (s *Stack) createFileBasedSecrets(secrets corev1.SecretInterface) ([]childResource, error) { 112 var resources []childResource 113 for name, secret := range s.Spec.Secrets { 114 if secret.File == "" { 115 continue 116 } 117 118 fileName := filepath.Base(secret.File) 119 content, err := ioutil.ReadFile(secret.File) 120 if err != nil { 121 return resources, err 122 } 123 124 secret, err := secrets.Create(toSecret(s.Name, name, fileName, content)) 125 if err != nil { 126 return resources, err 127 } 128 resources = append(resources, &secretChildResource{client: secrets, secret: secret}) 129 } 130 return resources, nil 131 } 132 133 type secretChildResource struct { 134 client corev1.SecretInterface 135 secret *apiv1.Secret 136 } 137 138 func (r *secretChildResource) setOwner(ref metav1.OwnerReference) error { 139 r.secret.OwnerReferences = append(r.secret.OwnerReferences, ref) 140 _, err := r.client.Update(r.secret) 141 return err 142 } 143 144 func (r *secretChildResource) delete() { 145 r.client.Delete(r.secret.Name, nil) 146 } 147 148 // toSecret converts a Compose Secret to a Kube Secret. 149 func toSecret(stackName, name, key string, content []byte) *apiv1.Secret { 150 return &apiv1.Secret{ 151 ObjectMeta: metav1.ObjectMeta{ 152 Name: name, 153 Labels: map[string]string{ 154 labels.ForStackName: stackName, 155 }, 156 }, 157 Data: map[string][]byte{ 158 key: content, 159 }, 160 } 161 }