Make child resource creation atomic when creating a k8s stack
Signed-off-by: Simon Ferquel <simon.ferquel@docker.com>
This commit is contained in:
@ -20,6 +20,26 @@ type Stack struct {
|
||||
Spec *v1beta2.StackSpec
|
||||
}
|
||||
|
||||
type childResource interface {
|
||||
setOwner(metav1.OwnerReference) error
|
||||
delete() // does not report error, as if a deletion failed, we want to continue deleting other child resources
|
||||
}
|
||||
|
||||
func deleteChildResources(childResources []childResource) {
|
||||
for _, cr := range childResources {
|
||||
cr.delete()
|
||||
}
|
||||
}
|
||||
|
||||
func setChildResourcesOwner(childResources []childResource, owner metav1.OwnerReference) error {
|
||||
for _, cr := range childResources {
|
||||
if err := cr.setOwner(owner); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getServices returns all the stack service names, sorted lexicographically
|
||||
func (s *Stack) getServices() []string {
|
||||
services := make([]string, len(s.Spec.Services))
|
||||
@ -31,7 +51,8 @@ func (s *Stack) getServices() []string {
|
||||
}
|
||||
|
||||
// createFileBasedConfigMaps creates a Kubernetes ConfigMap for each Compose global file-based config.
|
||||
func (s *Stack) createFileBasedConfigMaps(configMaps corev1.ConfigMapInterface) error {
|
||||
func (s *Stack) createFileBasedConfigMaps(configMaps corev1.ConfigMapInterface) ([]childResource, error) {
|
||||
var resources []childResource
|
||||
for name, config := range s.Spec.Configs {
|
||||
if config.File == "" {
|
||||
continue
|
||||
@ -40,15 +61,31 @@ func (s *Stack) createFileBasedConfigMaps(configMaps corev1.ConfigMapInterface)
|
||||
fileName := filepath.Base(config.File)
|
||||
content, err := ioutil.ReadFile(config.File)
|
||||
if err != nil {
|
||||
return err
|
||||
return resources, err
|
||||
}
|
||||
|
||||
if _, err := configMaps.Create(toConfigMap(s.Name, name, fileName, content)); err != nil {
|
||||
return err
|
||||
configMap, err := configMaps.Create(toConfigMap(s.Name, name, fileName, content))
|
||||
if err != nil {
|
||||
return resources, err
|
||||
}
|
||||
resources = append(resources, &configMapChildResource{client: configMaps, configMap: configMap})
|
||||
}
|
||||
return resources, nil
|
||||
}
|
||||
|
||||
return nil
|
||||
type configMapChildResource struct {
|
||||
client corev1.ConfigMapInterface
|
||||
configMap *apiv1.ConfigMap
|
||||
}
|
||||
|
||||
func (r *configMapChildResource) setOwner(ref metav1.OwnerReference) error {
|
||||
r.configMap.OwnerReferences = append(r.configMap.OwnerReferences, ref)
|
||||
_, err := r.client.Update(r.configMap)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *configMapChildResource) delete() {
|
||||
r.client.Delete(r.configMap.Name, nil)
|
||||
}
|
||||
|
||||
// toConfigMap converts a Compose Config to a Kube ConfigMap.
|
||||
@ -71,7 +108,8 @@ func toConfigMap(stackName, name, key string, content []byte) *apiv1.ConfigMap {
|
||||
}
|
||||
|
||||
// createFileBasedSecrets creates a Kubernetes Secret for each Compose global file-based secret.
|
||||
func (s *Stack) createFileBasedSecrets(secrets corev1.SecretInterface) error {
|
||||
func (s *Stack) createFileBasedSecrets(secrets corev1.SecretInterface) ([]childResource, error) {
|
||||
var resources []childResource
|
||||
for name, secret := range s.Spec.Secrets {
|
||||
if secret.File == "" {
|
||||
continue
|
||||
@ -80,15 +118,31 @@ func (s *Stack) createFileBasedSecrets(secrets corev1.SecretInterface) error {
|
||||
fileName := filepath.Base(secret.File)
|
||||
content, err := ioutil.ReadFile(secret.File)
|
||||
if err != nil {
|
||||
return err
|
||||
return resources, err
|
||||
}
|
||||
|
||||
if _, err := secrets.Create(toSecret(s.Name, name, fileName, content)); err != nil {
|
||||
return err
|
||||
secret, err := secrets.Create(toSecret(s.Name, name, fileName, content))
|
||||
if err != nil {
|
||||
return resources, err
|
||||
}
|
||||
resources = append(resources, &secretChildResource{client: secrets, secret: secret})
|
||||
}
|
||||
return resources, nil
|
||||
}
|
||||
|
||||
return nil
|
||||
type secretChildResource struct {
|
||||
client corev1.SecretInterface
|
||||
secret *apiv1.Secret
|
||||
}
|
||||
|
||||
func (r *secretChildResource) setOwner(ref metav1.OwnerReference) error {
|
||||
r.secret.OwnerReferences = append(r.secret.OwnerReferences, ref)
|
||||
_, err := r.client.Update(r.secret)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *secretChildResource) delete() {
|
||||
r.client.Delete(r.secret.Name, nil)
|
||||
}
|
||||
|
||||
// toSecret converts a Compose Secret to a Kube Secret.
|
||||
|
||||
Reference in New Issue
Block a user