Example #1
0
// title: node container info
// path: /docker/nodecontainers/{name}
// method: GET
// produce: application/json
// responses:
//   200: Ok
//   401: Unauthorized
//   404: Not found
func nodeContainerInfo(w http.ResponseWriter, r *http.Request, t auth.Token) error {
	pools, err := permission.ListContextValues(t, permission.PermNodecontainerRead, true)
	if err != nil {
		return err
	}
	name := r.URL.Query().Get(":name")
	configMap, err := nodecontainer.LoadNodeContainersForPools(name)
	if err != nil {
		if err == nodecontainer.ErrNodeContainerNotFound {
			return &tsuruErrors.HTTP{
				Code:    http.StatusNotFound,
				Message: err.Error(),
			}
		}
		return err
	}
	if pools != nil {
		poolMap := map[string]struct{}{}
		for _, p := range pools {
			poolMap[p] = struct{}{}
		}
		for poolName := range configMap {
			if poolName == "" {
				continue
			}
			if _, ok := poolMap[poolName]; !ok {
				delete(configMap, poolName)
			}
		}
	}
	w.Header().Set("Content-Type", "application/json")
	return json.NewEncoder(w).Encode(configMap)
}
Example #2
0
func (p *swarmProvisioner) ensureNodeContainersCreated() error {
	names, err := nodecontainer.AllNodeContainersNames()
	if err != nil {
		return errors.WithStack(err)
	}
	for _, n := range names {
		poolMap, err := nodecontainer.LoadNodeContainersForPools(n)
		if err != nil {
			return errors.WithStack(err)
		}
		for pool := range poolMap {
			err = p.UpgradeNodeContainer(n, pool, ioutil.Discard)
			if err != nil {
				return err
			}
		}
	}
	return nil
}
Example #3
0
func (s *S) TestLoadNodeContainersForPools(c *check.C) {
	err := nodecontainer.AddNewContainer("p1", &nodecontainer.NodeContainerConfig{
		Name: "c1",
		Config: docker.Config{
			Image: "myregistry/tsuru/bs",
		},
	})
	c.Assert(err, check.IsNil)
	result, err := nodecontainer.LoadNodeContainersForPools("c1")
	c.Assert(err, check.IsNil)
	c.Assert(result, check.DeepEquals, map[string]nodecontainer.NodeContainerConfig{
		"p1": {
			Name: "c1",
			Config: docker.Config{
				Image: "myregistry/tsuru/bs",
			},
		},
	})
}
Example #4
0
func (s *S) TestMigrateBSEnvs(c *check.C) {
	conn, err := db.Conn()
	c.Assert(err, check.IsNil)
	defer conn.Close()
	entries, err := nodecontainer.LoadNodeContainersForPools(nodecontainer.BsDefaultName)
	c.Assert(err, check.Equals, nodecontainer.ErrNodeContainerNotFound)
	c.Assert(entries, check.DeepEquals, map[string]nodecontainer.NodeContainerConfig(nil))
	coll := conn.Collection("bsconfig")
	err = coll.Insert(bson.M{
		"_id":   "bs",
		"image": "tsuru/bs@shacabum",
		"token": "999",
		"envs": []bson.M{
			{"name": "FOO", "value": "1"},
		},
		"pools": []bson.M{},
	})
	c.Assert(err, check.IsNil)
	err = migrateBSEnvs()
	c.Assert(err, check.IsNil)
	entries, err = nodecontainer.LoadNodeContainersForPools(nodecontainer.BsDefaultName)
	c.Assert(err, check.IsNil)
	defaultEntry := entries[""]
	c.Assert(defaultEntry.Config.Env, check.HasLen, 5)
	c.Assert(defaultEntry.Config.Env[0], check.Matches, `TSURU_TOKEN=\w{40}`)
	defaultEntry.Config.Env = defaultEntry.Config.Env[1:]
	entries[""] = defaultEntry
	expected := map[string]nodecontainer.NodeContainerConfig{
		"": {Name: "big-sibling", PinnedImage: "tsuru/bs@shacabum", Config: docker.Config{
			Image: "tsuru/bs:v1",
			Env: []string{
				"TSURU_ENDPOINT=http://tsuru.server:8080/",
				"HOST_PROC=/prochost",
				"SYSLOG_LISTEN_ADDRESS=udp://0.0.0.0:1514",
				"FOO=1",
			},
		}, HostConfig: docker.HostConfig{
			RestartPolicy: docker.AlwaysRestart(),
			Privileged:    true,
			NetworkMode:   "host",
			Binds:         []string{"/proc:/prochost:ro"},
		}},
	}
	c.Assert(entries, check.DeepEquals, expected)
	err = coll.UpdateId("bs", bson.M{
		"$set": bson.M{"pools": []bson.M{
			{"name": "p1", "envs": []bson.M{{"name": "A", "value": "x"}}},
			{"name": "p2", "envs": []bson.M{{"name": "A", "value": "y"}}},
			{"name": "p3", "envs": []bson.M{{"name": "B", "value": "z"}, {"name": "FOO", "value": "2"}}},
		}},
	})
	c.Assert(err, check.IsNil)
	err = migrateBSEnvs()
	c.Assert(err, check.IsNil)
	entries, err = nodecontainer.LoadNodeContainersForPoolsMerge(nodecontainer.BsDefaultName, true)
	c.Assert(err, check.IsNil)
	for k, v := range entries {
		v.Config.Env = v.Config.Env[1:]
		entries[k] = v
	}
	expectedBase := expected[""]
	expectedP1 := expectedBase
	expectedP2 := expectedBase
	expectedP3 := expectedBase
	expectedBase.Config.Env = append(expectedBase.Config.Env, "FOO=1")
	baseEnvs := append([]string{}, expectedBase.Config.Env...)
	expectedP1.Config.Env = append(baseEnvs, "A=x")
	expectedP2.Config.Env = append(baseEnvs, "A=y")
	expectedP3.Config.Env = append(baseEnvs, "B=z", "FOO=2")
	c.Assert(entries[""], check.DeepEquals, expectedBase)
	c.Assert(entries["p1"], check.DeepEquals, expectedP1)
	c.Assert(entries["p2"], check.DeepEquals, expectedP2)
	c.Assert(entries["p3"], check.DeepEquals, expectedP3)
}
Example #5
0
func (p *swarmProvisioner) UpgradeNodeContainer(name string, pool string, writer io.Writer) error {
	client, err := chooseDBSwarmNode()
	if err != nil {
		if errors.Cause(err) == errNoSwarmNode {
			return nil
		}
		return err
	}
	poolsToRun := []string{pool}
	if pool == "" {
		poolMap, errLoad := nodecontainer.LoadNodeContainersForPools(name)
		if errLoad != nil {
			return errors.WithStack(errLoad)
		}
		poolsToRun = make([]string, len(poolMap))
		i := 0
		for k, v := range poolMap {
			if !v.Valid() {
				continue
			}
			if k == "" {
				poolsToRun[len(poolMap)-1] = k
				continue
			}
			poolsToRun[i] = k
			i++
		}
	}
	var allErrors []error
	created := false
	for _, v := range poolsToRun {
		serviceSpec, errUpsert := serviceSpecForNodeContainer(name, v)
		if errUpsert != nil {
			errUpsert = errors.Wrapf(errUpsert, "[node containers] failed retrieve service spec for node container %q [%s]", name, v)
			allErrors = append(allErrors, errUpsert)
		}
		log.Debugf("[node containers] upserting service %q for node container %s [%s]", serviceSpec.Name, name, v)
		fmt.Fprintf(writer, "upserting service %q for node container %q [%s]\n", serviceSpec.Name, name, v)
		errUpsert, created = upsertService(serviceSpec, client)
		if errUpsert != nil {
			errUpsert = errors.Wrapf(errUpsert, "[node containers] failed upsert service %q for node container %q [%s]", serviceSpec.Name, name, v)
			allErrors = append(allErrors, errUpsert)
		}
	}
	if pool != "" && created {
		serviceName := nodeContainerServiceName(name, "")
		baseSpec, err := client.InspectService(serviceName)
		if err != nil {
			if _, ok := err.(*docker.NoSuchService); ok {
				return nil
			}
			err = errors.Wrapf(err, "[node containers] failed inspect base service %q for node container %q", serviceName, name)
			allErrors = append(allErrors, err)
		}
		newBaseSpec, err := serviceSpecForNodeContainer(name, "")
		if err != nil {
			err = errors.Wrapf(err, "[node containers] failed retrieve base service spec %q for node container %q", serviceName, name)
			allErrors = append(allErrors, err)
		}
		baseSpec.Spec.TaskTemplate.Placement = newBaseSpec.TaskTemplate.Placement
		log.Debugf("[node containers] updating base service %q for node container %s constraints", serviceName, name)
		fmt.Fprintf(writer, "updating base service %q for node container %s constraints\n", serviceName, name)
		err, _ = upsertService(&baseSpec.Spec, client)
		if err != nil {
			err = errors.Wrapf(err, "[node containers] failed update base service %q for node container %q", serviceName, name)
			allErrors = append(allErrors, err)
		}
	}
	if len(allErrors) == 0 {
		return nil
	}
	return tsuruErrors.NewMultiError(allErrors...)
}
Example #6
0
func (s *S) TestLoadNodeContainersForPoolsNotFound(c *check.C) {
	_, err := nodecontainer.LoadNodeContainersForPools("notfound")
	c.Assert(err, check.Equals, nodecontainer.ErrNodeContainerNotFound)
}
Example #7
0
func serviceSpecForNodeContainer(name, pool string) (*swarm.ServiceSpec, error) {
	config, err := nodecontainer.LoadNodeContainer(pool, name)
	if err != nil {
		return nil, errors.WithStack(err)
	}
	var constraints []string
	if pool == "" {
		otherConfigs, err := nodecontainer.LoadNodeContainersForPools(name)
		if err != nil {
			return nil, errors.WithStack(err)
		}
		for p := range otherConfigs {
			if p != "" {
				constraints = append(constraints, fmt.Sprintf("node.labels.%s != %s", labelNodePoolName, p))
			}
		}
	} else {
		constraints = []string{fmt.Sprintf("node.labels.%s == %s", labelNodePoolName, pool)}
	}
	var mounts []mount.Mount
	for _, b := range config.HostConfig.Binds {
		parts := strings.SplitN(b, ":", 3)
		mounts = append(mounts, mount.Mount{
			Type:     mount.TypeBind,
			Source:   parts[0],
			Target:   parts[1],
			ReadOnly: parts[2] == "ro",
		})
	}
	var healthcheck *container.HealthConfig
	if config.Config.Healthcheck != nil {
		healthcheck = &container.HealthConfig{
			Test:     config.Config.Healthcheck.Test,
			Interval: config.Config.Healthcheck.Interval,
			Timeout:  config.Config.Healthcheck.Timeout,
			Retries:  config.Config.Healthcheck.Retries,
		}
	}
	labels := config.Config.Labels
	if labels == nil {
		labels = make(map[string]string)
	}
	labels[labelNodeContainer.String()] = strconv.FormatBool(true)
	labels[labelNodeContainerName.String()] = name
	labels[labelPoolName.String()] = pool
	labels[labelProvisionerName.String()] = "swarm"
	service := &swarm.ServiceSpec{
		Annotations: swarm.Annotations{
			Name:   nodeContainerServiceName(name, pool),
			Labels: labels,
		},
		Mode: swarm.ServiceMode{Global: &swarm.GlobalService{}},
		TaskTemplate: swarm.TaskSpec{
			ContainerSpec: swarm.ContainerSpec{
				Image:       config.Image(),
				Labels:      labels,
				Command:     config.Config.Cmd,
				Env:         config.Config.Env,
				Dir:         config.Config.WorkingDir,
				User:        config.Config.User,
				TTY:         config.Config.Tty,
				Mounts:      mounts,
				Healthcheck: healthcheck,
			},
			Placement: &swarm.Placement{Constraints: constraints},
		},
	}
	return service, nil
}