Beispiel #1
0
func (r *RedisBackend) ListRegistrations(env string) ([]ServiceRegistration, error) {
	keys, err := r.Keys(path.Join(env, "*", "hosts", "*", "*", "*"))
	if err != nil {
		return nil, err
	}

	var regList []ServiceRegistration
	for _, key := range keys {

		val, err := r.Get(key, "location")
		if err != nil {
			log.Warnf("WARN: Unable to get location for %s: %s", key, err)
			continue
		}

		svcReg := ServiceRegistration{
			Name: path.Base(key),
		}
		err = json.Unmarshal([]byte(val), &svcReg)
		if err != nil {
			log.Warnf("WARN: Unable to unmarshal JSON for %s: %s", key, err)
			continue
		}

		svcReg.Path = key

		regList = append(regList, svcReg)
	}

	return regList, nil
}
Beispiel #2
0
func (s *ServiceRuntime) instanceIds(app, versionId string) ([]int, error) {
	containers, err := s.ManagedContainers()
	if err != nil {
		return []int{}, err
	}

	instances := []int{}
	for _, c := range containers {
		ga := s.EnvFor(c)["GALAXY_APP"]

		if ga != app {
			continue
		}

		gi := s.EnvFor(c)["GALAXY_INSTANCE"]
		gv := s.EnvFor(c)["GALAXY_VERSION"]
		if gi != "" {
			i, err := strconv.ParseInt(gi, 10, 64)
			if err != nil {
				log.Warnf("WARN: Invalid number %s for %s. Ignoring.", gi, c.ID[:12])
				continue
			}

			if versionId != "" && gv != versionId {
				continue
			}
			instances = append(instances, int(i))
		}
	}
	return instances, nil
}
Beispiel #3
0
func AppAssign(configStore *config.Store, app, env, pool string) error {
	// Don't allow deleting runtime hosts entries
	if app == "hosts" || app == "pools" {
		return fmt.Errorf("invalid app name: %s", app)
	}

	exists, err := configStore.PoolExists(env, pool)
	if err != nil {
		return err
	}

	if !exists {
		log.Warnf("WARN: Pool %s does not exist.", pool)
	}

	created, err := configStore.AssignApp(app, env, pool)

	if err != nil {
		return err
	}

	if created {
		log.Printf("Assigned %s in env %s to pool %s.\n", app, env, pool)
	} else {
		log.Printf("%s already assigned to pool %s in env %s.\n", app, pool, env)
	}
	return nil
}
Beispiel #4
0
func ConfigUnset(configStore *config.Store, app, env string, envVars []string) error {

	if len(envVars) == 0 {
		return fmt.Errorf("no config values specified.")
	}

	svcCfg, err := configStore.GetApp(app, env)
	if err != nil {
		return fmt.Errorf("unable to unset config: %s.", err)
	}

	updated := false
	for _, arg := range envVars {
		k := strings.ToUpper(strings.TrimSpace(arg))
		if k == "ENV" || svcCfg.EnvGet(k) == "" {
			log.Warnf("%s cannot be unset.", k)
			continue
		}

		log.Printf("%s\n", k)
		svcCfg.EnvSet(strings.ToUpper(arg), "")
		updated = true
	}

	if !updated {
		return fmt.Errorf("Configuration NOT changed for %s", app)
	}

	updated, err = configStore.UpdateApp(svcCfg, env)
	if err != nil {
		return fmt.Errorf("ERROR: Unable to unset config: %s.", err)

	}

	if !updated {
		return fmt.Errorf("Configuration NOT changed for %s", app)

	}
	log.Printf("Configuration changed for %s. v%d.\n", app, svcCfg.ID())
	return nil
}
Beispiel #5
0
// Stop any running galaxy containers that are not assigned to us
// TODO: We call ManagedContainers a lot, repeatedly listing and inspecting all containers.
func (s *ServiceRuntime) StopUnassigned(env, pool string) error {
	containers, err := s.ManagedContainers()
	if err != nil {
		return err
	}

	for _, container := range containers {
		name := s.EnvFor(container)["GALAXY_APP"]

		pools, err := s.configStore.ListAssignedPools(env, name)
		if err != nil {
			log.Errorf("ERROR: Unable to list pool assignments for %s: %s", container.Name, err)
			continue
		}

		if len(pools) == 0 || !utils.StringInSlice(pool, pools) {
			log.Warnf("galaxy container %s not assigned to %s/%s", container.Name, env, pool)
			s.stopContainer(container)
		}
	}
	return nil
}
Beispiel #6
0
func (c *ConsulBackend) ListRegistrations(env string) ([]ServiceRegistration, error) {
	prefix := path.Join("galaxy", "services", env)

	kvPairs, _, err := c.client.KV().List(prefix, nil)
	if err != nil {
		return nil, err
	}

	regList := []ServiceRegistration{}
	for _, kvp := range kvPairs {
		svcReg := ServiceRegistration{
			Name: path.Base(kvp.Key),
		}
		err = json.Unmarshal(kvp.Value, &svcReg)
		if err != nil {
			log.Warnf("WARN: Unable to unmarshal JSON for %s: %s", kvp.Key, err)
			continue
		}

		regList = append(regList, svcReg)
	}

	return regList, nil
}
Beispiel #7
0
func (s *ServiceRuntime) Start(env, pool string, appCfg config.App) (*docker.Container, error) {

	img := appCfg.Version()

	imgIdRef := appCfg.Version()
	if appCfg.VersionID() != "" {
		imgIdRef = appCfg.VersionID()
	}
	// see if we have the image locally
	image, err := s.PullImage(img, imgIdRef)
	if err != nil {
		return nil, err
	}

	// setup env vars from etcd
	var envVars []string
	envVars = append(envVars, "ENV"+"="+env)

	for key, value := range appCfg.Env() {
		if key == "ENV" {
			continue
		}
		envVars = append(envVars, strings.ToUpper(key)+"="+s.replaceVarEnv(value, s.hostIP))
	}

	instanceId, err := s.NextInstanceSlot(appCfg.Name(), strconv.FormatInt(appCfg.ID(), 10))
	if err != nil {
		return nil, err
	}

	envVars = append(envVars, fmt.Sprintf("HOST_IP=%s", s.hostIP))
	envVars = append(envVars, fmt.Sprintf("GALAXY_APP=%s", appCfg.Name()))
	envVars = append(envVars, fmt.Sprintf("GALAXY_VERSION=%s", strconv.FormatInt(appCfg.ID(), 10)))
	envVars = append(envVars, fmt.Sprintf("GALAXY_INSTANCE=%s", strconv.FormatInt(int64(instanceId), 10)))

	publicDns, err := EC2PublicHostname()
	if err != nil {
		log.Warnf("Unable to determine public hostname. Not on AWS? %s", err)
		publicDns = "127.0.0.1"
	}
	envVars = append(envVars, fmt.Sprintf("PUBLIC_HOSTNAME=%s", publicDns))

	containerName := appCfg.ContainerName() + "." + strconv.FormatInt(int64(instanceId), 10)
	container, err := s.dockerClient.InspectContainer(containerName)
	_, ok := err.(*docker.NoSuchContainer)
	if err != nil && !ok {
		return nil, err
	}

	// Existing container is running or stopped.  If the image has changed, stop
	// and re-create it.
	if container != nil && container.Image != image.ID {
		if container.State.Running || container.State.Restarting || container.State.Paused {
			log.Printf("Stopping %s version %s running as %s", appCfg.Name(), appCfg.Version(), container.ID[0:12])
			err := s.dockerClient.StopContainer(container.ID, 10)
			if err != nil {
				return nil, err
			}
		}

		log.Printf("Removing %s version %s running as %s", appCfg.Name(), appCfg.Version(), container.ID[0:12])
		err = s.dockerClient.RemoveContainer(docker.RemoveContainerOptions{
			ID: container.ID,
		})
		if err != nil {
			return nil, err
		}
		container = nil
	}

	if container == nil {

		config := &docker.Config{
			Image: img,
			Env:   envVars,
		}

		mem := appCfg.GetMemory(pool)
		if mem != "" {
			m, err := utils.ParseMemory(mem)
			if err != nil {
				return nil, err
			}
			config.Memory = m
		}

		cpu := appCfg.GetCPUShares(pool)
		if cpu != "" {
			if c, err := strconv.Atoi(cpu); err == nil {
				config.CPUShares = int64(c)
			}
		}

		log.Printf("Creating %s version %s", appCfg.Name(), appCfg.Version())
		container, err = s.dockerClient.CreateContainer(docker.CreateContainerOptions{
			Name:   containerName,
			Config: config,
		})
		if err != nil {
			return nil, err
		}
	}

	log.Printf("Starting %s version %s running as %s", appCfg.Name(), appCfg.Version(), container.ID[0:12])

	config := &docker.HostConfig{
		PublishAllPorts: true,
		RestartPolicy: docker.RestartPolicy{
			Name:              "on-failure",
			MaximumRetryCount: 16,
		},
	}

	if s.dns != "" {
		config.DNS = []string{s.dns}
	}
	err = s.dockerClient.StartContainer(container.ID, config)

	return container, err
}
Beispiel #8
0
func (s *ServiceRuntime) StartInteractive(env, pool string, appCfg config.App) error {

	// see if we have the image locally
	fmt.Fprintf(os.Stderr, "Pulling latest image for %s\n", appCfg.Version())
	_, err := s.PullImage(appCfg.Version(), appCfg.VersionID())
	if err != nil {
		return err
	}

	args := []string{
		"run", "--rm", "-i",
	}
	args = append(args, "-e")
	args = append(args, "ENV"+"="+env)

	for key, value := range appCfg.Env() {
		if key == "ENV" {
			continue
		}

		args = append(args, "-e")
		args = append(args, strings.ToUpper(key)+"="+s.replaceVarEnv(value, s.hostIP))
	}

	args = append(args, "-e")
	args = append(args, fmt.Sprintf("HOST_IP=%s", s.hostIP))
	if s.dns != "" {
		args = append(args, "--dns")
		args = append(args, s.dns)
	}
	args = append(args, "-e")
	args = append(args, fmt.Sprintf("GALAXY_APP=%s", appCfg.Name()))
	args = append(args, "-e")
	args = append(args, fmt.Sprintf("GALAXY_VERSION=%s", strconv.FormatInt(appCfg.ID(), 10)))

	instanceId, err := s.NextInstanceSlot(appCfg.Name(), strconv.FormatInt(appCfg.ID(), 10))
	if err != nil {
		return err
	}
	args = append(args, "-e")
	args = append(args, fmt.Sprintf("GALAXY_INSTANCE=%s", strconv.FormatInt(int64(instanceId), 10)))

	publicDns, err := EC2PublicHostname()
	if err != nil {
		log.Warnf("Unable to determine public hostname. Not on AWS? %s", err)
		publicDns = "127.0.0.1"
	}

	args = append(args, "-e")
	args = append(args, fmt.Sprintf("PUBLIC_HOSTNAME=%s", publicDns))

	mem := appCfg.GetMemory(pool)
	if mem != "" {
		args = append(args, "-m")
		args = append(args, mem)
	}

	cpu := appCfg.GetCPUShares(pool)
	if cpu != "" {
		args = append(args, "-c")
		args = append(args, cpu)
	}

	args = append(args, []string{"-t", appCfg.Version(), "/bin/bash"}...)
	// shell out to docker run to get signal forwarded and terminal setup correctly
	//cmd := exec.Command("docker", "run", "-rm", "-i", "-t", appCfg.Version(), "/bin/bash")
	cmd := exec.Command("docker", args...)

	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err = cmd.Start()
	if err != nil {
		log.Fatal(err)
	}

	err = cmd.Wait()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Command finished with error: %v\n", err)
	}

	return err
}
Beispiel #9
0
func ConfigSet(configStore *config.Store, app, env string, envVars []string) error {

	if len(envVars) == 0 {
		bytes, err := ioutil.ReadAll(os.Stdin)
		if err != nil {
			return err

		}
		envVars = strings.Split(string(bytes), "\n")
	}

	if len(envVars) == 0 {
		return fmt.Errorf("no config values specified.")
	}

	svcCfg, err := configStore.GetApp(app, env)
	if err != nil {
		return fmt.Errorf("unable to set config: %s.", err)
	}

	if svcCfg == nil {
		svcCfg = configStore.NewAppConfig(app, "")
	}

	updated := false
	for _, arg := range envVars {

		if strings.TrimSpace(arg) == "" {
			continue
		}

		if !strings.Contains(arg, "=") {
			return fmt.Errorf("bad config variable format: %s", arg)
		}

		sep := strings.Index(arg, "=")
		k := strings.ToUpper(strings.TrimSpace(arg[0:sep]))
		v := strings.TrimSpace(arg[sep+1:])
		if k == "ENV" {
			log.Warnf("%s cannot be updated.", k)
			continue
		}

		log.Printf("%s=%s\n", k, v)
		svcCfg.EnvSet(k, v)
		updated = true
	}

	if !updated {
		return fmt.Errorf("configuration NOT changed for %s", app)
	}

	updated, err = configStore.UpdateApp(svcCfg, env)
	if err != nil {
		return fmt.Errorf("unable to set config: %s.", err)
	}

	if !updated {
		return fmt.Errorf("configuration NOT changed for %s", app)
	}
	log.Printf("Configuration changed for %s. v%d\n", app, svcCfg.ID())
	return nil
}
Beispiel #10
0
// restore an app's config from backup
func appRestore(c *cli.Context) {
	initStore(c)

	var err error
	var rawBackup []byte

	fileName := c.String("file")
	if fileName != "" {
		rawBackup, err = ioutil.ReadFile(fileName)
		if err != nil {
			log.Fatal(err)
		}
	} else {
		log.Println("Reading backup from STDIN")
		rawBackup, err = ioutil.ReadAll(os.Stdin)
		if err != nil {
			log.Fatal(err)
		}
	}

	backup := &backupData{}
	if err := json.Unmarshal(rawBackup, backup); err != nil {
		log.Fatal(err)
	}

	fmt.Println("Found backup from ", backup.Time)

	var toRestore []*appCfg

	if apps := c.Args(); len(apps) > 0 {
		for _, app := range apps {
			found := false
			for _, bkup := range backup.Apps {
				if bkup.Name == app {
					toRestore = append(toRestore, bkup)
					found = true
					break
				}
			}
			if !found {
				log.Fatalf("no backup found for '%s'\n", app)
			}

		}
	} else {
		toRestore = backup.Apps
	}

	// check for conflicts
	// NOTE: there is still a race here if an app is created after this check
	if !c.Bool("force") {
		needForce := false
		for _, bkup := range toRestore {
			exists, err := configStore.AppExists(bkup.Name, utils.GalaxyEnv(c))
			if err != nil {
				log.Fatal(err)
			}
			if exists {
				log.Warnf("Cannot restore over existing app '%s'", bkup.Name)
				needForce = true
			}
		}
		if needForce {
			log.Fatal("Use -force to overwrite")
		}
	}

	loggedErr := false
	for _, bkup := range toRestore {
		if err := restoreApp(bkup, utils.GalaxyEnv(c)); err != nil {
			log.Errorf("%s", err)
			loggedErr = true
		}
	}

	if loggedErr {
		// This is mostly to give a non-zero exit status
		log.Fatal("Error occured during restore")
	}
}