// 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!") }, } }
func TestImageDeployment(t *testing.T) { imageName := "arch" simple := newDockerImage(t, imageName) image, err := NewImage(simple, kube.ObjectMeta{}, "test") assert.NoError(t, err, "valid image") expectedPod := kube.Pod{ ObjectMeta: kube.ObjectMeta{ GenerateName: imageName, Namespace: "default", }, Spec: kube.PodSpec{ Containers: []kube.Container{ { Name: imageName, Image: imageName, ImagePullPolicy: kube.PullAlways, }, }, RestartPolicy: kube.RestartPolicyAlways, DNSPolicy: kube.DNSDefault, }, } expected := new(deploy.Deployment) assert.NoError(t, expected.Add(&expectedPod), "should be able to add pod") actual, err := image.Deployment() assert.NoError(t, err, "deploy ok") testDeploymentEqual(t, expected, actual) }
func TestBaseNew(t *testing.T) { entityType := Type(rand.Intn(5)) source := randomString(8) var objects []deploy.KubeObject base, err := newBase(entityType, kube.ObjectMeta{}, source, objects) assert.NoError(t, err, "valid entity") assert.Equal(t, entityType, base.Type(), "type cannot change") assert.Equal(t, source, base.Source(), "source cannot change") emptyDeploy := deploy.Deployment{} assert.True(t, emptyDeploy.Equal(&base.objects)) }
func TestContainerWithImageDeployment(t *testing.T) { const imageName = "busybox:latest" kubeContainer := kube.Container{ Name: "simple-container", Image: imageName, Command: []string{"/bin/busybox", "ls"}, ImagePullPolicy: kube.PullAlways, } ctr, err := NewContainer(kubeContainer, kube.ObjectMeta{}, "simpleTest") assert.NoError(t, err, "should be able to create container") assert.NotNil(t, ctr.image, "an image should have been created") // check images images := ctr.Images() assert.Len(t, images, 1, "should have single image") expectedImage := newDockerImage(t, imageName) actualImage := images[0] assert.Equal(t, expectedImage.KubeImage(), actualImage.KubeImage(), "image should not have changed") // check kube kubectr, objects, err := ctr.data() assert.NoError(t, err, "should be able to produce kube") assert.True(t, kube.Semantic.DeepEqual(&kubectr, &kubeContainer), "kube should be same as container") assert.Equal(t, objects.Len(), 0, "no objects should have been added") pod := kube.Pod{ ObjectMeta: kube.ObjectMeta{ GenerateName: kubeContainer.Name, Namespace: kube.NamespaceDefault, }, Spec: kube.PodSpec{ Containers: []kube.Container{ kubeContainer, }, RestartPolicy: kube.RestartPolicyAlways, DNSPolicy: kube.DNSDefault, }, } expected := new(deploy.Deployment) assert.NoError(t, expected.Add(&pod), "valid pod") actual, err := ctr.Deployment() assert.NoError(t, err, "deploy ok") testDeploymentEqual(t, expected, actual) }
func TestPodWithContainersDeployment(t *testing.T) { kubePod := testCreateKubePodSourcegraph("deploy") pod, err := NewPod(kubePod, kube.ObjectMeta{}, "containers-deploy") assert.NoError(t, err, "valid pod") kubePod.Namespace = kube.NamespaceDefault expected := new(deploy.Deployment) err = expected.Add(kubePod) assert.NoError(t, err, "valid pod") actual, err := pod.Deployment() assert.NoError(t, err, "deployment should be valid") testDeploymentEqual(t, expected, actual) }
func objectOnlyDeploy(input *dir.FileInput) (*deploy.Deployment, error) { objects, err := input.Objects() if err != nil { return nil, err } else if len(objects) == 0 { return nil, ErrNothingDeployable } deployment := new(deploy.Deployment) for _, obj := range objects { err = deployment.Add(obj) if err != nil { return nil, err } } return deployment, nil }
// Deployment is created using Deployments of child Entities func (c *App) Deployment() (*deploy.Deployment, error) { d := new(deploy.Deployment) err := d.AddDeployment(c.objects) if err != nil { return nil, err } for _, entity := range c.children() { deploy, err := entity.Deployment() if err != nil { return nil, err } err = d.AddDeployment(*deploy) if err != nil { return nil, err } } return d, nil }
func TestContainerAttach(t *testing.T) { imageName := "to-be-attached" image := testNewImage(t, imageName, kube.ObjectMeta{}, "test", []deploy.KubeObject{}) kubeContainer := testNewKubeContainer("test-container", "") // no image container, err := NewContainer(kubeContainer, kube.ObjectMeta{}, "attach") assert.NoError(t, err, "valid container") _, err = container.Deployment() assert.Error(t, err, "cannot be deployed without image") err = container.Attach(image) assert.NoError(t, err, "attach should be allowed") children := container.children() assert.Contains(t, children, image, "should have image as child") images := container.Images() assert.Len(t, images, 1, "only one image should exist") kubeContainer.Image = imageName pod := kube.Pod{ ObjectMeta: kube.ObjectMeta{ GenerateName: kubeContainer.Name, Namespace: kube.NamespaceDefault, }, Spec: kube.PodSpec{ Containers: []kube.Container{ kubeContainer, }, RestartPolicy: kube.RestartPolicyAlways, DNSPolicy: kube.DNSDefault, }, } expected := new(deploy.Deployment) assert.NoError(t, expected.Add(&pod), "valid pod") actual, err := container.Deployment() assert.NoError(t, err, "deploy ok") testDeploymentEqual(t, expected, actual) }
func TestRCValidPodDeployment(t *testing.T) { selector := map[string]string{ "service": "postgres", } kubePod := testCreateKubePodSourcegraph("sourcegraph") kubePod.Labels = selector kubeRC := testNewKubeRC(kube.ObjectMeta{Name: "sourcegraph-rc", Namespace: kube.NamespaceDefault}, selector, kubePod) rc, err := NewReplicationController(kubeRC, kube.ObjectMeta{}, "") assert.NoError(t, err) assert.NotNil(t, rc.pod, "a pod should have be created") assert.Len(t, rc.pod.containers, 2, "two containers should have been created") expected := new(deploy.Deployment) err = expected.Add(kubeRC) assert.NoError(t, err, "should be valid RC") actual, err := rc.Deployment() assert.NoError(t, err) testDeploymentEqual(t, expected, actual) }
func newBase(t Type, defaults kube.ObjectMeta, source string, objects []deploy.KubeObject) (base base, err error) { base.defaults = defaults deployment := deploy.Deployment{} for _, obj := range objects { if obj == nil { err = ErrorNilObject return } base.setDefaults(obj) err = deployment.Add(obj) if err != nil { err = fmt.Errorf("error adding '%s': %v", source, err) return } } base.source = source base.entityType = t base.objects = deployment return }
// Deployment is created containing Pod with attached Containers. func (c *Pod) Deployment() (*deploy.Deployment, error) { deployment := deploy.Deployment{} // create Pod from tree of Entities kubePod, childObj, err := c.data() if err != nil { return nil, err } // add Pod to deployment err = deployment.Add(kubePod) if err != nil { return nil, err } // add child objects err = deployment.AddDeployment(childObj) if err != nil { return nil, err } return &deployment, nil }
func TestPodAttachImage(t *testing.T) { podObjects := testRandomObjects(3) kubePod := testNewKubePod("containerless") pod, err := NewPod(kubePod, kube.ObjectMeta{}, "pod", podObjects...) assert.NoError(t, err, "valid") imageObjects := testRandomObjects(3) kubeImage, err := image.FromString("bprashanth/nginxhttps:1.0") assert.NoError(t, err, "image should be valid") image, err := NewImage(kubeImage, kube.ObjectMeta{}, "image", imageObjects...) assert.NoError(t, err, "valid") err = pod.Attach(image) assert.NoError(t, err, "should be attachable") kubePod.Namespace = kube.NamespaceDefault kubePod.Spec.Containers = []kube.Container{ { Name: "nginxhttps", Image: "bprashanth/nginxhttps:1.0", ImagePullPolicy: kube.PullAlways, }, } objects := append(podObjects, imageObjects...) expected := new(deploy.Deployment) err = expected.Add(kubePod) assert.NoError(t, err, "valid") for _, obj := range objects { assert.NoError(t, expected.Add(obj)) } actual, err := pod.Deployment() assert.NoError(t, err, "deployment should be ok") testDeploymentEqual(t, expected, actual) }
// Deployment is created for RC attached with it's Pod. func (c *ReplicationController) Deployment() (*deploy.Deployment, error) { deployment := new(deploy.Deployment) // create RC kubeRC, childObj, err := c.data() if err != nil { return nil, err } // add RC to deployment err = deployment.Add(kubeRC) if err != nil { return nil, err } // add child objects err = deployment.AddDeployment(childObj) if err != nil { return nil, err } return deployment, nil }
func TestPodAttachContainer(t *testing.T) { podObjects := testRandomObjects(60) kubePod := testNewKubePod("containerless") pod, err := NewPod(kubePod, kube.ObjectMeta{}, "pod", podObjects...) assert.NoError(t, err, "valid") containerObjects := testRandomObjects(20) kubeContainer := testNewKubeContainer("container", "busybox:latest") container, err := NewContainer(kubeContainer, kube.ObjectMeta{}, "container", containerObjects...) assert.NoError(t, err) err = pod.Attach(container) assert.NoError(t, err) children := pod.children() assert.Contains(t, children, container, "should have container as child") kubePod.Namespace = kube.NamespaceDefault kubePod.Spec.Containers = []kube.Container{ kubeContainer, } expected := new(deploy.Deployment) err = expected.Add(kubePod) assert.NoError(t, err) actual, err := pod.Deployment() assert.NoError(t, err) objects := append(podObjects, containerObjects...) for _, obj := range objects { assert.NoError(t, expected.Add(obj)) } testDeploymentEqual(t, expected, actual) }
func testDeploymentEqual(t *testing.T, expected, actual *deploy.Deployment) bool { equal := expected.Equal(actual) return assert.True(t, equal, "expected: %s,\n actual: %s,\n diff:\n%s", expected, actual, expected.Diff(actual)) }
func TestRCAttachPod(t *testing.T) { kubeContainer := kube.Container{ Name: "redis", Image: "redis", ImagePullPolicy: kube.PullAlways, } selector := map[string]string{ "app": "db", } // create ReplicationController rcObjects := testRandomObjects(10) rc := testNewRC(t, "container-test", selector, rcObjects) // create kube.Pod // create Pod from created pod kubePod := &kube.Pod{ ObjectMeta: kube.ObjectMeta{Name: "attached"}, Spec: kube.PodSpec{ Containers: []kube.Container{ kubeContainer, }, RestartPolicy: kube.RestartPolicyAlways, DNSPolicy: kube.DNSDefault, }, } podObjects := testRandomObjects(10) pod, err := NewPod(kubePod, kube.ObjectMeta{}, "", podObjects...) assert.NoError(t, err, "should be valid pod") // Attach pod to RC // Should assume defaults up tree creating necessary components err = rc.Attach(pod) assert.NoError(t, err, "pod should be able to attach to ") children := rc.children() assert.Contains(t, children, pod, "should have image as child") // Compare internal elements assert.NotNil(t, rc.pod, "should of created pod") assert.Len(t, rc.pod.containers, 1) // Create struct representation for expected // Insert into Deployment // Create Deployment from RC rcMeta := rc.rc.ObjectMeta rcMeta.Namespace = kube.NamespaceDefault podMeta := pod.pod.ObjectMeta podMeta.Labels = selector expectedRC := &kube.ReplicationController{ ObjectMeta: rcMeta, Spec: kube.ReplicationControllerSpec{ Selector: selector, Template: &kube.PodTemplateSpec{ ObjectMeta: kube.ObjectMeta{ Namespace: kube.NamespaceDefault, Labels: selector, }, Spec: kubePod.Spec, }, }, } // Insert into Deployment expected := new(deploy.Deployment) err = expected.Add(expectedRC) assert.NoError(t, err, "should be valid RC") // add objects to deployment expected.AddDeployment(pod.objects) expected.AddDeployment(rc.objects) // Create Deployment from RC actual, err := rc.Deployment() assert.NoError(t, err, "should produce valid deployment") // Compare deployments testDeploymentEqual(t, expected, actual) // check images images := rc.Images() assert.Len(t, images, 1) }
func TestRCAttachImage(t *testing.T) { imageName := "rc-attach-image" rcName := "image-test" selector := map[string]string{ "app": "cache", } // create ReplicationController rcObjects := testRandomObjects(10) rc := testNewRC(t, rcName, selector, rcObjects) // create Image imageObjects := testRandomObjects(10) imageEntity := testNewImage(t, imageName, kube.ObjectMeta{}, "", imageObjects) // Attach image to RC // Should assume defaults up tree creating necessary components err := rc.Attach(imageEntity) assert.NoError(t, err, "attachment should be allowed") // Compare internal elements assert.NotNil(t, rc.pod, "should of created template") // Create struct representation for expected expectedRC := &kube.ReplicationController{ ObjectMeta: kube.ObjectMeta{ Name: rcName, Namespace: kube.NamespaceDefault, }, Spec: kube.ReplicationControllerSpec{ Selector: selector, Template: &kube.PodTemplateSpec{ ObjectMeta: kube.ObjectMeta{ Namespace: kube.NamespaceDefault, Labels: selector, }, Spec: kube.PodSpec{ Containers: []kube.Container{ { Name: imageName, Image: imageName, ImagePullPolicy: kube.PullAlways, }, }, RestartPolicy: kube.RestartPolicyAlways, DNSPolicy: kube.DNSDefault, }, }, }, } // Insert into Deployment expected := new(deploy.Deployment) err = expected.Add(expectedRC) assert.NoError(t, err, "should be valid RC") // add objects to deployment expected.AddDeployment(imageEntity.objects) expected.AddDeployment(rc.objects) // Create Deployment from RC actual, err := rc.Deployment() assert.NoError(t, err, "should produce valid deployment") // Compare deployments testDeploymentEqual(t, expected, actual) // check images images := rc.Images() expectedImage, _ := image.FromString(imageName) assert.Len(t, images, 1) for _, v := range images { assert.EqualValues(t, expectedImage, v, "should match original image") } }
func TestRCAttachContainer(t *testing.T) { containerName := "attached" imageName := "embedded-image" selector := map[string]string{ "app": "db", } // create ReplicationController rcObjects := testRandomObjects(10) rc := testNewRC(t, "container-test", selector, rcObjects) // create kube.Container // create Container from created container containerObjects := testRandomObjects(20) kubeContainer := testNewKubeContainer(containerName, imageName) container, err := NewContainer(kubeContainer, kube.ObjectMeta{}, "", containerObjects...) assert.NoError(t, err, "should be valid container") // Attach container to RC // Should assume defaults up tree creating necessary components err = rc.Attach(container) assert.NoError(t, err, "container should be able to attach to rc") // Compare internal elements assert.NotNil(t, rc.pod, "should of created pod") // assert.Len(t, rc.pod.containers, 1) // Create struct representation for expected // Insert into Deployment // Create Deployment from RC rcMeta := rc.rc.ObjectMeta rcMeta.Namespace = kube.NamespaceDefault expectedRC := &kube.ReplicationController{ ObjectMeta: rcMeta, Spec: kube.ReplicationControllerSpec{ Selector: selector, Template: &kube.PodTemplateSpec{ ObjectMeta: kube.ObjectMeta{ Labels: selector, Namespace: kube.NamespaceDefault, }, Spec: kube.PodSpec{ Containers: []kube.Container{ kubeContainer, }, RestartPolicy: kube.RestartPolicyAlways, DNSPolicy: kube.DNSDefault, }, }, }, } // Insert into Deployment expected := new(deploy.Deployment) err = expected.Add(expectedRC) assert.NoError(t, err, "should be valid RC") // add objects to deployment expected.AddDeployment(container.objects) expected.AddDeployment(rc.objects) // Create Deployment from RC actual, err := rc.Deployment() assert.NoError(t, err, "should produce valid deployment") // Compare deployments testDeploymentEqual(t, expected, actual) // check images images := rc.Images() assert.Len(t, images, 1) }