예제 #1
0
파일: auto_scale.go 프로젝트: keymon/tsuru
func (a *autoScaleConfig) removeNode(chosenNode *cluster.Node) error {
	_, hasIaas := chosenNode.Metadata["iaas"]
	if !hasIaas {
		return fmt.Errorf("no IaaS information in node (%s) metadata: %#v", chosenNode.Address, chosenNode.Metadata)
	}
	err := a.provisioner.getCluster().Unregister(chosenNode.Address)
	if err != nil {
		return fmt.Errorf("unable to unregister node (%s) for removal: %s", chosenNode.Address, err)
	}
	buf := safe.NewBuffer(nil)
	err = a.provisioner.moveContainers(urlToHost(chosenNode.Address), "", buf)
	if err != nil {
		a.provisioner.getCluster().Register(chosenNode.Address, chosenNode.Metadata)
		return fmt.Errorf("unable to move containers from node (%s): %s - log: %s", chosenNode.Address, err, buf.String())
	}
	m, err := iaas.FindMachineByIdOrAddress(chosenNode.Metadata["iaas-id"], urlToHost(chosenNode.Address))
	if err != nil {
		a.logError("unable to find machine for removal in iaas: %s", err)
		return nil
	}
	err = m.Destroy()
	if err != nil {
		a.logError("unable to destroy machine in IaaS: %s", err)
	}
	return nil
}
예제 #2
0
파일: shell_test.go 프로젝트: keymon/tsuru
func (s *S) TestAppShellSpecifyUnit(c *check.C) {
	a := app.App{
		Name:     "someapp",
		Platform: "zend",
		Teams:    []string{s.team.Name},
	}
	err := s.conn.Apps().Insert(a)
	c.Assert(err, check.IsNil)
	defer s.conn.Apps().Remove(bson.M{"name": a.Name})
	defer s.logConn.Logs(a.Name).DropCollection()
	err = s.provisioner.Provision(&a)
	c.Assert(err, check.IsNil)
	defer s.provisioner.Destroy(&a)
	s.provisioner.AddUnits(&a, 5, "web", nil)
	unit := s.provisioner.Units(&a)[3]
	url := fmt.Sprintf("/shell?:app=%s&width=140&height=38&term=xterm&unit=%s", a.Name, unit.Name)
	request, err := http.NewRequest("GET", url, nil)
	c.Assert(err, check.IsNil)
	buf := safe.NewBuffer([]byte("echo teste"))
	recorder := provisiontest.Hijacker{Conn: &provisiontest.FakeConn{Buf: buf}}
	err = remoteShellHandler(&recorder, request, s.token)
	c.Assert(err, check.IsNil)
	shells := s.provisioner.Shells(unit.Name)
	c.Assert(shells, check.HasLen, 1)
	c.Assert(shells[0].App.GetName(), check.Equals, a.Name)
	c.Assert(shells[0].Width, check.Equals, 140)
	c.Assert(shells[0].Height, check.Equals, 38)
	c.Assert(shells[0].Term, check.Equals, "xterm")
	c.Assert(shells[0].Unit, check.Equals, unit.Name)
	for _, u := range s.provisioner.Units(&a) {
		if u.Name != unit.Name {
			c.Check(s.provisioner.Shells(u.Name), check.HasLen, 0)
		}
	}
}
예제 #3
0
func (s *S) TestEnsureContainersStartedOnlyChild(c *check.C) {
	err := nodecontainer.AddNewContainer("p1", &nodecontainer.NodeContainerConfig{
		Name: "c1",
		Config: docker.Config{
			Image: "myregistry/tsuru/bs",
		},
	})
	c.Assert(err, check.IsNil)
	p, err := dockertest.StartMultipleServersCluster()
	c.Assert(err, check.IsNil)
	defer p.Destroy()
	clust := p.Cluster()
	nodes, err := clust.Nodes()
	c.Assert(err, check.IsNil)
	c.Assert(nodes, check.HasLen, 2)
	nodes[0].Metadata["pool"] = "p1"
	_, err = p.Cluster().UpdateNode(nodes[0])
	c.Assert(err, check.IsNil)
	nodes[1].Metadata["pool"] = "p2"
	_, err = p.Cluster().UpdateNode(nodes[1])
	c.Assert(err, check.IsNil)
	buf := safe.NewBuffer(nil)
	err = ensureContainersStarted(p, buf, true, nil)
	c.Assert(err, check.IsNil)
	client, err := docker.NewClient(nodes[0].Address)
	c.Assert(err, check.IsNil)
	containers, err := client.ListContainers(docker.ListContainersOptions{All: true})
	c.Assert(err, check.IsNil)
	c.Assert(containers, check.HasLen, 1)
	client2, err := docker.NewClient(nodes[1].Address)
	c.Assert(err, check.IsNil)
	containers2, err := client2.ListContainers(docker.ListContainersOptions{All: true})
	c.Assert(err, check.IsNil)
	c.Assert(containers2, check.HasLen, 0)
}
func (s *HandlersSuite) TestSSHToContainerHandler(c *gocheck.C) {
	sshServer := newMockSSHServer(c, 2e9)
	defer sshServer.Shutdown()
	coll := collection()
	defer coll.Close()
	container := container{
		ID:          "9930c24f1c4x",
		AppName:     "makea",
		Type:        "python",
		Status:      provision.StatusStarted.String(),
		IP:          "127.0.0.4",
		HostPort:    "9025",
		HostAddr:    "localhost",
		SSHHostPort: sshServer.port,
		PrivateKey:  string(fakeServerPrivateKey),
		User:        sshUsername(),
	}
	err := coll.Insert(container)
	c.Assert(err, gocheck.IsNil)
	defer coll.RemoveAll(bson.M{"appname": "makea"})
	tmpDir, err := ioutil.TempDir("", "containerssh")
	defer os.RemoveAll(tmpDir)
	filepath := path.Join(tmpDir, "file.txt")
	file, err := os.Create(filepath)
	c.Assert(err, gocheck.IsNil)
	file.Write([]byte("hello"))
	file.Close()
	buf := safe.NewBuffer([]byte("cat " + filepath + "\nexit\n"))
	recorder := hijacker{conn: &fakeConn{buf}}
	request, err := http.NewRequest("GET", "/?:container_id="+container.ID, nil)
	c.Assert(err, gocheck.IsNil)
	err = sshToContainerHandler(&recorder, request, nil)
	c.Assert(err, gocheck.IsNil)
}
예제 #5
0
파일: suite_test.go 프로젝트: tsuru/tsuru
func (s *S) SetUpTest(c *check.C) {
	config.Set("docker:api-timeout", 2)
	iaas.ResetAll()
	repositorytest.Reset()
	queue.ResetQueue()
	repository.Manager().CreateUser(s.user.Email)
	s.p = &dockerProvisioner{storage: &cluster.MapStorage{}}
	err := s.p.Initialize()
	c.Assert(err, check.IsNil)
	queue.ResetQueue()
	s.server, err = dtesting.NewServer("127.0.0.1:0", nil, nil)
	c.Assert(err, check.IsNil)
	s.p.cluster, err = cluster.New(nil, s.p.storage,
		cluster.Node{Address: s.server.URL(), Metadata: map[string]string{"pool": "test-default"}},
	)
	c.Assert(err, check.IsNil)
	mainDockerProvisioner = s.p
	err = dbtest.ClearAllCollectionsExcept(s.storage.Apps().Database, []string{"users", "tokens", "teams"})
	c.Assert(err, check.IsNil)
	err = clearClusterStorage(s.clusterSess)
	c.Assert(err, check.IsNil)
	routertest.FakeRouter.Reset()
	opts := provision.AddPoolOptions{Name: "test-default", Default: true}
	err = provision.AddPool(opts)
	c.Assert(err, check.IsNil)
	s.storage.Tokens().Remove(bson.M{"appname": bson.M{"$ne": ""}})
	s.logBuf = safe.NewBuffer(nil)
	log.SetLogger(log.NewWriterLogger(s.logBuf, true))
	s.token = createTokenForUser(s.user, "*", string(permission.CtxGlobal), "", c)
}
예제 #6
0
func (s *S) TestFollowLogsAndCommitForward(c *check.C) {
	err := s.newFakeImage(s.p, "tsuru/python", nil)
	c.Assert(err, check.IsNil)
	app := provisiontest.NewFakeApp("mightyapp", "python", 1)
	nextImgName, err := appNewImageName(app.GetName())
	c.Assert(err, check.IsNil)
	cont := container.Container{AppName: "mightyapp", ID: "myid123", BuildingImage: nextImgName}
	err = cont.Create(&container.CreateArgs{
		App:         app,
		ImageID:     "tsuru/python",
		Commands:    []string{"foo"},
		Provisioner: s.p,
	})
	c.Assert(err, check.IsNil)
	buf := safe.NewBuffer(nil)
	args := runContainerActionsArgs{writer: buf, provisioner: s.p}
	context := action.FWContext{Params: []interface{}{args}, Previous: cont}
	imageId, err := followLogsAndCommit.Forward(context)
	c.Assert(err, check.IsNil)
	c.Assert(imageId, check.Equals, "tsuru/app-mightyapp:v1")
	c.Assert(buf.String(), check.Not(check.Equals), "")
	var dbCont container.Container
	coll := s.p.Collection()
	defer coll.Close()
	err = coll.Find(bson.M{"id": cont.ID}).One(&dbCont)
	c.Assert(err, check.NotNil)
	c.Assert(err.Error(), check.Equals, "not found")
	_, err = s.p.Cluster().InspectContainer(cont.ID)
	c.Assert(err, check.NotNil)
	c.Assert(err.Error(), check.Matches, "No such container.*")
	err = s.p.Cluster().RemoveImage("tsuru/app-mightyapp:v1")
	c.Assert(err, check.IsNil)
}
예제 #7
0
func (s *S) TestBindAndHealthcheckBackward(c *check.C) {
	appName := "my-fake-app"
	err := s.newFakeImage(s.p, "tsuru/app-"+appName, nil)
	c.Assert(err, check.IsNil)
	fakeApp := provisiontest.NewFakeApp(appName, "python", 0)
	s.p.Provision(fakeApp)
	defer s.p.Destroy(fakeApp)
	buf := safe.NewBuffer(nil)
	args := changeUnitsPipelineArgs{
		app:         fakeApp,
		provisioner: s.p,
		writer:      buf,
		toAdd:       map[string]*containersToAdd{"web": {Quantity: 2}},
		imageId:     "tsuru/app-" + appName,
	}
	containers, err := addContainersWithHost(&args)
	c.Assert(err, check.IsNil)
	c.Assert(containers, check.HasLen, 2)
	context := action.BWContext{Params: []interface{}{args}, FWResult: containers}
	for _, c := range containers {
		u := c.AsUnit(fakeApp)
		fakeApp.BindUnit(&u)
	}
	bindAndHealthcheck.Backward(context)
	c.Assert(err, check.IsNil)
	u1 := containers[0].AsUnit(fakeApp)
	c.Assert(fakeApp.HasBind(&u1), check.Equals, false)
	u2 := containers[1].AsUnit(fakeApp)
	c.Assert(fakeApp.HasBind(&u2), check.Equals, false)
}
예제 #8
0
func (s *S) TestMoveContainerErrorStarted(c *check.C) {
	p, err := s.startMultipleServersCluster()
	c.Assert(err, check.IsNil)
	err = s.newFakeImage(p, "tsuru/app-myapp", nil)
	c.Assert(err, check.IsNil)
	appInstance := provisiontest.NewFakeApp("myapp", "python", 0)
	p.Provision(appInstance)
	imageId, err := image.AppCurrentImageName(appInstance.GetName())
	c.Assert(err, check.IsNil)
	addedConts, err := addContainersWithHost(&changeUnitsPipelineArgs{
		toHost:      "localhost",
		toAdd:       map[string]*containersToAdd{"web": {Quantity: 2}},
		app:         appInstance,
		imageId:     imageId,
		provisioner: p,
	})
	c.Assert(err, check.IsNil)
	err = addedConts[0].SetStatus(p, provision.StatusError, true)
	c.Assert(err, check.IsNil)
	appStruct := &app.App{
		Name: appInstance.GetName(),
	}
	err = s.storage.Apps().Insert(appStruct)
	c.Assert(err, check.IsNil)
	buf := safe.NewBuffer(nil)
	_, err = p.moveContainer(addedConts[0].ID[:6], "127.0.0.1", buf)
	c.Assert(err, check.IsNil)
	containers, err := p.listContainersByHost("localhost")
	c.Assert(err, check.IsNil)
	c.Assert(containers, check.HasLen, 1)
	containers, err = p.listContainersByHost("127.0.0.1")
	c.Assert(err, check.IsNil)
	c.Assert(containers, check.HasLen, 1)
	c.Assert(containers[0].Status, check.Equals, provision.StatusStarting.String())
}
예제 #9
0
파일: actions_test.go 프로젝트: tsuru/tsuru
func (s *S) TestFollowLogsAndCommitForwardWaitFailure(c *check.C) {
	s.server.PrepareFailure("failed to wait for the container", "/containers/.*/wait")
	defer s.server.ResetFailure("failed to wait for the container")
	err := s.newFakeImage(s.p, "tsuru/python", nil)
	c.Assert(err, check.IsNil)
	app := provisiontest.NewFakeApp("myapp", "python", 1)
	cont := container.Container{AppName: "mightyapp"}
	err = cont.Create(&container.CreateArgs{
		App:         app,
		ImageID:     "tsuru/python",
		Commands:    []string{"foo"},
		Provisioner: s.p,
	})
	c.Assert(err, check.IsNil)
	err = cont.Start(&container.StartArgs{
		Provisioner: s.p,
		App:         app,
	})
	c.Assert(err, check.IsNil)
	err = cont.Stop(s.p)
	c.Assert(err, check.IsNil)
	buf := safe.NewBuffer(nil)
	args := runContainerActionsArgs{writer: buf, provisioner: s.p}
	context := action.FWContext{Params: []interface{}{args}, Previous: cont}
	imageId, err := followLogsAndCommit.Forward(context)
	c.Assert(err, check.ErrorMatches, `.*failed to wait for the container\n$`)
	c.Assert(imageId, check.IsNil)
}
예제 #10
0
func (s *S) TestRebalanceContainers(c *check.C) {
	p, err := s.startMultipleServersCluster()
	c.Assert(err, check.IsNil)
	err = s.newFakeImage(p, "tsuru/app-myapp", nil)
	c.Assert(err, check.IsNil)
	appInstance := provisiontest.NewFakeApp("myapp", "python", 0)
	defer p.Destroy(appInstance)
	p.Provision(appInstance)
	imageId, err := appCurrentImageName(appInstance.GetName())
	c.Assert(err, check.IsNil)
	_, err = addContainersWithHost(&changeUnitsPipelineArgs{
		toHost:      "localhost",
		toAdd:       map[string]*containersToAdd{"web": {Quantity: 5}},
		app:         appInstance,
		imageId:     imageId,
		provisioner: p,
	})
	c.Assert(err, check.IsNil)
	appStruct := &app.App{
		Name: appInstance.GetName(),
	}
	err = s.storage.Apps().Insert(appStruct)
	c.Assert(err, check.IsNil)
	buf := safe.NewBuffer(nil)
	err = p.rebalanceContainers(buf, false)
	c.Assert(err, check.IsNil)
	c1, err := p.listContainersByHost("localhost")
	c.Assert(err, check.IsNil)
	c2, err := p.listContainersByHost("127.0.0.1")
	c.Assert(err, check.IsNil)
	c.Assert((len(c1) == 3 && len(c2) == 2) || (len(c1) == 2 && len(c2) == 3), check.Equals, true)
}
예제 #11
0
func (s *S) TestEnsureContainersStartedForceStopOnlyOnFailure(c *check.C) {
	config.Set("docker:bs:image", "myregistry/tsuru/bs")
	_, err := nodecontainer.InitializeBS()
	c.Assert(err, check.IsNil)
	var reqs []*http.Request
	server, err := testing.NewServer("127.0.0.1:0", nil, func(r *http.Request) {
		reqs = append(reqs, r)
	})
	c.Assert(err, check.IsNil)
	defer server.Stop()
	errCount := 0
	server.CustomHandler("/containers/big-sibling", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		reqs = append(reqs, r)
		if r.Method != "DELETE" {
			server.DefaultHandler().ServeHTTP(w, r)
			return
		}
		errCount++
		if errCount > 2 {
			server.DefaultHandler().ServeHTTP(w, r)
		} else {
			w.WriteHeader(http.StatusInternalServerError)
		}
	}))
	p, err := dockertest.NewFakeDockerProvisioner(server.URL())
	c.Assert(err, check.IsNil)
	defer p.Destroy()
	client, err := docker.NewClient(server.URL())
	c.Assert(err, check.IsNil)
	buf := safe.NewBuffer(nil)
	err = ensureContainersStarted(p, buf, true, nil)
	c.Assert(err, check.IsNil)
	reqs = nil
	err = ensureContainersStarted(p, buf, true, nil)
	c.Assert(err, check.IsNil)
	var paths []string
	for _, r := range reqs {
		paths = append(paths, r.Method+" "+r.URL.Path)
	}
	c.Assert(paths, check.DeepEquals, []string{
		"POST /images/create",
		"POST /containers/create",
		"POST /containers/big-sibling/stop",
		"DELETE /containers/big-sibling",
		"DELETE /containers/big-sibling",
		"DELETE /containers/big-sibling",
		"POST /containers/create",
		"GET /version",
		"POST /containers/big-sibling/start",
	})
	c.Assert(reqs[3].URL.Query().Get("force"), check.Equals, "")
	c.Assert(reqs[4].URL.Query().Get("force"), check.Equals, "1")
	c.Assert(reqs[5].URL.Query().Get("force"), check.Equals, "1")
	containers, err := client.ListContainers(docker.ListContainersOptions{All: true})
	c.Assert(err, check.IsNil)
	c.Assert(containers, check.HasLen, 1)
	container, err := client.InspectContainer(containers[0].ID)
	c.Assert(err, check.IsNil)
	c.Assert(container.Name, check.Equals, nodecontainer.BsDefaultName)
}
예제 #12
0
func (s *S) TestRebalanceContainersManyApps(c *check.C) {
	p, err := s.startMultipleServersCluster()
	c.Assert(err, check.IsNil)
	err = s.newFakeImage(p, "tsuru/app-myapp", nil)
	c.Assert(err, check.IsNil)
	err = s.newFakeImage(p, "tsuru/app-otherapp", nil)
	c.Assert(err, check.IsNil)
	appInstance := provisiontest.NewFakeApp("myapp", "python", 0)
	defer p.Destroy(appInstance)
	p.Provision(appInstance)
	appInstance2 := provisiontest.NewFakeApp("otherapp", "python", 0)
	defer p.Destroy(appInstance2)
	p.Provision(appInstance2)
	imageId, err := image.AppCurrentImageName(appInstance.GetName())
	c.Assert(err, check.IsNil)
	_, err = addContainersWithHost(&changeUnitsPipelineArgs{
		toHost:      "localhost",
		toAdd:       map[string]*containersToAdd{"web": {Quantity: 1}},
		app:         appInstance,
		imageId:     imageId,
		provisioner: p,
	})
	c.Assert(err, check.IsNil)
	imageId2, err := image.AppCurrentImageName(appInstance2.GetName())
	c.Assert(err, check.IsNil)
	_, err = addContainersWithHost(&changeUnitsPipelineArgs{
		toHost:      "localhost",
		toAdd:       map[string]*containersToAdd{"web": {Quantity: 1}},
		app:         appInstance2,
		imageId:     imageId2,
		provisioner: p,
	})
	c.Assert(err, check.IsNil)
	appStruct := &app.App{
		Name: appInstance.GetName(),
		Pool: "test-default",
	}
	err = s.storage.Apps().Insert(appStruct)
	c.Assert(err, check.IsNil)
	appStruct2 := &app.App{
		Name: appInstance2.GetName(),
		Pool: "test-default",
	}
	err = s.storage.Apps().Insert(appStruct2)
	c.Assert(err, check.IsNil)
	buf := safe.NewBuffer(nil)
	c1, err := p.listContainersByHost("localhost")
	c.Assert(err, check.IsNil)
	c.Assert(c1, check.HasLen, 2)
	err = p.rebalanceContainers(buf, false)
	c.Assert(err, check.IsNil)
	c1, err = p.listContainersByHost("localhost")
	c.Assert(err, check.IsNil)
	c.Assert(c1, check.HasLen, 1)
	c2, err := p.listContainersByHost("127.0.0.1")
	c.Assert(err, check.IsNil)
	c.Assert(c2, check.HasLen, 1)
}
예제 #13
0
func (s *S) TestBindAndHealthcheckDontHealtcheckForErroredApps(c *check.C) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNotFound)
	}))
	defer server.Close()
	conn, err := db.Conn()
	c.Assert(err, check.IsNil)
	defer conn.Close()
	dbApp := &app.App{Name: "myapp"}
	err = conn.Apps().Insert(dbApp)
	c.Assert(err, check.IsNil)
	defer conn.Apps().Remove(bson.M{"name": dbApp.Name})
	imageName := "tsuru/app-" + dbApp.Name
	customData := map[string]interface{}{
		"healthcheck": map[string]interface{}{
			"path":   "/x/y",
			"status": http.StatusOK,
		},
		"procfile": "web: python myapp.py",
	}
	err = s.newFakeImage(s.p, imageName, customData)
	c.Assert(err, check.IsNil)
	fakeApp := provisiontest.NewFakeApp(dbApp.Name, "python", 0)
	s.p.Provision(fakeApp)
	defer s.p.Destroy(fakeApp)
	buf := safe.NewBuffer(nil)
	contOpts := newContainerOpts{
		Status: "error",
	}
	oldContainer, err := s.newContainer(&contOpts, nil)
	c.Assert(err, check.IsNil)
	args := changeUnitsPipelineArgs{
		app:         fakeApp,
		provisioner: s.p,
		writer:      buf,
		toAdd:       map[string]*containersToAdd{"web": {Quantity: 2}},
		imageId:     "tsuru/app-" + dbApp.Name,
		toRemove:    []container{*oldContainer},
	}
	containers, err := addContainersWithHost(&args)
	c.Assert(err, check.IsNil)
	c.Assert(containers, check.HasLen, 2)
	url, _ := url.Parse(server.URL)
	host, port, _ := net.SplitHostPort(url.Host)
	containers[0].HostAddr = host
	containers[0].HostPort = port
	containers[1].HostAddr = host
	containers[1].HostPort = port
	context := action.FWContext{Params: []interface{}{args}, Previous: containers}
	result, err := bindAndHealthcheck.Forward(context)
	c.Assert(err, check.IsNil)
	resultContainers := result.([]container)
	c.Assert(resultContainers, check.DeepEquals, containers)
	u1 := containers[0].asUnit(fakeApp)
	u2 := containers[1].asUnit(fakeApp)
	c.Assert(fakeApp.HasBind(&u1), check.Equals, true)
	c.Assert(fakeApp.HasBind(&u2), check.Equals, true)
}
예제 #14
0
func (s *S) TestRebalanceContainersByHost(c *check.C) {
	otherServer, err := dtesting.NewServer("localhost:0", nil, nil)
	c.Assert(err, check.IsNil)
	defer otherServer.Stop()
	otherUrl := strings.Replace(otherServer.URL(), "127.0.0.1", "localhost", 1)
	p := &dockerProvisioner{}
	err = p.Initialize()
	c.Assert(err, check.IsNil)
	p.storage = &cluster.MapStorage{}
	p.scheduler = &segregatedScheduler{provisioner: p}
	p.cluster, err = cluster.New(p.scheduler, p.storage,
		cluster.Node{Address: s.server.URL(), Metadata: map[string]string{"pool": "pool1"}},
		cluster.Node{Address: otherUrl, Metadata: map[string]string{"pool": "pool1"}},
	)
	c.Assert(err, check.IsNil)
	opts := provision.AddPoolOptions{Name: "pool1"}
	err = provision.AddPool(opts)
	c.Assert(err, check.IsNil)
	err = provision.AddTeamsToPool("pool1", []string{"team1"})
	c.Assert(err, check.IsNil)
	err = s.newFakeImage(p, "tsuru/app-myapp", nil)
	c.Assert(err, check.IsNil)
	appInstance := provisiontest.NewFakeApp("myapp", "python", 0)
	defer p.Destroy(appInstance)
	p.Provision(appInstance)
	imageId, err := appCurrentImageName(appInstance.GetName())
	c.Assert(err, check.IsNil)
	_, err = addContainersWithHost(&changeUnitsPipelineArgs{
		toHost:      "localhost",
		toAdd:       map[string]*containersToAdd{"web": {Quantity: 5}},
		app:         appInstance,
		imageId:     imageId,
		provisioner: p,
	})
	c.Assert(err, check.IsNil)
	appStruct := &app.App{
		Name:      appInstance.GetName(),
		TeamOwner: "team1",
		Pool:      "pool1",
	}
	err = s.storage.Apps().Insert(appStruct)
	c.Assert(err, check.IsNil)
	c1, err := p.listContainersByHost("localhost")
	c.Assert(err, check.IsNil)
	c.Assert(c1, check.HasLen, 5)
	c2, err := p.listContainersByHost("127.0.0.1")
	c.Assert(err, check.IsNil)
	c.Assert(c2, check.HasLen, 0)
	err = p.Cluster().Unregister(otherUrl)
	c.Assert(err, check.IsNil)
	buf := safe.NewBuffer(nil)
	err = p.rebalanceContainersByHost(net.URLToHost(otherUrl), buf)
	c.Assert(err, check.IsNil)
	c.Assert(p.scheduler.ignoredContainers, check.IsNil)
	c2, err = p.listContainersByHost("127.0.0.1")
	c.Assert(err, check.IsNil)
	c.Assert(c2, check.HasLen, 5)
}
예제 #15
0
파일: auto_scale.go 프로젝트: keymon/tsuru
func (a *autoScaleConfig) rebalanceIfNeeded(event *autoScaleEvent, groupMetadata string, nodes []*cluster.Node) error {
	if a.preventRebalance {
		return nil
	}
	var rebalanceFilter map[string]string
	if a.groupByMetadata != "" {
		rebalanceFilter = map[string]string{a.groupByMetadata: groupMetadata}
	}
	if event.Action == "" {
		// No action yet, check if we need rebalance
		_, gap, err := a.provisioner.containerGapInNodes(nodes)
		buf := safe.NewBuffer(nil)
		dryProvisioner, err := a.provisioner.rebalanceContainersByFilter(buf, nil, rebalanceFilter, true)
		if err != nil {
			return fmt.Errorf("unable to run dry rebalance to check if rebalance is needed: %s - log: %s", err, buf.String())
		}
		if dryProvisioner == nil {
			return nil
		}
		_, gapAfter, err := dryProvisioner.containerGapInNodes(nodes)
		if err != nil {
			return fmt.Errorf("couldn't find containers from rebalanced nodes: %s", err)
		}
		if math.Abs((float64)(gap-gapAfter)) > 2.0 {
			err = event.update(scaleActionRebalance, fmt.Sprintf("gap is %d, after rebalance gap will be %d", gap, gapAfter))
			if err != nil {
				return fmt.Errorf("unable to update event: %s", err)
			}
		}
	}
	if event.Action != "" && event.Action != scaleActionRemove {
		a.logDebug("running rebalance, due to %q for %q: %s", event.Action, event.MetadataValue, event.Reason)
		buf := safe.NewBuffer(nil)
		var writer io.Writer = buf
		if a.writer != nil {
			writer = io.MultiWriter(buf, a.writer)
		}
		_, err := a.provisioner.rebalanceContainersByFilter(writer, nil, rebalanceFilter, false)
		if err != nil {
			return fmt.Errorf("unable to rebalance containers: %s - log: %s", err.Error(), buf.String())
		}
		return nil
	}
	return nil
}
예제 #16
0
func (s *S) TestRebalanceContainersDry(c *check.C) {
	p, err := s.startMultipleServersCluster()
	c.Assert(err, check.IsNil)
	err = s.newFakeImage(p, "tsuru/app-myapp", nil)
	c.Assert(err, check.IsNil)
	appInstance := provisiontest.NewFakeApp("myapp", "python", 0)
	defer p.Destroy(appInstance)
	p.Provision(appInstance)
	imageId, err := image.AppCurrentImageName(appInstance.GetName())
	c.Assert(err, check.IsNil)
	args := changeUnitsPipelineArgs{
		app:         appInstance,
		toAdd:       map[string]*containersToAdd{"web": {Quantity: 5}},
		imageId:     imageId,
		provisioner: p,
		toHost:      "localhost",
	}
	pipeline := action.NewPipeline(
		&provisionAddUnitsToHost,
		&bindAndHealthcheck,
		&addNewRoutes,
		&setRouterHealthcheck,
		&updateAppImage,
	)
	err = pipeline.Execute(args)
	c.Assert(err, check.IsNil)
	appStruct := &app.App{
		Name: appInstance.GetName(),
		Pool: "test-default",
	}
	err = s.storage.Apps().Insert(appStruct)
	c.Assert(err, check.IsNil)
	router, err := getRouterForApp(appInstance)
	c.Assert(err, check.IsNil)
	beforeRoutes, err := router.Routes(appStruct.Name)
	c.Assert(err, check.IsNil)
	c.Assert(beforeRoutes, check.HasLen, 5)
	var serviceCalled bool
	rollback := s.addServiceInstance(c, appInstance.GetName(), nil, func(w http.ResponseWriter, r *http.Request) {
		serviceCalled = true
		w.WriteHeader(http.StatusOK)
	})
	defer rollback()
	buf := safe.NewBuffer(nil)
	err = p.rebalanceContainers(buf, true)
	c.Assert(err, check.IsNil)
	c1, err := p.listContainersByHost("localhost")
	c.Assert(err, check.IsNil)
	c2, err := p.listContainersByHost("127.0.0.1")
	c.Assert(err, check.IsNil)
	c.Assert(c1, check.HasLen, 5)
	c.Assert(c2, check.HasLen, 0)
	routes, err := router.Routes(appStruct.Name)
	c.Assert(err, check.IsNil)
	c.Assert(routes, check.DeepEquals, beforeRoutes)
	c.Assert(serviceCalled, check.Equals, false)
}
예제 #17
0
func (s *S) TestMoveContainer(c *check.C) {
	p, err := s.startMultipleServersCluster()
	c.Assert(err, check.IsNil)
	err = s.newFakeImage(p, "tsuru/app-myapp", nil)
	c.Assert(err, check.IsNil)
	appInstance := provisiontest.NewFakeApp("myapp", "python", 0)
	defer p.Destroy(appInstance)
	p.Provision(appInstance)
	coll := p.Collection()
	defer coll.Close()
	coll.Insert(container.Container{
		ID:      "container-id",
		AppName: appInstance.GetName(),
		Version: "container-version",
		Image:   "tsuru/python",
	})
	defer coll.RemoveAll(bson.M{"appname": appInstance.GetName()})
	imageId, err := image.AppCurrentImageName(appInstance.GetName())
	c.Assert(err, check.IsNil)
	addedConts, err := addContainersWithHost(&changeUnitsPipelineArgs{
		toHost:      "localhost",
		toAdd:       map[string]*containersToAdd{"web": {Quantity: 2}},
		app:         appInstance,
		imageId:     imageId,
		provisioner: p,
	})
	c.Assert(err, check.IsNil)
	appStruct := &app.App{
		Name: appInstance.GetName(),
	}
	err = s.storage.Apps().Insert(appStruct)
	c.Assert(err, check.IsNil)
	buf := safe.NewBuffer(nil)
	var serviceBodies []string
	var serviceMethods []string
	rollback := s.addServiceInstance(c, appInstance.GetName(), []string{addedConts[0].ID}, func(w http.ResponseWriter, r *http.Request) {
		data, _ := ioutil.ReadAll(r.Body)
		serviceBodies = append(serviceBodies, string(data))
		serviceMethods = append(serviceMethods, r.Method)
		w.WriteHeader(http.StatusOK)
	})
	defer rollback()
	_, err = p.moveContainer(addedConts[0].ID[:6], "127.0.0.1", buf)
	c.Assert(err, check.IsNil)
	containers, err := p.listContainersByHost("localhost")
	c.Assert(err, check.IsNil)
	c.Assert(containers, check.HasLen, 1)
	containers, err = p.listContainersByHost("127.0.0.1")
	c.Assert(err, check.IsNil)
	c.Assert(containers, check.HasLen, 1)
	c.Assert(serviceBodies, check.HasLen, 2)
	c.Assert(serviceMethods, check.HasLen, 2)
	c.Assert(serviceMethods[0], check.Equals, "POST")
	c.Assert(serviceBodies[0], check.Matches, ".*unit-host=127.0.0.1")
	c.Assert(serviceMethods[1], check.Equals, "DELETE")
	c.Assert(serviceBodies[1], check.Matches, ".*unit-host=localhost")
}
예제 #18
0
파일: auto_scale.go 프로젝트: tsuru/tsuru
func (a *autoScaleConfig) rebalanceIfNeeded(evt *event.Event, pool string, nodes []*cluster.Node, sResult *scalerResult) error {
	if len(sResult.ToRemove) > 0 {
		return nil
	}
	if sResult.ToAdd > 0 {
		sResult.ToRebalance = true
	}
	rebalanceFilter := map[string]string{poolMetadataName: pool}
	if !sResult.ToRebalance {
		// No action yet, check if we need rebalance
		_, gap, err := a.provisioner.containerGapInNodes(nodes)
		if err != nil {
			return errors.Wrapf(err, "unable to obtain container gap in nodes")
		}
		buf := safe.NewBuffer(nil)
		dryProvisioner, err := a.provisioner.rebalanceContainersByFilter(buf, nil, rebalanceFilter, true)
		if err != nil {
			return errors.Wrapf(err, "unable to run dry rebalance to check if rebalance is needed. log: %s", buf.String())
		}
		if dryProvisioner == nil {
			return nil
		}
		_, gapAfter, err := dryProvisioner.containerGapInNodes(nodes)
		if err != nil {
			return errors.Wrap(err, "couldn't find containers from rebalanced nodes")
		}
		if math.Abs((float64)(gap-gapAfter)) > 2.0 {
			sResult.ToRebalance = true
			if sResult.Reason == "" {
				sResult.Reason = fmt.Sprintf("gap is %d, after rebalance gap will be %d", gap, gapAfter)
			}
		}
	}
	if sResult.ToRebalance {
		evt.Logf("running rebalance, for %q: %#v", pool, sResult)
		buf := safe.NewBuffer(nil)
		writer := io.MultiWriter(buf, evt)
		_, err := a.provisioner.rebalanceContainersByFilter(writer, nil, rebalanceFilter, false)
		if err != nil {
			return errors.Wrapf(err, "unable to rebalance containers. log: %s", buf.String())
		}
	}
	return nil
}
예제 #19
0
func (s *S) TestBindAndHealthcheckForward(c *check.C) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/x/y" {
			w.WriteHeader(http.StatusOK)
		}
	}))
	defer server.Close()
	appName := "my-fake-app"
	customData := map[string]interface{}{
		"healthcheck": map[string]interface{}{
			"path":   "/x/y",
			"status": http.StatusOK,
		},
		"processes": map[string]interface{}{
			"web":    "python myapp.py",
			"worker": "python myworker.py",
		},
	}
	err := s.newFakeImage(s.p, "tsuru/app-"+appName, customData)
	c.Assert(err, check.IsNil)
	fakeApp := provisiontest.NewFakeApp(appName, "python", 0)
	s.p.Provision(fakeApp)
	defer s.p.Destroy(fakeApp)
	buf := safe.NewBuffer(nil)
	args := changeUnitsPipelineArgs{
		app:         fakeApp,
		provisioner: s.p,
		writer:      buf,
		toAdd:       map[string]*containersToAdd{"web": {Quantity: 2}, "worker": {Quantity: 1}},
		imageId:     "tsuru/app-" + appName,
	}
	containers, err := addContainersWithHost(&args)
	c.Assert(err, check.IsNil)
	c.Assert(containers, check.HasLen, 3)
	url, _ := url.Parse(server.URL)
	host, port, _ := net.SplitHostPort(url.Host)
	for i := range containers {
		if containers[i].ProcessName == "web" {
			containers[i].HostAddr = host
			containers[i].HostPort = port
		}
	}
	context := action.FWContext{Params: []interface{}{args}, Previous: containers}
	result, err := bindAndHealthcheck.Forward(context)
	c.Assert(err, check.IsNil)
	resultContainers := result.([]container.Container)
	c.Assert(resultContainers, check.DeepEquals, containers)
	u1 := containers[0].AsUnit(fakeApp)
	u2 := containers[1].AsUnit(fakeApp)
	c.Assert(fakeApp.HasBind(&u1), check.Equals, true)
	c.Assert(fakeApp.HasBind(&u2), check.Equals, true)
}
예제 #20
0
func (s *S) TestMoveContainers(c *check.C) {
	p, err := s.startMultipleServersCluster()
	c.Assert(err, check.IsNil)
	err = s.newFakeImage(p, "tsuru/app-myapp", nil)
	c.Assert(err, check.IsNil)
	appInstance := provisiontest.NewFakeApp("myapp", "python", 0)
	defer p.Destroy(appInstance)
	p.Provision(appInstance)
	coll := p.Collection()
	defer coll.Close()
	coll.Insert(container.Container{
		ID:      "container-id",
		AppName: appInstance.GetName(),
		Version: "container-version",
		Image:   "tsuru/python",
	})
	defer coll.RemoveAll(bson.M{"appname": appInstance.GetName()})
	imageId, err := image.AppCurrentImageName(appInstance.GetName())
	c.Assert(err, check.IsNil)
	_, err = addContainersWithHost(&changeUnitsPipelineArgs{
		toHost:      "localhost",
		toAdd:       map[string]*containersToAdd{"web": {Quantity: 2}},
		app:         appInstance,
		imageId:     imageId,
		provisioner: p,
	})
	c.Assert(err, check.IsNil)
	appStruct := &app.App{
		Name: appInstance.GetName(),
	}
	err = s.storage.Apps().Insert(appStruct)
	c.Assert(err, check.IsNil)
	buf := safe.NewBuffer(nil)
	err = p.MoveContainers("localhost", "127.0.0.1", buf)
	c.Assert(err, check.IsNil)
	containers, err := p.listContainersByHost("localhost")
	c.Assert(err, check.IsNil)
	c.Assert(containers, check.HasLen, 0)
	containers, err = p.listContainersByHost("127.0.0.1")
	c.Assert(err, check.IsNil)
	c.Assert(containers, check.HasLen, 2)
	parts := strings.Split(buf.String(), "\n")
	c.Assert(parts[0], check.Matches, ".*Moving 2 units.*")
	var matches int
	movingRegexp := regexp.MustCompile(`.*Moving unit.*for.*myapp.*localhost.*127.0.0.1.*`)
	for _, line := range parts[1:] {
		if movingRegexp.MatchString(line) {
			matches++
		}
	}
	c.Assert(matches, check.Equals, 2)
}
예제 #21
0
func (s *S) TestEnsureContainersStartedGracefullyStop(c *check.C) {
	config.Set("docker:bs:image", "myregistry/tsuru/bs")
	_, err := nodecontainer.InitializeBS()
	c.Assert(err, check.IsNil)
	var reqs []*http.Request
	server, err := testing.NewServer("127.0.0.1:0", nil, func(r *http.Request) {
		reqs = append(reqs, r)
	})
	c.Assert(err, check.IsNil)
	defer server.Stop()
	p, err := dockertest.NewFakeDockerProvisioner(server.URL())
	c.Assert(err, check.IsNil)
	defer p.Destroy()
	client, err := docker.NewClient(server.URL())
	c.Assert(err, check.IsNil)
	buf := safe.NewBuffer(nil)
	err = ensureContainersStarted(p, buf, true, nil)
	c.Assert(err, check.IsNil)
	var paths []string
	for _, r := range reqs {
		paths = append(paths, r.Method+" "+r.URL.Path)
	}
	c.Assert(paths, check.DeepEquals, []string{
		"POST /images/create",
		"POST /containers/create",
		"GET /version",
		"POST /containers/big-sibling/start",
	})
	reqs = nil
	err = ensureContainersStarted(p, buf, true, nil)
	c.Assert(err, check.IsNil)
	paths = nil
	for _, r := range reqs {
		paths = append(paths, r.Method+" "+r.URL.Path)
	}
	c.Assert(paths, check.DeepEquals, []string{
		"POST /images/create",
		"POST /containers/create",
		"POST /containers/big-sibling/stop",
		"DELETE /containers/big-sibling",
		"POST /containers/create",
		"GET /version",
		"POST /containers/big-sibling/start",
	})
	c.Assert(reqs[3].URL.Query().Get("force"), check.Equals, "")
	containers, err := client.ListContainers(docker.ListContainersOptions{All: true})
	c.Assert(err, check.IsNil)
	c.Assert(containers, check.HasLen, 1)
	container, err := client.InspectContainer(containers[0].ID)
	c.Assert(err, check.IsNil)
	c.Assert(container.Name, check.Equals, nodecontainer.BsDefaultName)
}
예제 #22
0
func (s *S) TestEnsureContainersStartedAlreadyPinned(c *check.C) {
	config.Set("docker:bs:image", "myregistry/tsuru/bs")
	_, err := nodecontainer.InitializeBS()
	c.Assert(err, check.IsNil)
	cont, err := nodecontainer.LoadNodeContainer("", nodecontainer.BsDefaultName)
	c.Assert(err, check.IsNil)
	cont.PinnedImage = "myregistry/tsuru/bs@" + digest
	err = nodecontainer.AddNewContainer("", cont)
	c.Assert(err, check.IsNil)
	server, err := testing.NewServer("127.0.0.1:0", nil, nil)
	c.Assert(err, check.IsNil)
	defer server.Stop()
	server.CustomHandler("/images/create", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		server.DefaultHandler().ServeHTTP(w, r)
		w.Write([]byte(pullOutputDigest))
	}))
	p, err := dockertest.NewFakeDockerProvisioner(server.URL())
	c.Assert(err, check.IsNil)
	defer p.Destroy()
	client, err := docker.NewClient(server.URL())
	c.Assert(err, check.IsNil)
	err = client.PullImage(docker.PullImageOptions{
		Repository: "base",
	}, docker.AuthConfiguration{})
	c.Assert(err, check.IsNil)
	_, err = client.CreateContainer(docker.CreateContainerOptions{
		Name:       nodecontainer.BsDefaultName,
		Config:     &docker.Config{Image: "base"},
		HostConfig: &docker.HostConfig{},
	})
	c.Assert(err, check.IsNil)
	buf := safe.NewBuffer(nil)
	err = ensureContainersStarted(p, buf, true, nil)
	c.Assert(err, check.IsNil)
	containers, err := client.ListContainers(docker.ListContainersOptions{All: true})
	c.Assert(err, check.IsNil)
	c.Assert(containers, check.HasLen, 1)
	container, err := client.InspectContainer(containers[0].ID)
	c.Assert(err, check.IsNil)
	c.Assert(container.Name, check.Equals, nodecontainer.BsDefaultName)
	c.Assert(container.Config.Image, check.Equals, "myregistry/tsuru/bs@"+digest)
	c.Assert(container.HostConfig.RestartPolicy, check.Equals, docker.AlwaysRestart())
	c.Assert(container.State.Running, check.Equals, true)
	nodeContainer, err := nodecontainer.LoadNodeContainer("", nodecontainer.BsDefaultName)
	c.Assert(err, check.IsNil)
	c.Assert(nodeContainer.PinnedImage, check.Equals, "myregistry/tsuru/bs@"+digest)
}
예제 #23
0
func (s *S) TestBindAndHealthcheckForwardHealthcheckError(c *check.C) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNotFound)
	}))
	defer server.Close()
	dbApp := &app.App{Name: "myapp"}
	err := s.storage.Apps().Insert(dbApp)
	c.Assert(err, check.IsNil)
	imageName := "tsuru/app-" + dbApp.Name
	customData := map[string]interface{}{
		"healthcheck": map[string]interface{}{
			"path":   "/x/y",
			"status": http.StatusOK,
		},
		"processes": map[string]interface{}{
			"web": "python start_app.py",
		},
	}
	err = s.newFakeImage(s.p, imageName, customData)
	c.Assert(err, check.IsNil)
	fakeApp := provisiontest.NewFakeApp(dbApp.Name, "python", 0)
	s.p.Provision(fakeApp)
	defer s.p.Destroy(fakeApp)
	buf := safe.NewBuffer(nil)
	args := changeUnitsPipelineArgs{
		app:         fakeApp,
		provisioner: s.p,
		writer:      buf,
		toAdd:       map[string]*containersToAdd{"web": {Quantity: 2}},
		imageId:     "tsuru/app-" + dbApp.Name,
	}
	containers, err := addContainersWithHost(&args)
	c.Assert(err, check.IsNil)
	c.Assert(containers, check.HasLen, 2)
	url, _ := url.Parse(server.URL)
	host, port, _ := net.SplitHostPort(url.Host)
	containers[0].HostAddr = host
	containers[0].HostPort = port
	containers[1].HostAddr = host
	containers[1].HostPort = port
	context := action.FWContext{Params: []interface{}{args}, Previous: containers}
	_, err = bindAndHealthcheck.Forward(context)
	c.Assert(err, check.ErrorMatches, `healthcheck fail\(.*?\): wrong status code, expected 200, got: 404`)
	u1 := containers[0].AsUnit(fakeApp)
	u2 := containers[1].AsUnit(fakeApp)
	c.Assert(fakeApp.HasBind(&u1), check.Equals, false)
	c.Assert(fakeApp.HasBind(&u2), check.Equals, false)
}
예제 #24
0
파일: event_test.go 프로젝트: tsuru/tsuru
func (s *S) TestEventDoneLogError(c *check.C) {
	logBuf := safe.NewBuffer(nil)
	log.SetLogger(log.NewWriterLogger(logBuf, false))
	defer log.SetLogger(nil)
	evt, err := New(&Opts{
		Target:  Target{Type: "app", Value: "myapp"},
		Kind:    permission.PermAppUpdateEnvSet,
		Owner:   s.token,
		Allowed: Allowed(permission.PermAppReadEvents),
	})
	c.Assert(err, check.IsNil)
	config.Set("database:url", "127.0.0.1:99999")
	err = evt.Done(nil)
	c.Assert(err, check.ErrorMatches, "no reachable servers")
	c.Assert(logBuf.String(), check.Matches, `(?s).*\[events\] error marking event as done - .*: no reachable servers.*`)
}
예제 #25
0
func (s *S) TestBindAndHealthcheckForwardRestartError(c *check.C) {
	s.server.CustomHandler("/exec/.*/json", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		w.Write([]byte(`{"ID":"id","ExitCode":9}`))
	}))
	conn, err := db.Conn()
	c.Assert(err, check.IsNil)
	defer conn.Close()
	dbApp := &app.App{Name: "myapp"}
	err = conn.Apps().Insert(dbApp)
	c.Assert(err, check.IsNil)
	defer conn.Apps().Remove(bson.M{"name": dbApp.Name})
	imageName := "tsuru/app-" + dbApp.Name
	customData := map[string]interface{}{
		"hooks": map[string]interface{}{
			"restart": map[string]interface{}{
				"after": []string{"will fail"},
			},
		},
		"procfile": "web: python myapp.py",
	}
	err = s.newFakeImage(s.p, imageName, customData)
	c.Assert(err, check.IsNil)
	fakeApp := provisiontest.NewFakeApp(dbApp.Name, "python", 0)
	s.p.Provision(fakeApp)
	defer s.p.Destroy(fakeApp)
	buf := safe.NewBuffer(nil)
	args := changeUnitsPipelineArgs{
		app:         fakeApp,
		provisioner: s.p,
		writer:      buf,
		toAdd:       map[string]*containersToAdd{"web": {Quantity: 2}},
		imageId:     "tsuru/app-" + dbApp.Name,
	}
	containers, err := addContainersWithHost(&args)
	c.Assert(err, check.IsNil)
	c.Assert(containers, check.HasLen, 2)
	context := action.FWContext{Params: []interface{}{args}, Previous: containers}
	_, err = bindAndHealthcheck.Forward(context)
	c.Assert(err, check.ErrorMatches, `couldn't execute restart:after hook "will fail"\(.+?\): unexpected exit code: 9`)
	u1 := containers[0].asUnit(fakeApp)
	u2 := containers[1].asUnit(fakeApp)
	c.Assert(fakeApp.HasBind(&u1), check.Equals, false)
	c.Assert(fakeApp.HasBind(&u2), check.Equals, false)
}
예제 #26
0
func (a *autoScaleConfig) removeMultipleNodes(event *autoScaleEvent, chosenNodes []cluster.Node) error {
	nodeAddrs := make([]string, len(chosenNodes))
	nodeHosts := make([]string, len(chosenNodes))
	for i, node := range chosenNodes {
		_, hasIaas := node.Metadata["iaas"]
		if !hasIaas {
			return fmt.Errorf("no IaaS information in node (%s) metadata: %#v", node.Address, node.Metadata)
		}
		nodeAddrs[i] = node.Address
		nodeHosts[i] = urlToHost(node.Address)
	}
	err := a.provisioner.Cluster().UnregisterNodes(nodeAddrs...)
	if err != nil {
		return fmt.Errorf("unable to unregister nodes (%s) for removal: %s", strings.Join(nodeAddrs, ", "), err)
	}
	buf := safe.NewBuffer(nil)
	err = a.provisioner.moveContainersFromHosts(nodeHosts, "", buf)
	if err != nil {
		for _, node := range chosenNodes {
			a.provisioner.Cluster().Register(node)
		}
		return fmt.Errorf("unable to move containers from nodes (%s): %s - log: %s", strings.Join(nodeAddrs, ", "), err, buf.String())
	}
	wg := sync.WaitGroup{}
	for i := range chosenNodes {
		wg.Add(1)
		go func(i int) {
			defer wg.Done()
			node := chosenNodes[i]
			m, err := iaas.FindMachineByIdOrAddress(node.Metadata["iaas-id"], urlToHost(node.Address))
			if err != nil {
				event.logMsg("unable to find machine for removal in iaas: %s", err)
				return
			}
			err = m.Destroy()
			if err != nil {
				event.logMsg("unable to destroy machine in IaaS: %s", err)
			}
		}(i)
	}
	wg.Wait()
	return nil
}
예제 #27
0
func (s *S) TestEnsureContainersStartedPinImgInChild(c *check.C) {
	err := nodecontainer.AddNewContainer("", &nodecontainer.NodeContainerConfig{
		Name: "c1",
		Config: docker.Config{
			Image: "myrootimg",
		},
	})
	c.Assert(err, check.IsNil)
	err = nodecontainer.AddNewContainer("p1", &nodecontainer.NodeContainerConfig{
		Name: "c1",
		Config: docker.Config{
			Image: "myregistry/tsuru/bs",
		},
	})
	c.Assert(err, check.IsNil)
	server, err := testing.NewServer("127.0.0.1:0", nil, nil)
	c.Assert(err, check.IsNil)
	defer server.Stop()
	server.CustomHandler("/images/create", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		server.DefaultHandler().ServeHTTP(w, r)
		w.Write([]byte(pullOutputDigest))
	}))
	p, err := dockertest.NewFakeDockerProvisioner(server.URL())
	c.Assert(err, check.IsNil)
	defer p.Destroy()
	node, err := p.Cluster().GetNode(server.URL())
	c.Assert(err, check.IsNil)
	node.Metadata["pool"] = "p1"
	_, err = p.Cluster().UpdateNode(node)
	c.Assert(err, check.IsNil)
	buf := safe.NewBuffer(nil)
	err = ensureContainersStarted(p, buf, true, nil)
	c.Assert(err, check.IsNil)
	all, err := nodecontainer.LoadNodeContainersForPoolsMerge("c1", false)
	c.Assert(err, check.IsNil)
	c.Assert(all, check.DeepEquals, map[string]nodecontainer.NodeContainerConfig{
		"":   {Name: "c1", PinnedImage: "", Config: docker.Config{Image: "myrootimg"}},
		"p1": {Name: "c1", PinnedImage: "myregistry/tsuru/bs@" + digest, Config: docker.Config{Image: "myregistry/tsuru/bs"}},
	})
}
func (s *S) TestDeploy(c *gocheck.C) {
	h := &tsrTesting.TestHandler{}
	gandalfServer := tsrTesting.StartGandalfTestServer(h)
	defer gandalfServer.Close()
	go s.stopContainers(1)
	err := newImage("tsuru/python", s.server.URL())
	c.Assert(err, gocheck.IsNil)
	setExecut(&etesting.FakeExecutor{})
	defer setExecut(nil)
	p := dockerProvisioner{}
	a := app.App{
		Name:     "otherapp",
		Platform: "python",
	}
	conn, err := db.Conn()
	defer conn.Close()
	err = conn.Apps().Insert(a)
	c.Assert(err, gocheck.IsNil)
	defer conn.Apps().Remove(bson.M{"name": a.Name})
	p.Provision(&a)
	defer p.Destroy(&a)
	w := safe.NewBuffer(make([]byte, 2048))
	var serviceBodies []string
	rollback := s.addServiceInstance(c, a.Name, func(w http.ResponseWriter, r *http.Request) {
		data, _ := ioutil.ReadAll(r.Body)
		serviceBodies = append(serviceBodies, string(data))
		w.WriteHeader(http.StatusOK)
	})
	defer rollback()
	err = app.Deploy(app.DeployOptions{
		App:          &a,
		Version:      "master",
		Commit:       "123",
		OutputStream: w,
	})
	c.Assert(err, gocheck.IsNil)
	units := a.Units()
	c.Assert(units, gocheck.HasLen, 1)
	c.Assert(serviceBodies, gocheck.HasLen, 1)
	c.Assert(serviceBodies[0], gocheck.Matches, ".*unit-host="+units[0].Ip)
}
예제 #29
0
func (s *S) TestDeployEnqueuesBindService(c *gocheck.C) {
	h := &tsrTesting.TestHandler{}
	gandalfServer := tsrTesting.StartGandalfTestServer(h)
	defer gandalfServer.Close()
	go s.stopContainers(1)
	err := newImage("tsuru/python", s.server.URL())
	c.Assert(err, gocheck.IsNil)
	setExecut(&etesting.FakeExecutor{})
	defer setExecut(nil)
	p := dockerProvisioner{}
	app.Provisioner = &p
	a := app.App{
		Name:     "otherapp",
		Platform: "python",
	}
	conn, err := db.Conn()
	defer conn.Close()
	err = conn.Apps().Insert(a)
	c.Assert(err, gocheck.IsNil)
	defer conn.Apps().Remove(bson.M{"name": a.Name})
	p.Provision(&a)
	defer p.Destroy(&a)
	w := safe.NewBuffer(make([]byte, 2048))
	err = app.Deploy(app.DeployOptions{
		App:          &a,
		Version:      "master",
		Commit:       "123",
		OutputStream: w,
	})
	c.Assert(err, gocheck.IsNil)
	defer p.Destroy(&a)
	q, err := getQueue()
	c.Assert(err, gocheck.IsNil)
	for _, u := range a.Units() {
		message, err := q.Get(1e6)
		c.Assert(err, gocheck.IsNil)
		c.Assert(message.Action, gocheck.Equals, app.BindService)
		c.Assert(message.Args[0], gocheck.Equals, a.GetName())
		c.Assert(message.Args[1], gocheck.Equals, u.Name)
	}
}
예제 #30
0
func (s *S) TestFollowLogsAndCommitForwardNonZeroStatus(c *check.C) {
	err := s.newFakeImage(s.p, "tsuru/python", nil)
	c.Assert(err, check.IsNil)
	app := provisiontest.NewFakeApp("myapp", "python", 1)
	cont := container.Container{AppName: "mightyapp"}
	err = cont.Create(&container.CreateArgs{
		App:         app,
		ImageID:     "tsuru/python",
		Commands:    []string{"foo"},
		Provisioner: s.p,
	})
	c.Assert(err, check.IsNil)
	err = s.server.MutateContainer(cont.ID, docker.State{ExitCode: 1})
	c.Assert(err, check.IsNil)
	buf := safe.NewBuffer(nil)
	args := runContainerActionsArgs{writer: buf, provisioner: s.p}
	context := action.FWContext{Params: []interface{}{args}, Previous: cont}
	imageId, err := followLogsAndCommit.Forward(context)
	c.Assert(err, check.NotNil)
	c.Assert(err.Error(), check.Equals, "Exit status 1")
	c.Assert(imageId, check.IsNil)
}