github.com/docker/compose-on-kubernetes@v0.5.0/internal/controller/resourceupdater.go (about) 1 package controller 2 3 import ( 4 "github.com/docker/compose-on-kubernetes/api/client/clientset" 5 "github.com/docker/compose-on-kubernetes/api/compose/latest" 6 "github.com/docker/compose-on-kubernetes/api/labels" 7 "github.com/docker/compose-on-kubernetes/internal/stackresources" 8 "github.com/docker/compose-on-kubernetes/internal/stackresources/diff" 9 "github.com/pkg/errors" 10 appstypes "k8s.io/api/apps/v1" 11 coretypes "k8s.io/api/core/v1" 12 kerrors "k8s.io/apimachinery/pkg/api/errors" 13 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 14 k8sclientset "k8s.io/client-go/kubernetes" 15 "k8s.io/client-go/rest" 16 ) 17 18 type impersonatingResourceUpdaterProvider struct { 19 config rest.Config 20 ownerCache StackOwnerCacher 21 } 22 23 func (p *impersonatingResourceUpdaterProvider) getUpdater(stack *latest.Stack, isDirty bool) (resourceUpdater, error) { 24 ic, err := p.ownerCache.getWithRetries(stack, !isDirty) 25 if err != nil { 26 return nil, err 27 } 28 localConfig := p.config 29 localConfig.Impersonate = ic 30 result := &k8sResourceUpdater{ 31 originalStack: stack, 32 } 33 if result.stackClient, err = clientset.NewForConfig(&localConfig); err != nil { 34 return nil, err 35 } 36 if result.k8sclient, err = k8sclientset.NewForConfig(&localConfig); err != nil { 37 return nil, err 38 } 39 return result, nil 40 } 41 42 // NewImpersonatingResourceUpdaterProvider creates a ResourceUpdaterProvider that impersonate api calls 43 func NewImpersonatingResourceUpdaterProvider(config rest.Config, ownerCache StackOwnerCacher) ResourceUpdaterProvider { 44 return &impersonatingResourceUpdaterProvider{config: config, ownerCache: ownerCache} 45 } 46 47 var deletePolicy = metav1.DeletePropagationForeground 48 var deleteOptions = metav1.DeleteOptions{ 49 PropagationPolicy: &deletePolicy, 50 } 51 52 type k8sResourceUpdater struct { 53 stackClient clientset.Interface 54 k8sclient k8sclientset.Interface 55 originalStack *latest.Stack 56 } 57 58 func (u *k8sResourceUpdater) applyDaemonsets(toAdd, toUpdate, toDelete []appstypes.DaemonSet) error { 59 for _, r := range toDelete { 60 if err := u.k8sclient.AppsV1().DaemonSets(u.originalStack.Namespace).Delete(r.Name, &deleteOptions); err != nil && !kerrors.IsNotFound(err) { 61 return errors.Wrapf(err, "k8sResourceUpdater: error while deleting daemonset %s in stack %s", r.Name, stackresources.ObjKey(u.originalStack.Namespace, u.originalStack.Name)) 62 } 63 } 64 for _, r := range toAdd { 65 if _, err := u.k8sclient.AppsV1().DaemonSets(u.originalStack.Namespace).Create(&r); err != nil { 66 return errors.Wrapf(err, "k8sResourceUpdater: error while creating daemonset %s in stack %s", r.Name, stackresources.ObjKey(u.originalStack.Namespace, u.originalStack.Name)) 67 } 68 } 69 for _, r := range toUpdate { 70 if _, err := u.k8sclient.AppsV1().DaemonSets(u.originalStack.Namespace).Update(&r); err != nil { 71 return errors.Wrapf(err, "k8sResourceUpdater: error while patching daemonset %s in stack %s", r.Name, stackresources.ObjKey(u.originalStack.Namespace, u.originalStack.Name)) 72 } 73 } 74 return nil 75 } 76 77 func (u *k8sResourceUpdater) applyDeployments(toAdd, toUpdate, toDelete []appstypes.Deployment) error { 78 for _, r := range toDelete { 79 if err := u.k8sclient.AppsV1().Deployments(u.originalStack.Namespace).Delete(r.Name, &deleteOptions); err != nil && !kerrors.IsNotFound(err) { 80 return errors.Wrapf(err, "k8sResourceUpdater: error while deleting deployment %s in stack %s", r.Name, stackresources.ObjKey(u.originalStack.Namespace, u.originalStack.Name)) 81 } 82 } 83 for _, r := range toAdd { 84 if _, err := u.k8sclient.AppsV1().Deployments(u.originalStack.Namespace).Create(&r); err != nil { 85 return errors.Wrapf(err, "k8sResourceUpdater: error while creating deployment %s in stack %s", r.Name, stackresources.ObjKey(u.originalStack.Namespace, u.originalStack.Name)) 86 } 87 } 88 for _, r := range toUpdate { 89 if _, err := u.k8sclient.AppsV1().Deployments(u.originalStack.Namespace).Update(&r); err != nil { 90 return errors.Wrapf(err, "k8sResourceUpdater: error while patching deployment %s in stack %s", r.Name, stackresources.ObjKey(u.originalStack.Namespace, u.originalStack.Name)) 91 } 92 } 93 return nil 94 } 95 96 func (u *k8sResourceUpdater) applyStatefulsets(toAdd, toUpdate, toDelete []appstypes.StatefulSet) error { 97 for _, r := range toDelete { 98 if err := u.k8sclient.AppsV1().StatefulSets(u.originalStack.Namespace).Delete(r.Name, &deleteOptions); err != nil && !kerrors.IsNotFound(err) { 99 return errors.Wrapf(err, "k8sResourceUpdater: error while deleting statefulset %s in stack %s", r.Name, stackresources.ObjKey(u.originalStack.Namespace, u.originalStack.Name)) 100 } 101 } 102 for _, r := range toAdd { 103 if _, err := u.k8sclient.AppsV1().StatefulSets(u.originalStack.Namespace).Create(&r); err != nil { 104 return errors.Wrapf(err, "k8sResourceUpdater: error while creating statefulset %s in stack %s", r.Name, stackresources.ObjKey(u.originalStack.Namespace, u.originalStack.Name)) 105 } 106 } 107 for _, r := range toUpdate { 108 if _, err := u.k8sclient.AppsV1().StatefulSets(u.originalStack.Namespace).Update(&r); err != nil { 109 return errors.Wrapf(err, "k8sResourceUpdater: error while patching statefulset %s in stack %s", r.Name, stackresources.ObjKey(u.originalStack.Namespace, u.originalStack.Name)) 110 } 111 } 112 return nil 113 } 114 115 func (u *k8sResourceUpdater) applyServices(toAdd, toUpdate, toDelete []coretypes.Service) error { 116 for _, r := range toDelete { 117 if err := u.k8sclient.CoreV1().Services(u.originalStack.Namespace).Delete(r.Name, &deleteOptions); err != nil && !kerrors.IsNotFound(err) { 118 return errors.Wrapf(err, "k8sResourceUpdater: error while deleting service %s in stack %s", r.Name, stackresources.ObjKey(u.originalStack.Namespace, u.originalStack.Name)) 119 } 120 } 121 for _, r := range toAdd { 122 if _, err := u.k8sclient.CoreV1().Services(u.originalStack.Namespace).Create(&r); err != nil { 123 return errors.Wrapf(err, "k8sResourceUpdater: error while creating service %s in stack %s", r.Name, stackresources.ObjKey(u.originalStack.Namespace, u.originalStack.Name)) 124 } 125 } 126 for _, r := range toUpdate { 127 if _, err := u.k8sclient.CoreV1().Services(u.originalStack.Namespace).Update(&r); err != nil { 128 return errors.Wrapf(err, "k8sResourceUpdater: error while patching service %s in stack %s", r.Name, stackresources.ObjKey(u.originalStack.Namespace, u.originalStack.Name)) 129 } 130 } 131 return nil 132 } 133 134 func (u *k8sResourceUpdater) applyStackDiff(d *diff.StackStateDiff) error { 135 if err := u.applyDaemonsets(d.DaemonsetsToAdd, d.DaemonsetsToUpdate, d.DaemonsetsToDelete); err != nil { 136 return err 137 } 138 if err := u.applyDeployments(d.DeploymentsToAdd, d.DeploymentsToUpdate, d.DeploymentsToDelete); err != nil { 139 return err 140 } 141 if err := u.applyStatefulsets(d.StatefulsetsToAdd, d.StatefulsetsToUpdate, d.StatefulsetsToDelete); err != nil { 142 return err 143 } 144 if err := u.applyServices(d.ServicesToAdd, d.ServicesToUpdate, d.ServicesToDelete); err != nil { 145 return err 146 } 147 return nil 148 } 149 150 func (u *k8sResourceUpdater) updateStackStatus(status latest.StackStatus) (*latest.Stack, error) { 151 if u.originalStack.Status != nil && *u.originalStack.Status == status { 152 return u.originalStack, nil 153 } 154 newStack := u.originalStack.Clone() 155 newStack.Status = &status 156 updated, err := u.stackClient.ComposeLatest().Stacks(u.originalStack.Namespace).WithSkipValidation().Update(newStack) 157 if err != nil { 158 return nil, errors.Wrapf(err, "k8sResourceUpdater: error while patching stack %s", stackresources.ObjKey(u.originalStack.Namespace, u.originalStack.Name)) 159 } 160 return updated, nil 161 } 162 163 func (u *k8sResourceUpdater) deleteSecretsNoCollection() error { 164 if u.originalStack.Spec == nil { 165 return nil 166 } 167 for name, s := range u.originalStack.Spec.Secrets { 168 if s.External.External { 169 continue 170 } 171 if err := u.k8sclient.CoreV1().Secrets(u.originalStack.Namespace).Delete(name, nil); err != nil && !kerrors.IsNotFound(err) { 172 return err 173 } 174 } 175 return nil 176 } 177 178 func (u *k8sResourceUpdater) deleteConfigMapsNoCollection() error { 179 if u.originalStack.Spec == nil { 180 return nil 181 } 182 for name, s := range u.originalStack.Spec.Configs { 183 if s.External.External { 184 continue 185 } 186 if err := u.k8sclient.CoreV1().ConfigMaps(u.originalStack.Namespace).Delete(name, nil); err != nil && !kerrors.IsNotFound(err) { 187 return err 188 } 189 } 190 return nil 191 } 192 func (u *k8sResourceUpdater) deleteSecretsAndConfigMaps() error { 193 listOptions := metav1.ListOptions{ 194 LabelSelector: labels.SelectorForStack(u.originalStack.Name), 195 } 196 if err := u.k8sclient.CoreV1().Secrets(u.originalStack.Namespace).DeleteCollection(nil, listOptions); err != nil { 197 if kerrors.IsForbidden(err) { 198 if err := u.deleteSecretsNoCollection(); err != nil { 199 return err 200 } 201 } 202 } 203 if err := u.k8sclient.CoreV1().ConfigMaps(u.originalStack.Namespace).DeleteCollection(nil, listOptions); err != nil { 204 if kerrors.IsForbidden(err) { 205 if err := u.deleteConfigMapsNoCollection(); err != nil { 206 return err 207 } 208 } 209 } 210 return nil 211 }