func (ztr *ZipkinTaskRunner) RunTask(context *framework.Variables, application *framework.Application, task map[string]string) error { api := context.MustGet(fmt.Sprintf("%s.api", application.ID)) id, ok := task["id"] if !ok { return errors.New("Missing task id") } taskType, ok := task["type"] if !ok { return fmt.Errorf("Missing task type for id %s", id) } client := NewZipkinMesosClient(api) _, err := client.Add(task) if err != nil { return err } response, err := client.Start(task) if err != nil { return err } if taskType == "query" { return ztr.fillTaskContext(context, application, response) } return nil }
func (etr *ExhibitorTaskRunner) RunTask(context *framework.Variables, application *framework.Application, task map[string]string) error { api := context.MustGet(fmt.Sprintf("%s.api", application.ID)) client := NewExhibitorMesosClient(api) _, err := client.Add(task) if err != nil { return err } _, err = client.Update(task) if err != nil { return err } response, err := client.Start(task) if err != nil { return err } err = etr.fillTaskContext(context, application, response) if err != nil { return err } return client.AwaitZookeeperRunning() }
func (etr *ElasticsearchTaskRunner) FillContext(context *framework.Variables, application *framework.Application, task marathon.Task) error { context.SetStackVariable(fmt.Sprintf("%s.host", application.ID), task.Host) for idx, port := range task.Ports { context.SetStackVariable(fmt.Sprintf("%s.port%d", application.ID, idx), fmt.Sprint(port)) } api := fmt.Sprintf("http://%s:%d", task.Host, task.Ports[0]) context.SetStackVariable(fmt.Sprintf("%s.api", application.ID), api) client := NewElasticsearchClient(api) err := client.AwaitRunning(etr.awaitTimeout, etr.backoffTimeout) if err != nil { return err } tasks, err := client.GetTasks() if err != nil { return err } for idx, task := range tasks { context.SetStackVariable(fmt.Sprintf("%s.%d.httpAddress", application.ID, idx), task.HttpAddress) context.SetStackVariable(fmt.Sprintf("%s.%d.transportAddress", application.ID, idx), task.TransportAddress) } return nil }
func (str *StatsdTaskRunner) RunTask(context *framework.Variables, application *framework.Application, task map[string]string) error { api := context.MustGet(fmt.Sprintf("%s.api", application.ID)) client := NewStatsdMesosClient(api) err := client.Update(task) if err != nil { return err } return client.Start(task) }
func (dtr *DSE02xTaskRunner) fillTaskContext(context *framework.Variables, application *framework.Application, response []byte) error { startResponse := new(DSEMesos02xStartResponse) err := json.Unmarshal(response, &startResponse) if err != nil { return err } if startResponse.Status == "timeout" { return errors.New("Timed out") } servers := make([]string, 0) for _, node := range startResponse.Nodes { nodeEndpoint := fmt.Sprintf("%s:%d", node.Runtime.Address, node.Runtime.Reservation.Ports["cql"]) context.SetStackVariable(fmt.Sprintf("%s.cassandra-%s", application.ID, fmt.Sprint(node.ID)), nodeEndpoint) context.SetStackVariable(fmt.Sprintf("%s.cassandra-%s.host", application.ID, fmt.Sprint(node.ID)), node.Runtime.Address) for name, port := range node.Runtime.Reservation.Ports { context.SetStackVariable(fmt.Sprintf("%s.cassandra-%s.%sPort", application.ID, fmt.Sprint(node.ID), name), fmt.Sprint(port)) } servers = append(servers, nodeEndpoint) } context.SetStackVariable(fmt.Sprintf("%s.cassandraConnect", application.ID), strings.Join(servers, ",")) return nil }
func (dtr *DSETaskRunner) RunTask(context *framework.Variables, application *framework.Application, task map[string]string) error { api := context.MustGet(fmt.Sprintf("%s.api", application.ID)) client := NewDSEMesosClient(api) _, err := client.Add(task) if err != nil { return err } response, err := client.Start(task) if err != nil { return err } return dtr.fillTaskContext(context, application, response) }
func (dtr *DSETaskRunner) fillTaskContext(context *framework.Variables, application *framework.Application, response map[string]interface{}) error { servers := make([]string, 0) serversMap := make(map[string]string) value, ok := response["value"].(map[string]interface{}) if !ok { return errors.New("Wrong value field") } clusterArr, ok := value["cluster"].([]interface{}) if !ok { return errors.New("Wrong cluster field") } for _, clusterIface := range clusterArr { cluster, ok := clusterIface.(map[string]interface{}) if !ok { return errors.New("Wrong cluster field") } id, ok := cluster["id"].(string) if !ok { return errors.New("Wrong id field") } runtime, ok := cluster["runtime"].(map[string]interface{}) if !ok { return errors.New("Wrong runtime field") } hostname, ok := runtime["hostname"].(string) if !ok { return errors.New("Wrong hostname field") } serversMap[id] = hostname servers = append(servers, hostname) } for id, host := range servers { context.SetStackVariable(fmt.Sprintf("%s.cassandra-node-%s", application.ID, fmt.Sprint(id)), host) } context.SetStackVariable(fmt.Sprintf("%s.cassandraConnect", application.ID), strings.Join(servers, ",")) return nil }
func (etr *ExhibitorTaskRunner) fillTaskContext(context *framework.Variables, application *framework.Application, response *exhibitorCluster) error { servers := make([]string, 0) serversMap := make(map[string]string) for _, server := range response.Cluster { hostname := fmt.Sprintf("%s:%s", server.Config.Hostname, etr.getClientPort(server)) serversMap[server.Id] = hostname servers = append(servers, hostname) } for id, host := range servers { context.SetStackVariable(fmt.Sprintf("%s.exhibitor-%s", application.ID, fmt.Sprint(id)), host) } context.SetStackVariable(fmt.Sprintf("%s.zkConnect", application.ID), strings.Join(servers, ",")) return nil }
func (ztr *ZipkinTaskRunner) fillTaskContext(context *framework.Variables, application *framework.Application, response map[string]interface{}) error { valueArr, ok := response["value"].([]interface{}) if !ok { return errors.New("Wrong value field") } for _, valueIface := range valueArr { value, ok := valueIface.(map[string]interface{}) if !ok { return errors.New("Wrong value interface field") } id, ok := value["id"].(string) if !ok { return errors.New("Wrong id field") } config, ok := value["config"].(map[string]interface{}) if !ok { return errors.New("Wrong config field") } hostname, ok := config["hostname"].(string) if !ok { return errors.New("Wrong hostname field") } env, ok := config["env"].(map[string]interface{}) if !ok { return errors.New("Wrong env field") } queryPort, ok := env["QUERY_PORT"].(string) if !ok { return errors.New("Wrong QUERY_PORT env") } context.SetStackVariable(fmt.Sprintf("%s.query-%s.endpoint", application.ID, id), fmt.Sprintf("%s:%s", hostname, queryPort)) } return nil }
func (dtr *DSETaskRunner) FillContext(context *framework.Variables, application *framework.Application, task marathon.Task) error { context.SetStackVariable(fmt.Sprintf("%s.host", application.ID), task.Host) for idx, port := range task.Ports { context.SetStackVariable(fmt.Sprintf("%s.port%d", application.ID, idx), fmt.Sprint(port)) } context.SetStackVariable(fmt.Sprintf("%s.api", application.ID), fmt.Sprintf("http://%s:%d", task.Host, task.Ports[0])) return nil }
func (sc *ServerCommand) Run(args []string) int { schedulerConfig := framework.NewSchedulerConfig() var ( flags = flag.NewFlagSet("server", flag.ExitOnError) marathonURL = flags.String("marathon", "http://127.0.0.1:8080", "Marathon address <ip:port>.") persistentStorage = flags.String("storage", "", "Storage to store stack-deploy runtime information to recover from failovers. Required.") api = flags.String("api", "0.0.0.0:4200", "Stack-deploy server binding address") bootstrap = flags.String("bootstrap", "", "Stack file to bootstrap with.") cassandra = flags.String("cassandra", "127.0.0.1", "Cassandra cluster IPs, comma-separated") keyspace = flags.String("keyspace", "stack_deploy", "Cassandra keyspace") proto = flags.Int("proto", 3, "Cassandra protocol version") connectRetries = flags.Int("connect.retries", 10, "Number of retries to connect to either Marathon or Cassandra") connectBackoff = flags.Duration("connect.backoff", 10*time.Second, "Backoff between connection attempts to either Marathon or Cassandra") debug = flags.Bool("debug", false, "Flag for debug mode") dev = flags.Bool("dev", false, "Flag for developer mode") variables = make(vars) ) flags.StringVar(&schedulerConfig.Master, "master", "127.0.0.1:5050", "Mesos Master address <ip:port>.") flags.StringVar(&schedulerConfig.User, "framework.user", "", "Mesos user. Defaults to current system user.") flags.StringVar(&schedulerConfig.FrameworkName, "framework.name", "stack-deploy", "Mesos framework name. Defaults to stack-deploy.") flags.StringVar(&schedulerConfig.FrameworkRole, "framework.role", "*", "Mesos framework role. Defaults to *.") flags.DurationVar(&schedulerConfig.FailoverTimeout, "failover.timeout", 168*time.Hour, "Mesos framework failover timeout. Defaults to 1 week.") flags.Var(variables, "var", "Global variables to add to every stack context run by stack-deploy server. Multiple occurrences of this flag allowed.") flags.Parse(args) if *debug { framework.Logger = plog.NewConsoleLogger(plog.DebugLevel, plog.DefaultLogFormat) } ctrlc := make(chan os.Signal, 1) signal.Notify(ctrlc, os.Interrupt) framework.TaskRunners = sc.runners framework.MesosTaskRunners = sc.mesosRunners marathonClient, err := sc.connectMarathon(*marathonURL, *connectRetries, *connectBackoff) if err != nil { log.Fatal(err) return 1 } if *persistentStorage == "" { if !*dev { log.Fatal("--storage flag is required. Examples: 'file:stack-deploy.json', 'zk:zookeeper.service:2181/stack-deploy'") return 1 } else { *persistentStorage = "file:stack-deploy.json" } } frameworkStorage, err := framework.NewFrameworkStorage(*persistentStorage) if err != nil { log.Fatal(err) return 1 } schedulerConfig.Storage = frameworkStorage frameworkStorage.Load() scheduler := framework.NewScheduler(schedulerConfig) err = scheduler.GetMesosState().Update() if err != nil { log.Fatal(err) return 1 } if *bootstrap != "" { var context *framework.Variables if frameworkStorage.BootstrapContext != nil && len(frameworkStorage.BootstrapContext.All()) > 0 { log.Info("Restored bootstrap context from persistent storage") context = frameworkStorage.BootstrapContext } else { log.Info("No existing bootstrap context found in persistent storage, bootstrapping") var err error context, err = sc.Bootstrap(*bootstrap, marathonClient, scheduler, *connectRetries, *connectBackoff) if err != nil { log.Fatal(err) return 1 } } log.Infof("Bootstrap context: %s", context) log.Infof("Cassandra connect before resolving: %s", *cassandra) for k, v := range context.All() { *cassandra = strings.Replace(*cassandra, fmt.Sprintf("{%s}", fmt.Sprint(k)), fmt.Sprint(v), -1) } log.Infof("Cassandra connect after resolving: %s", *cassandra) frameworkStorage.BootstrapContext = context frameworkStorage.Save() } var storage framework.Storage var userStorage framework.UserStorage var stateStorage framework.StateStorage var key string if !*dev { var connection *gocql.Session var err error storage, connection, err = framework.NewCassandraStorageRetryBackoff(strings.Split(*cassandra, ","), *keyspace, *connectRetries, *connectBackoff, *proto) if err != nil { panic(err) } userStorage, key, err = framework.NewCassandraUserStorage(connection, *keyspace) if err != nil { panic(err) } stateStorage, err = framework.NewCassandraStateStorage(connection, *keyspace) if err != nil { panic(err) } } else { log.Warning("Starting in developer mode. DO NOT use this in production!") schedulerConfig.FailoverTimeout = time.Duration(0) storage = framework.NewInMemoryStorage() userStorage = new(framework.NoopUserStorage) stateStorage = framework.NewInMemoryStateStorage() } apiServer := framework.NewApiServer(*api, marathonClient, variables, storage, userStorage, stateStorage, scheduler) if key != "" { fmt.Printf("***\nAdmin user key: %s\n***\n", key) } go apiServer.Start() <-ctrlc return 0 }