func (p *swarmProvisioner) ArchiveDeploy(a provision.App, archiveURL string, evt *event.Event) (imgID string, err error) { baseImage := image.GetBuildImage(a) buildingImage, err := image.AppNewImageName(a.GetName()) if err != nil { return "", errors.WithStack(err) } client, err := chooseDBSwarmNode() if err != nil { return "", err } cmds := dockercommon.ArchiveDeployCmds(a, archiveURL) srvID, task, err := runOnceBuildCmds(client, a, cmds, baseImage, buildingImage, evt) if srvID != "" { defer removeServiceAndLog(client, srvID) } if err != nil { return "", err } _, err = commitPushBuildImage(client, buildingImage, task.Status.ContainerStatus.ContainerID, a) if err != nil { return "", err } err = deployProcesses(client, a, buildingImage, nil) if err != nil { return "", errors.WithStack(err) } return buildingImage, nil }
func (s *S) TestGetImageFromAppPlatform(c *check.C) { app := provisiontest.NewFakeApp("myapp", "python", 1) img := image.GetBuildImage(app) repoNamespace, err := config.GetString("docker:repository-namespace") c.Assert(err, check.IsNil) c.Assert(img, check.Equals, fmt.Sprintf("%s/python:latest", repoNamespace)) }
func (s *S) TestArchiveDeployCanceledEvent(c *check.C) { err := s.newFakeImage(s.p, "tsuru/python:latest", nil) c.Assert(err, check.IsNil) app := provisiontest.NewFakeApp("myapp", "python", 1) routertest.FakeRouter.AddBackend(app.GetName()) defer routertest.FakeRouter.RemoveBackend(app.GetName()) evt, err := event.New(&event.Opts{ Target: event.Target{Type: "app", Value: "myapp"}, Kind: permission.PermAppDeploy, Owner: s.token, Cancelable: true, Allowed: event.Allowed(permission.PermApp), AllowedCancel: event.Allowed(permission.PermApp), }) c.Assert(err, check.IsNil) done := make(chan bool) go func() { defer close(done) img, depErr := s.p.archiveDeploy(app, image.GetBuildImage(app), "https://s3.amazonaws.com/wat/archive.tar.gz", evt) c.Assert(depErr, check.ErrorMatches, "deploy canceled by user action") c.Assert(img, check.Equals, "") }() time.Sleep(100 * time.Millisecond) err = evt.TryCancel("because yes", "*****@*****.**") c.Assert(err, check.IsNil) <-done }
func (p *dockerProvisioner) ArchiveDeploy(app provision.App, archiveURL string, evt *event.Event) (string, error) { imageId, err := p.archiveDeploy(app, image.GetBuildImage(app), archiveURL, evt) if err != nil { return "", err } return imageId, p.deployAndClean(app, imageId, evt) }
func (s *S) TestGetImageWithRegistry(c *check.C) { config.Set("docker:registry", "localhost:3030") defer config.Unset("docker:registry") app := provisiontest.NewFakeApp("myapp", "python", 1) img := image.GetBuildImage(app) repoNamespace, _ := config.GetString("docker:repository-namespace") expected := fmt.Sprintf("localhost:3030/%s/python:latest", repoNamespace) c.Assert(img, check.Equals, expected) }
func (s *S) TestArchiveDeploy(c *check.C) { stopCh := s.stopContainers(s.server.URL(), 1) defer func() { <-stopCh }() err := s.newFakeImage(s.p, "tsuru/python:latest", nil) c.Assert(err, check.IsNil) app := provisiontest.NewFakeApp("myapp", "python", 1) routertest.FakeRouter.AddBackend(app.GetName()) defer routertest.FakeRouter.RemoveBackend(app.GetName()) img, err := s.p.archiveDeploy(app, image.GetBuildImage(app), "https://s3.amazonaws.com/wat/archive.tar.gz", nil) c.Assert(err, check.IsNil) c.Assert(img, check.Equals, "tsuru/app-myapp:v1") }
func (s *S) TestGetImageAppWhenDeployIsMultipleOf10(c *check.C) { app := &app.App{Name: "app1", Platform: "python", Deploys: 20} err := s.storage.Apps().Insert(app) c.Assert(err, check.IsNil) cont := container.Container{ID: "bleble", Type: app.Platform, AppName: app.Name, Image: "tsuru/app1"} coll := s.p.Collection() err = coll.Insert(cont) c.Assert(err, check.IsNil) defer coll.Close() c.Assert(err, check.IsNil) defer coll.RemoveAll(bson.M{"id": cont.ID}) img := image.GetBuildImage(app) repoNamespace, err := config.GetString("docker:repository-namespace") c.Assert(err, check.IsNil) c.Assert(img, check.Equals, fmt.Sprintf("%s/%s:latest", repoNamespace, app.Platform)) }
func (s *S) TestStart(c *check.C) { err := s.newFakeImage(s.p, "tsuru/python:latest", nil) c.Assert(err, check.IsNil) app := provisiontest.NewFakeApp("myapp", "python", 1) imageId := image.GetBuildImage(app) routertest.FakeRouter.AddBackend(app.GetName()) defer routertest.FakeRouter.RemoveBackend(app.GetName()) var buf bytes.Buffer cont, err := s.p.start(&container.Container{ProcessName: "web"}, app, imageId, &buf, "") c.Assert(err, check.IsNil) defer cont.Remove(s.p) c.Assert(cont.ID, check.Not(check.Equals), "") cont2, err := s.p.GetContainer(cont.ID) c.Assert(err, check.IsNil) c.Assert(cont2.Image, check.Equals, imageId) c.Assert(cont2.Status, check.Equals, provision.StatusStarting.String()) }
func (s *S) TestArchiveDeployRegisterRace(c *check.C) { defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(10)) var p dockerProvisioner var registerCount int64 server, err := testing.NewServer("127.0.0.1:0", nil, func(r *http.Request) { go func(path string) { parts := strings.Split(path, "/") if len(parts) == 4 && parts[3] == "start" { registerErr := p.RegisterUnit(nil, parts[2], nil) if registerErr == nil { atomic.AddInt64(®isterCount, 1) } } }(r.URL.Path) }) c.Assert(err, check.IsNil) defer server.Stop() config.Set("docker:registry", "localhost:3030") defer config.Unset("docker:registry") err = p.Initialize() c.Assert(err, check.IsNil) p.cluster, err = cluster.New(nil, &cluster.MapStorage{}, cluster.Node{Address: server.URL()}) c.Assert(err, check.IsNil) err = s.newFakeImage(&p, "tsuru/python:latest", nil) c.Assert(err, check.IsNil) nTests := 100 stopCh := s.stopContainers(server.URL(), uint(nTests)) defer func() { <-stopCh }() wg := sync.WaitGroup{} for i := 0; i < nTests; i++ { wg.Add(1) go func(i int) { defer wg.Done() name := fmt.Sprintf("myapp-%d", i) app := provisiontest.NewFakeApp(name, "python", 1) routertest.FakeRouter.AddBackend(app.GetName()) defer routertest.FakeRouter.RemoveBackend(app.GetName()) img, _ := p.archiveDeploy(app, image.GetBuildImage(app), "https://s3.amazonaws.com/wat/archive.tar.gz", nil) c.Assert(img, check.Equals, "localhost:3030/tsuru/app-"+name+":v1") }(i) } wg.Wait() c.Assert(registerCount, check.Equals, int64(nTests)) }
func (p *swarmProvisioner) UploadDeploy(a provision.App, archiveFile io.ReadCloser, fileSize int64, build bool, evt *event.Event) (string, error) { defer archiveFile.Close() if build { return "", errors.New("running UploadDeploy with build=true is not yet supported") } client, err := chooseDBSwarmNode() if err != nil { return "", err } baseImage := image.GetBuildImage(a) buildingImage, err := image.AppNewImageName(a.GetName()) if err != nil { return "", errors.WithStack(err) } spec, err := serviceSpecForApp(tsuruServiceOpts{ app: a, image: baseImage, isDeploy: true, buildImage: buildingImage, }) if err != nil { return "", err } spec.TaskTemplate.ContainerSpec.Command = []string{"/usr/bin/tail", "-f", "/dev/null"} spec.TaskTemplate.RestartPolicy.Condition = swarm.RestartPolicyConditionNone srv, err := client.CreateService(docker.CreateServiceOptions{ ServiceSpec: *spec, }) if err != nil { return "", errors.WithStack(err) } tasks, err := waitForTasks(client, srv.ID, swarm.TaskStateRunning) if err != nil { return "", err } client, err = clientForNode(client, tasks[0].NodeID) if err != nil { return "", err } contID := tasks[0].Status.ContainerStatus.ContainerID imageID, fileURI, err := dockercommon.UploadToContainer(client, contID, archiveFile, fileSize) removeErr := client.RemoveService(docker.RemoveServiceOptions{ ID: srv.ID, }) if removeErr != nil { return "", errors.WithStack(removeErr) } if err != nil { return "", errors.WithStack(err) } cmds := dockercommon.ArchiveDeployCmds(a, fileURI) opts := tsuruServiceOpts{ app: a, image: imageID, isDeploy: true, buildImage: buildingImage, constraints: []string{ fmt.Sprintf("node.id == %s", tasks[0].NodeID), }, } srvID, task, err := runOnceCmds(client, opts, cmds, evt, evt) if srvID != "" { defer removeServiceAndLog(client, srvID) } if err != nil { return "", err } _, err = commitPushBuildImage(client, buildingImage, task.Status.ContainerStatus.ContainerID, a) if err != nil { return "", err } err = deployProcesses(client, a, buildingImage, nil) if err != nil { return "", errors.WithStack(err) } return buildingImage, nil }
func (p *dockerProvisioner) UploadDeploy(app provision.App, archiveFile io.ReadCloser, fileSize int64, build bool, evt *event.Event) (string, error) { if build { return "", errors.New("running UploadDeploy with build=true is not yet supported") } user, err := config.GetString("docker:user") if err != nil { user, _ = config.GetString("docker:ssh:user") } defer archiveFile.Close() imageName := image.GetBuildImage(app) options := docker.CreateContainerOptions{ Config: &docker.Config{ AttachStdout: true, AttachStderr: true, AttachStdin: true, OpenStdin: true, StdinOnce: true, User: user, Image: imageName, Cmd: []string{"/bin/bash", "-c", "tail -f /dev/null"}, }, } cluster := p.Cluster() schedOpts := &container.SchedulerOpts{ AppName: app.GetName(), ActionLimiter: p.ActionLimiter(), } addr, cont, err := cluster.CreateContainerSchedulerOpts(options, schedOpts, net.StreamInactivityTimeout) hostAddr := net.URLToHost(addr) if schedOpts.LimiterDone != nil { schedOpts.LimiterDone() } if err != nil { return "", err } defer func() { done := p.ActionLimiter().Start(hostAddr) cluster.RemoveContainer(docker.RemoveContainerOptions{ID: cont.ID, Force: true}) done() }() done := p.ActionLimiter().Start(hostAddr) err = cluster.StartContainer(cont.ID, nil) done() if err != nil { return "", err } intermediateImageID, fileURI, err := dockercommon.UploadToContainer(cluster, cont.ID, archiveFile, fileSize) done = p.ActionLimiter().Start(hostAddr) stopErr := cluster.StopContainer(cont.ID, 10) done() if stopErr != nil { return "", stopErr } if err != nil { return "", err } imageId, err := p.archiveDeploy(app, intermediateImageID, fileURI, evt) if err != nil { return "", err } return imageId, p.deployAndClean(app, imageId, evt) }