// 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) }
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 }
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", }, }, }) }
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) }
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...) }
func (s *S) TestLoadNodeContainersForPoolsNotFound(c *check.C) { _, err := nodecontainer.LoadNodeContainersForPools("notfound") c.Assert(err, check.Equals, nodecontainer.ErrNodeContainerNotFound) }
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 }