Example #1
0
// Deploy allows the creation of deploy.Deployments remotely
func (s *SpreadCli) Deploy() *cli.Command {
	return &cli.Command{
		Name:        "deploy",
		Usage:       "spread deploy [-s] PATH | COMMIT [kubectl context]",
		Description: "Deploys objects to a remote Kubernetes cluster.",
		ArgsUsage:   "-s will deploy only if no other deployment found (otherwise fails)",
		Action: func(c *cli.Context) {
			ref := c.Args().First()
			var dep *deploy.Deployment

			proj, err := s.project()
			if err == nil {
				var docs map[string]*pb.Document
				if len(ref) == 0 {
					s.printf("Deploying from index...")
					docs, err = proj.Index()
					if err != nil {
						s.fatalf("Error getting index: %v", err)
					}

					if err = s.promptForArgs(docs, false); err == nil {
						dep, err = deploy.DeploymentFromDocMap(docs)
					}

				} else {
					if docs, err = proj.ResolveCommit(ref); err == nil {
						if err = s.promptForArgs(docs, false); err == nil {
							dep, err = deploy.DeploymentFromDocMap(docs)
						}
					} else {
						dep, err = s.globalDeploy(ref)
					}
				}
			} else {
				dep, err = s.globalDeploy(ref)
			}

			if err != nil {
				s.fatalf("Failed to assemble deployment: %v", err)
			}

			context := c.Args().Get(1)
			cluster, err := deploy.NewKubeClusterFromContext(context)
			if err != nil {
				s.fatalf("Failed to deploy: %v", err)
			}

			s.printf("Deploying %d objects using the %s.", dep.Len(), displayContext(context))

			update := !c.Bool("s")
			err = cluster.Deploy(dep, update, false)
			if err != nil {
				//TODO: make better error messages (one to indicate a deployment already existed; another one if a deployment did not exist but some other error was thrown
				s.fatalf("Did not deploy.: %v", err)
			}

			s.printf("Deployment successful!")
		},
	}
}
Example #2
0
// Status returns information about the current state of the project.
func (s SpreadCli) Status() *cli.Command {
	return &cli.Command{
		Name:        "status",
		Usage:       "spread status",
		Description: "Information about what's commited, changed, and staged.",
		Action: func(c *cli.Context) {
			proj := s.projectOrDie()
			indexDocs, err := proj.Index()
			if err != nil {
				s.fatalf("Could not load Index: %v", err)
			}

			index, err := deploy.DeploymentFromDocMap(indexDocs)
			if err != nil {
				s.fatalf("Failed to create KubeObject from index doc: %v", err)
			}

			var head *deploy.Deployment
			headDocs, err := proj.Head()
			if err == nil {
				head, err = deploy.DeploymentFromDocMap(headDocs)
				if err != nil {
					s.fatalf("Failed to create KubeObject from HEAD doc: %v", err)
				}
			} else {
				head = new(deploy.Deployment)
			}

			client, err := deploy.NewKubeClusterFromContext("")
			if err != nil {
				s.fatalf("Failed to connect to Kubernetes cluster: %v", err)
			}

			cluster, err := client.Deployment()
			if err != nil {
				s.fatalf("Could not load deployment from cluster: %v", err)
			}

			stat := deploy.Stat(index, head, cluster)
			s.printStatus(stat)
		},
	}
}
Example #3
0
// Diff shows the difference bettwen the cluster and the index.
func (s SpreadCli) Diff() *cli.Command {
	return &cli.Command{
		Name:        "diff",
		Usage:       "spread diff",
		Description: "Diffs index against state of cluster",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "context",
				Value: "",
				Usage: "kubectl context to use for requests",
			},
		},
		Action: func(c *cli.Context) {
			proj := s.projectOrDie()
			docs, err := proj.Index()
			if err != nil {
				s.fatalf("Could not load Index: %v", err)
			}

			index, err := deploy.DeploymentFromDocMap(docs)
			if err != nil {
				s.fatalf("Failed to create Deployment from Documents: %v", err)
			}

			context := c.String("context")
			client, err := deploy.NewKubeClusterFromContext(context)
			if err != nil {
				s.fatalf("Failed to connect to Kubernetes cluster: %v", err)
			}

			cluster, err := client.Deployment()
			if err != nil {
				s.fatalf("Could not load deployment from cluster: %v", err)
			}

			s.printf(index.Diff(cluster))
		},
	}
}
Example #4
0
// Add sets up a Spread repository for versioning.
func (s SpreadCli) Add() *cli.Command {
	return &cli.Command{
		Name:        "add",
		Usage:       "spread add <path>",
		Description: "Stage objects to the index",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "namespace",
				Value: "default",
				Usage: "namespace to look for objects",
			},
			cli.StringFlag{
				Name:  "context",
				Value: "",
				Usage: "kubectl context to use for requests",
			},
			cli.BoolFlag{
				Name:  "no-export",
				Usage: "don't request Kube API server to export objects",
			},
			cli.BoolFlag{
				Name:  "clean",
				Usage: "Removes fields that are known to cause issues with reproducibility",
			},
		},
		Action: func(c *cli.Context) {
			// Download specified object from Kubernetes cluster
			// example: spread add rc/mattermost
			resource := c.Args().First()
			if len(resource) == 0 {
				s.fatalf("A resource to be added must be specified")
			}

			context := c.String("context")
			cluster, err := deploy.NewKubeClusterFromContext(context)
			if err != nil {
				s.fatalf("Failed to connect to Kubernetes cluster: %v", err)
			}

			// parse resource type and name
			parts := strings.Split(resource, "/")
			if len(parts) != 2 {
				s.fatalf("Unrecognized resource format")
			}

			kind, name := parts[0], parts[1]
			namespace := c.String("namespace")
			export := !c.Bool("no-export")

			kubeObj, err := cluster.Get(kind, namespace, name, export)
			if err != nil {
				s.fatalf("Could not get object from cluster: %v", err)
			}

			if c.Bool("clean") {
				err = cleanObj(kubeObj)
				if err != nil {
					s.fatalf("Could not get object from cluster: %v", err)
				}
			}

			// TODO(DG): Clean this up
			gvk := kubeObj.GetObjectKind().GroupVersionKind()
			gvk.Version = "v1"
			kubeObj.GetObjectKind().SetGroupVersionKind(gvk)
			kubeObj.GetObjectMeta().SetNamespace(namespace)

			path, err := deploy.ObjectPath(kubeObj)
			if err != nil {
				s.fatalf("Failed to determine path to save object: %v", err)
			}

			obj, err := data.CreateDocument(kubeObj.GetObjectMeta().GetName(), path, kubeObj)
			if err != nil {
				s.fatalf("failed to encode document: %v", err)
			}

			proj := s.projectOrDie()
			err = proj.AddDocumentToIndex(obj)
			if err != nil {
				s.fatalf("Failed to add object to Git index: %v", err)
			}
		},
	}
}