Skip to content

Commit

Permalink
Warning if a service/volume in a stack already belongs to a different…
Browse files Browse the repository at this point in the history
… stack

Signed-off-by: Pablo Chico de Guzman <pchico83@gmail.com>
  • Loading branch information
pchico83 committed Mar 12, 2022
1 parent 1904549 commit 40da75c
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 70 deletions.
156 changes: 95 additions & 61 deletions pkg/cmd/stack/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,10 @@ func deploy(ctx context.Context, s *model.Stack, c *kubernetes.Clientset, config
}

for name := range s.Volumes {
if err := deployVolume(ctx, name, s, c); err != nil {
if err := deployVolume(ctx, name, s, c, spinner); err != nil {
exit <- err
return
}
spinner.Stop()
oktetoLog.Success("Created volume '%s'", name)
spinner.Start()
}

if err := deployServices(ctx, s, c, config, spinner, options); err != nil {
Expand All @@ -142,13 +139,10 @@ func deploy(ctx context.Context, s *model.Stack, c *kubernetes.Clientset, config
return
}
for name := range s.Endpoints {
if err := deployIngress(ctx, name, s, iClient); err != nil {
if err := deployIngress(ctx, name, s, iClient, spinner); err != nil {
exit <- err
return
}
spinner.Stop()
oktetoLog.Success("Created endpoint '%s'", name)
spinner.Start()
}

if err := destroyServicesNotInStack(ctx, spinner, s, c); err != nil {
Expand Down Expand Up @@ -224,21 +218,30 @@ func deployServices(ctx context.Context, stack *model.Stack, k8sClient *kubernet
}

func deploySvc(ctx context.Context, stack *model.Stack, svcName string, client kubernetes.Interface, spinner *utils.Spinner) error {
isNew := false
var err error
if stack.Services[svcName].IsJob() {
if err := deployJob(ctx, svcName, stack, client); err != nil {
return err
}
isNew, err = deployJob(ctx, svcName, stack, client, spinner)
} else if len(stack.Services[svcName].Volumes) == 0 {
if err := deployDeployment(ctx, svcName, stack, client); err != nil {
return err
}
isNew, err = deployDeployment(ctx, svcName, stack, client, spinner)
} else {
if err := deployStatefulSet(ctx, svcName, stack, client); err != nil {
return err
}
isNew, err = deployStatefulSet(ctx, svcName, stack, client, spinner)
}
spinner.Stop()
oktetoLog.Success("Deployed service '%s'", svcName)
if err != nil {
if strings.Contains(err.Error(), "skipping ") {
oktetoLog.Warning(err.Error())
spinner.Start()
return nil
}
spinner.Start()
return err
}
if isNew {
oktetoLog.Success("Service '%s' created", svcName)
} else {
oktetoLog.Success("Service '%s' updated", svcName)
}
spinner.Start()
return nil
}
Expand Down Expand Up @@ -374,19 +377,19 @@ func isAnyPortAvailable(ctx context.Context, svc *model.Service, stack *model.St
return false
}

func deployDeployment(ctx context.Context, svcName string, s *model.Stack, c kubernetes.Interface) error {
func deployDeployment(ctx context.Context, svcName string, s *model.Stack, c kubernetes.Interface, spinner *utils.Spinner) (bool, error) {
d := translateDeployment(svcName, s)
old, err := c.AppsV1().Deployments(s.Namespace).Get(ctx, svcName, metav1.GetOptions{})
if err != nil && !oktetoErrors.IsNotFound(err) {
return fmt.Errorf("error getting deployment of service '%s': %s", svcName, err.Error())
return false, fmt.Errorf("error getting deployment of service '%s': %s", svcName, err.Error())
}
isNewDeployment := old == nil || old.Name == ""
if !isNewDeployment {
if old.Labels[model.StackNameLabel] == "" {
return fmt.Errorf("name collision: the deployment '%s' was running before deploying your stack", svcName)
return false, fmt.Errorf("skipping deploy of deployment '%s' due to name collision with pre-existing deployment", svcName)
}
if old.Labels[model.StackNameLabel] != s.Name {
return fmt.Errorf("name collision: the deployment '%s' belongs to the stack '%s'", svcName, old.Labels[model.StackNameLabel])
return false, fmt.Errorf("skipping deploy of deployment '%s' due to name collision with deployment in stack '%s'", svcName, old.Labels[model.StackNameLabel])
}
if v, ok := old.Labels[model.DeployedByLabel]; ok {
d.Labels[model.DeployedByLabel] = v
Expand All @@ -395,78 +398,80 @@ func deployDeployment(ctx context.Context, svcName string, s *model.Stack, c kub

if _, err := deployments.Deploy(ctx, d, c); err != nil {
if isNewDeployment {
return fmt.Errorf("error creating deployment of service '%s': %s", svcName, err.Error())
return false, fmt.Errorf("error creating deployment of service '%s': %s", svcName, err.Error())
}
return fmt.Errorf("error updating deployment of service '%s': %s", svcName, err.Error())
return false, fmt.Errorf("error updating deployment of service '%s': %s", svcName, err.Error())
}

return nil
return isNewDeployment, nil
}

func deployStatefulSet(ctx context.Context, svcName string, s *model.Stack, c kubernetes.Interface) error {
func deployStatefulSet(ctx context.Context, svcName string, s *model.Stack, c kubernetes.Interface, spinner *utils.Spinner) (bool, error) {
sfs := translateStatefulSet(svcName, s)
old, err := c.AppsV1().StatefulSets(s.Namespace).Get(ctx, svcName, metav1.GetOptions{})
if err != nil && !oktetoErrors.IsNotFound(err) {
return fmt.Errorf("error getting statefulset of service '%s': %s", svcName, err.Error())
return false, fmt.Errorf("error getting statefulset of service '%s': %s", svcName, err.Error())
}
if old == nil || old.Name == "" {
if _, err := statefulsets.Deploy(ctx, sfs, c); err != nil {
return fmt.Errorf("error creating statefulset of service '%s': %s", svcName, err.Error())
return false, fmt.Errorf("error creating statefulset of service '%s': %s", svcName, err.Error())
}
} else {
if old.Labels[model.StackNameLabel] == "" {
return fmt.Errorf("name collision: the statefulset '%s' was running before deploying your stack", svcName)
}
if old.Labels[model.StackNameLabel] != s.Name {
return fmt.Errorf("name collision: the statefulset '%s' belongs to the stack '%s'", svcName, old.Labels[model.StackNameLabel])
return true, nil
}

if old.Labels[model.StackNameLabel] == "" {
return false, fmt.Errorf("skipping deploy of statefulset '%s' due to name collision with pre-existing statefulset", svcName)
}
if old.Labels[model.StackNameLabel] != s.Name {
return false, fmt.Errorf("skipping deploy of statefulset '%s' due to name collision with statefulset in stack '%s'", svcName, old.Labels[model.StackNameLabel])
}
if v, ok := old.Labels[model.DeployedByLabel]; ok {
sfs.Labels[model.DeployedByLabel] = v
}
if _, err := statefulsets.Deploy(ctx, sfs, c); err != nil {
if !strings.Contains(err.Error(), "Forbidden: updates to statefulset spec") {
return false, fmt.Errorf("error updating statefulset of service '%s': %s", svcName, err.Error())
}
if v, ok := old.Labels[model.DeployedByLabel]; ok {
sfs.Labels[model.DeployedByLabel] = v
if err := statefulsets.Destroy(ctx, sfs.Name, sfs.Namespace, c); err != nil {
return false, fmt.Errorf("error updating statefulset of service '%s': %s", svcName, err.Error())
}
if _, err := statefulsets.Deploy(ctx, sfs, c); err != nil {
if !strings.Contains(err.Error(), "Forbidden: updates to statefulset spec") {
return fmt.Errorf("error updating statefulset of service '%s': %s", svcName, err.Error())
}
if err := statefulsets.Destroy(ctx, sfs.Name, sfs.Namespace, c); err != nil {
return fmt.Errorf("error updating statefulset of service '%s': %s", svcName, err.Error())
}
if _, err := statefulsets.Deploy(ctx, sfs, c); err != nil {
return fmt.Errorf("error updating statefulset of service '%s': %s", svcName, err.Error())
}
return false, fmt.Errorf("error updating statefulset of service '%s': %s", svcName, err.Error())
}
}
return nil

return false, nil
}

func deployJob(ctx context.Context, svcName string, s *model.Stack, c kubernetes.Interface) error {
func deployJob(ctx context.Context, svcName string, s *model.Stack, c kubernetes.Interface, spinner *utils.Spinner) (bool, error) {
job := translateJob(svcName, s)
old, err := c.BatchV1().Jobs(s.Namespace).Get(ctx, svcName, metav1.GetOptions{})
if err != nil && !oktetoErrors.IsNotFound(err) {
return fmt.Errorf("error getting job of service '%s': %s", svcName, err.Error())
return false, fmt.Errorf("error getting job of service '%s': %s", svcName, err.Error())
}
isNewJob := old == nil || old.Name == ""
if !isNewJob {
if old.Labels[model.StackNameLabel] == "" {
return fmt.Errorf("name collision: the job '%s' was running before deploying your stack", svcName)
return false, fmt.Errorf("skipping deploy of job '%s' due to name collision with pre-existing job", svcName)
}
if old.Labels[model.StackNameLabel] != s.Name {
return fmt.Errorf("name collision: the job '%s' belongs to the stack '%s'", svcName, old.Labels[model.StackNameLabel])
return false, fmt.Errorf("skipping deploy of job '%s' due to name collision with job in stack '%s'", svcName, old.Labels[model.StackNameLabel])
}
}

if isNewJob {
if err := jobs.Create(ctx, job, c); err != nil {
return fmt.Errorf("error creating job of service '%s': %s", svcName, err.Error())
return false, fmt.Errorf("error creating job of service '%s': %s", svcName, err.Error())
}
} else {
if err := jobs.Update(ctx, job, c); err != nil {
return fmt.Errorf("error updating job of service '%s': %s", svcName, err.Error())
return false, fmt.Errorf("error updating job of service '%s': %s", svcName, err.Error())
}
}
return nil
return isNewJob, nil
}

func deployVolume(ctx context.Context, volumeName string, s *model.Stack, c kubernetes.Interface) error {
func deployVolume(ctx context.Context, volumeName string, s *model.Stack, c kubernetes.Interface, spinner *utils.Spinner) error {
pvc := translatePersistentVolumeClaim(volumeName, s)

old, err := c.CoreV1().PersistentVolumeClaims(s.Namespace).Get(ctx, pvc.Name, metav1.GetOptions{})
Expand All @@ -477,12 +482,21 @@ func deployVolume(ctx context.Context, volumeName string, s *model.Stack, c kube
if err := volumes.Create(ctx, &pvc, c); err != nil {
return fmt.Errorf("error creating volume '%s': %s", pvc.Name, err.Error())
}
spinner.Stop()
oktetoLog.Success("Volume '%s' created", volumeName)
spinner.Start()
} else {
if old.Labels[model.StackNameLabel] == "" {
return fmt.Errorf("name collision: the volume '%s' was running before deploying your stack", pvc.Name)
spinner.Stop()
oktetoLog.Warning("skipping creation of volume '%s' due to name collision with pre-existing volume", pvc.Name)
spinner.Start()
return nil
}
if old.Labels[model.StackNameLabel] != s.Name {
return fmt.Errorf("name collision: the volume '%s' belongs to the stack '%s'", pvc.Name, old.Labels[model.StackNameLabel])
spinner.Stop()
oktetoLog.Warning("skipping creation of volume '%s' due to name collision with volume in stack '%s'", pvc.Name, old.Labels[model.StackNameLabel])
spinner.Start()
return nil
}

old.Spec.Resources.Requests["storage"] = pvc.Spec.Resources.Requests["storage"]
Expand All @@ -502,11 +516,14 @@ func deployVolume(ctx context.Context, volumeName string, s *model.Stack, c kube
}
return fmt.Errorf("error updating volume '%s': %s", old.Name, err.Error())
}
spinner.Stop()
oktetoLog.Success("Volume '%s' updated", volumeName)
spinner.Start()
}
return nil
}

func deployIngress(ctx context.Context, ingressName string, s *model.Stack, c *ingresses.Client) error {
func deployIngress(ctx context.Context, ingressName string, s *model.Stack, c *ingresses.Client, spinner *utils.Spinner) error {
iModel := &ingresses.Ingress{
V1: translateIngressV1(ingressName, s),
V1Beta1: translateIngressV1Beta1(ingressName, s),
Expand All @@ -516,18 +533,35 @@ func deployIngress(ctx context.Context, ingressName string, s *model.Stack, c *i
if !oktetoErrors.IsNotFound(err) {
return fmt.Errorf("error getting ingress '%s': %s", ingressName, err.Error())
}
return c.Create(ctx, iModel)
if err := c.Create(ctx, iModel); err != nil {
return err
}
spinner.Stop()
oktetoLog.Success("Endpoint '%s' created", ingressName)
spinner.Start()
}

if old.GetLabels()[model.StackNameLabel] == "" {
return fmt.Errorf("name collision: the ingress '%s' was running before deploying your stack", ingressName)
spinner.Stop()
oktetoLog.Warning("skipping deploy of endpoint '%s' due to name collision with pre-existing endpoint", ingressName)
spinner.Start()
return nil
}

if old.GetLabels()[model.StackNameLabel] != s.Name {
return fmt.Errorf("name collision: the endpoint '%s' belongs to the stack '%s'", ingressName, old.GetLabels()[model.StackNameLabel])
spinner.Stop()
oktetoLog.Warning("skipping creation of endpoint '%s' due to name collision with endpoint in stack '%s'", ingressName, old.GetLabels()[model.StackNameLabel])
spinner.Start()
return nil
}

return c.Update(ctx, iModel)
if err := c.Update(ctx, iModel); err != nil {
return err
}
spinner.Stop()
oktetoLog.Success("Endpoint '%s' updated", ingressName)
spinner.Start()
return nil
}

func waitForPodsToBeRunning(ctx context.Context, s *model.Stack, c *kubernetes.Clientset) error {
Expand Down
16 changes: 12 additions & 4 deletions pkg/cmd/stack/deploy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,9 @@ func Test_deployDeployment(t *testing.T) {
}
client := fake.NewSimpleClientset()

err := deployDeployment(ctx, "test", stack, client)
spinner := utils.NewSpinner("Starting...")
spinner.Start()
_, err := deployDeployment(ctx, "test", stack, client, spinner)
if err != nil {
t.Fatal("Not deployed correctly")
}
Expand Down Expand Up @@ -163,7 +165,9 @@ func Test_deployVolumes(t *testing.T) {
}
client := fake.NewSimpleClientset()

err := deployVolume(ctx, "a", stack, client)
spinner := utils.NewSpinner("Starting...")
spinner.Start()
err := deployVolume(ctx, "a", stack, client, spinner)
if err != nil {
t.Fatal("Not deployed correctly")
}
Expand Down Expand Up @@ -197,7 +201,9 @@ func Test_deploySfs(t *testing.T) {
}
client := fake.NewSimpleClientset()

err := deployStatefulSet(ctx, "test", stack, client)
spinner := utils.NewSpinner("Starting...")
spinner.Start()
_, err := deployStatefulSet(ctx, "test", stack, client, spinner)
if err != nil {
t.Fatal("Not deployed correctly")
}
Expand All @@ -222,7 +228,9 @@ func Test_deployJob(t *testing.T) {
}
client := fake.NewSimpleClientset()

err := deployJob(ctx, "test", stack, client)
spinner := utils.NewSpinner("Starting...")
spinner.Start()
_, err := deployJob(ctx, "test", stack, client, spinner)
if err != nil {
t.Fatal("Not deployed correctly")
}
Expand Down
10 changes: 5 additions & 5 deletions pkg/cmd/stack/destroy.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ func destroyDeployments(ctx context.Context, spinner *utils.Spinner, s *model.St
if _, ok := s.Services[dList[i].Name]; ok {
oktetoLog.Success("Destroyed previous service '%s'", dList[i].Name)
} else {
oktetoLog.Success("Destroyed service '%s'", dList[i].Name)
oktetoLog.Success("Service '%s' destroyed", dList[i].Name)
}
spinner.Start()
}
Expand All @@ -178,7 +178,7 @@ func destroyStatefulsets(ctx context.Context, spinner *utils.Spinner, s *model.S
if _, ok := s.Services[sfsList[i].Name]; ok {
oktetoLog.Success("Destroyed previous service '%s'", sfsList[i].Name)
} else {
oktetoLog.Success("Destroyed service '%s'", sfsList[i].Name)
oktetoLog.Success("Service '%s' destroyed", sfsList[i].Name)
}
spinner.Start()
}
Expand All @@ -203,7 +203,7 @@ func destroyJobs(ctx context.Context, spinner *utils.Spinner, s *model.Stack, c
if _, ok := s.Services[jobsList[i].Name]; ok {
oktetoLog.Success("Destroyed previous service '%s'", jobsList[i].Name)
} else {
oktetoLog.Success("Destroyed service '%s'", jobsList[i].Name)
oktetoLog.Success("Service '%s' destroyed", jobsList[i].Name)
}
spinner.Start()
}
Expand Down Expand Up @@ -232,7 +232,7 @@ func destroyIngresses(ctx context.Context, spinner *utils.Spinner, s *model.Stac
return fmt.Errorf("error destroying ingress '%s': %s", iList[i].GetName(), err)
}
spinner.Stop()
oktetoLog.Success("Destroyed endpoint '%s'", iList[i].GetName())
oktetoLog.Success("Endpoint '%s' destroyed", iList[i].GetName())
spinner.Start()
}
return nil
Expand Down Expand Up @@ -267,7 +267,7 @@ func destroyStackVolumes(ctx context.Context, spinner *utils.Spinner, s *model.S
return fmt.Errorf("error destroying volume '%s': %s", v.Name, err)
}
spinner.Stop()
oktetoLog.Success("Destroyed volume '%s'", v.Name)
oktetoLog.Success("Volume '%s' destroyed", v.Name)
spinner.Start()
}
}
Expand Down

0 comments on commit 40da75c

Please sign in to comment.