func CreateRouterPaths() { helper.SetRouterRoot(true) for _, path := range routerzk.ZkPaths { Zk.Touch(path) } helper.SetRouterRoot(false) for _, path := range routerzk.ZkPaths { Zk.Touch(path) } for _, zone := range AvailableZones { Zk.Touch(helper.GetBaseRouterPath(true, zone)) Zk.Touch(helper.GetBaseRouterPath(false, zone)) } }
func ReserveRouterPortAndUpdateTrie(internal bool, app, sha, env string) (string, bool, error) { helper.SetRouterRoot(internal) var ( err error created = false port = "" trieName = "" ) // reserve port for app env if !HasRouterPortForAppEnv(internal, app, env) { created = true } if port, err = reserveRouterPort(internal, app, env); err != nil { return port, created, err } if trieName, err = UpdateAppEnvTrie(internal, app, sha, env); err != nil { return port, created, err } // now port is reserved and trie is created so we can actually create port for router portUInt, err := strconv.ParseUint(port, 10, 16) if err != nil { return port, created, err } err = routerzk.SetPort(Zk.Conn, routercfg.Port{ Port: uint16(portUInt), Trie: trieName, }) if err != nil { return port, created, err } // return true if port was created return port, created, err }
func (e *GetAppEnvPortExecutor) Execute(t *Task) (err error) { if e.arg.App == "" { return errors.New("Please specify an app") } else if e.arg.Env == "" { return errors.New("Please specify an environment") } zkApp, err := datamodel.GetApp(e.arg.App) if err != nil { return err } zrp := datamodel.GetRouterPorts(zkApp.Internal) fmt.Printf("ROUTER PORTS: %+v\n", zrp) portStr := zrp.AppEnvMap[helper.GetAppEnvTrieName(e.arg.App, e.arg.Env)] if portStr == "" { return errors.New("port not found") } fmt.Printf("PORT STRING: %+v -> %+v\n", helper.GetAppEnvTrieName(e.arg.App, e.arg.Env), portStr) port, err := strconv.ParseUint(portStr, 10, 16) if err != nil { return err } helper.SetRouterRoot(zkApp.Internal) e.reply.Port, err = routerzk.GetPort(datamodel.Zk.Conn, uint16(port)) return err }
func (s *DatamodelSuite) TestReserveRouterPortAndUpdateTrie(c *C) { Zk.RecursiveDelete(helper.GetBaseRouterPortsPath(true)) Zk.RecursiveDelete(helper.GetBaseRouterPortsPath(false)) Zk.RecursiveDelete(helper.GetBaseLockPath()) Zk.RecursiveDelete("/atlantis/router") CreateRouterPaths() CreateRouterPortsPaths() CreateLockPaths() MinRouterPort = uint16(65533) MaxRouterPort = uint16(65535) helper.SetRouterRoot(true) port, created, err := ReserveRouterPortAndUpdateTrie(true, "app", "sha", "env") c.Assert(err, IsNil) c.Assert(created, Equals, true) c.Assert(port, Equals, "65533") trie, err := routerzk.GetTrie(Zk.Conn, helper.GetAppEnvTrieName("app", "env")) c.Assert(err, IsNil) c.Assert(len(trie.Rules), Equals, 1) port, created, err = ReserveRouterPortAndUpdateTrie(true, "app", "sha2", "env") c.Assert(err, IsNil) c.Assert(created, Equals, false) c.Assert(port, Equals, "65533") trie, err = routerzk.GetTrie(Zk.Conn, helper.GetAppEnvTrieName("app", "env")) c.Assert(err, IsNil) c.Assert(len(trie.Rules), Equals, 2) }
func (e *UpdateRuleExecutor) Execute(t *Task) (err error) { if e.arg.Rule.Name == "" { return errors.New("Please specify a name") } else if e.arg.Rule.Type == "" { return errors.New("Please specify a type") } else if e.arg.Rule.Value == "" { return errors.New("Please specify a value") } else if e.arg.Rule.Next == "" && e.arg.Rule.Pool == "" { return errors.New("Please specify either a next trie or a pool") } // fill in current cname suffixes in multi-host rules if e.arg.Rule.Type == "multi-host" && dns.Provider != nil { suffix, err := dns.Provider.Suffix(Region) if err != nil { return err } list := strings.Join(helper.GetAppCNameSuffixes(suffix), ",") e.arg.Rule.Value = fmt.Sprintf("%s:%s", e.arg.Rule.Value, list) } helper.SetRouterRoot(e.arg.Rule.Internal) err = routerzk.SetRule(datamodel.Zk.Conn, e.arg.Rule) if err != nil { e.reply.Status = StatusError } else { e.reply.Status = StatusOk } return err }
func CleanupCreatedPoolRefs(internal bool, app, sha, env string) error { helper.SetRouterRoot(internal) // remove static rule, cleanup rule from trie if needed ruleName := helper.GetAppShaEnvStaticRuleName(app, sha, env) trieName := helper.GetAppEnvTrieName(app, env) // remove static rule from trie trie, err := routerzk.GetTrie(Zk.Conn, trieName) if err != nil { return err } newRules := []string{} for _, rule := range trie.Rules { if rule != ruleName { newRules = append(newRules, rule) } } if len(trie.Rules) != len(newRules) { trie.Rules = newRules err = routerzk.SetTrie(Zk.Conn, trie) if err != nil { return err } } // delete static rule err = routerzk.DelRule(Zk.Conn, ruleName) if err != nil { return err } return nil }
func (e *ListPortsExecutor) Execute(t *Task) (err error) { helper.SetRouterRoot(e.arg.Internal) e.reply.Ports, err = routerzk.ListPorts(datamodel.Zk.Conn) if err == nil { sort.Sort(PortSortable(e.reply.Ports)) } return err }
func (e *GetPortExecutor) Execute(t *Task) (err error) { if e.arg.Port == 0 { return errors.New("Please specify a port") } helper.SetRouterRoot(e.arg.Internal) e.reply.Port, err = routerzk.GetPort(datamodel.Zk.Conn, e.arg.Port) return err }
func (e *UpdatePortExecutor) Execute(t *Task) (err error) { if e.arg.Port.Trie == "" { return errors.New("Please specify a trie") } if e.arg.Port.Port == uint16(0) { return errors.New("Please specify a port") } helper.SetRouterRoot(e.arg.Port.Internal) return routerzk.SetPort(datamodel.Zk.Conn, e.arg.Port) }
func (e *ListTriesExecutor) Execute(t *Task) (err error) { helper.SetRouterRoot(e.arg.Internal) e.reply.Tries, err = routerzk.ListTries(datamodel.Zk.Conn) if err != nil { e.reply.Status = StatusError } else { sort.Strings(e.reply.Tries) e.reply.Status = StatusOk } return err }
func DeleteFromPool(containers []string) error { pools := map[bool]map[string]*poolDefinition{} pools[true] = map[string]*poolDefinition{} pools[false] = map[string]*poolDefinition{} for _, cont := range containers { inst, err := GetInstance(cont) if err != nil { // instance doesn't exist continue } name := helper.CreatePoolName(inst.App, inst.Sha, inst.Env) zkApp, err := GetApp(inst.App) if err != nil { return err } poolDef := pools[zkApp.Internal][name] if poolDef == nil { poolDef = &poolDefinition{ app: inst.App, sha: inst.Sha, env: inst.Env, insts: []*ZkInstance{}, } pools[zkApp.Internal][name] = poolDef } pools[zkApp.Internal][name].insts = append(poolDef.insts, inst) } for internal, allPools := range pools { helper.SetRouterRoot(internal) for name, poolDef := range allPools { // remove hosts hosts := []string{} for _, inst := range poolDef.insts { hosts = append(hosts, fmt.Sprintf("%s:%d", inst.Host, inst.Port)) } routerzk.DelHosts(Zk.Conn, name, hosts) // delete pool if no hosts exist getHosts, err := routerzk.GetHosts(Zk.Conn, name) if err != nil || len(getHosts) == 0 { err = routerzk.DelPool(Zk.Conn, name) if err != nil { log.Println("Error trying to clean up pool:", err) } err = CleanupCreatedPoolRefs(internal, poolDef.app, poolDef.sha, poolDef.env) if err != nil { log.Println("Error trying to clean up pool:", err) } } } } return nil }
func (e *GetTrieExecutor) Execute(t *Task) (err error) { if e.arg.Name == "" { return errors.New("Please specify a name") } helper.SetRouterRoot(e.arg.Internal) e.reply.Trie, err = routerzk.GetTrie(datamodel.Zk.Conn, e.arg.Name) if err != nil { e.reply.Status = StatusError } else { e.reply.Status = StatusOk } return err }
func (e *UpdatePoolExecutor) Execute(t *Task) error { if e.arg.Pool.Name == "" { return errors.New("Please specify a name") } else if e.arg.Pool.Config.HealthzEvery == "" { return errors.New("Please specify a healthz check frequency") } else if e.arg.Pool.Config.HealthzTimeout == "" { return errors.New("Please specify a healthz timeout") } else if e.arg.Pool.Config.RequestTimeout == "" { return errors.New("Please specify a request timeout") } // no need to check hosts. an empty pool is still a valid pool helper.SetRouterRoot(e.arg.Pool.Internal) err := routerzk.SetPool(datamodel.Zk.Conn, e.arg.Pool) if err != nil { e.reply.Status = StatusError return err } // diff pools and update existingHosts, err := routerzk.GetHosts(datamodel.Zk.Conn, e.arg.Pool.Name) if err != nil { e.reply.Status = StatusError return err } delHosts := []string{} for name, _ := range existingHosts { if _, ok := e.arg.Pool.Hosts[name]; !ok { delHosts = append(delHosts, name) } } newHosts := map[string]routercfg.Host{} for name, newHost := range e.arg.Pool.Hosts { if _, ok := existingHosts[name]; !ok { newHosts[name] = newHost } } err = routerzk.AddHosts(datamodel.Zk.Conn, e.arg.Pool.Name, newHosts) if err != nil { e.reply.Status = StatusError return err } err = routerzk.DelHosts(datamodel.Zk.Conn, e.arg.Pool.Name, delHosts) if err != nil { e.reply.Status = StatusError return err } e.reply.Status = StatusOk return nil }
func UpdateAppEnvTrie(internal bool, app, sha, env string) (string, error) { helper.SetRouterRoot(internal) // create trie (if it doesn't exist) trieName := helper.GetAppEnvTrieName(app, env) if exists, err := routerzk.TrieExists(Zk.Conn, trieName); !exists || err != nil { err = routerzk.SetTrie(Zk.Conn, routercfg.Trie{ Name: trieName, Rules: []string{}, Internal: internal, }) if err != nil { return trieName, err } } // if sha != "" attach pool as static rule (if trie is empty) if sha != "" { // if static rule does not exist, create it ruleName := helper.GetAppShaEnvStaticRuleName(app, sha, env) poolName := helper.CreatePoolName(app, sha, env) if exists, err := routerzk.RuleExists(Zk.Conn, ruleName); !exists || err != nil { err = routerzk.SetRule(Zk.Conn, routercfg.Rule{ Name: ruleName, Type: "static", Value: "true", Pool: poolName, Internal: internal, }) if err != nil { return trieName, err } } trie, err := routerzk.GetTrie(Zk.Conn, trieName) if err != nil { return trieName, err } if len(trie.Rules) == 0 { trie.Rules = []string{ruleName} } else { trie.Rules = append(trie.Rules, ruleName) } if err = routerzk.SetTrie(Zk.Conn, trie); err != nil { return trieName, err } } return trieName, nil }
func ReclaimRouterPortsForEnv(internal bool, env string) error { helper.SetRouterRoot(internal) lock := NewRouterPortsLock(internal) lock.Lock() defer lock.Unlock() zrp := GetRouterPorts(internal) ports, err := zrp.reclaimEnv(env) if err != nil { return err } for _, port := range ports { if err := routerzk.DelPort(Zk.Conn, port); err != nil { log.Printf("Error reclaiming port %d for env %s", port, env) // don't fail here // TODO email appsplat } } return nil }
func AddToPool(containers []string) error { pools := map[bool]map[string][]*ZkInstance{} pools[true] = map[string][]*ZkInstance{} pools[false] = map[string][]*ZkInstance{} for _, cont := range containers { inst, err := GetInstance(cont) if err != nil { // instance doesn't exist continue } name := helper.CreatePoolName(inst.App, inst.Sha, inst.Env) zkApp, err := GetApp(inst.App) if err != nil { return err } currInsts := pools[zkApp.Internal][name] if currInsts == nil { currInsts = []*ZkInstance{} } pools[zkApp.Internal][name] = append(currInsts, inst) } for internal, allPools := range pools { helper.SetRouterRoot(internal) for name, insts := range allPools { // create pool if we need to if exists, err := routerzk.PoolExists(Zk.Conn, name); !exists || err != nil { if err = routerzk.SetPool(Zk.Conn, defaultPool(name, internal)); err != nil { return err } } // add hosts hosts := map[string]routercfg.Host{} for _, inst := range insts { address := fmt.Sprintf("%s:%d", inst.Host, inst.Port) hosts[address] = routercfg.Host{Address: address} } if err := routerzk.AddHosts(Zk.Conn, name, hosts); err != nil { return err } } } return nil }
func (s *DatamodelSuite) TestRouterExternalPool(c *C) { Zk.RecursiveDelete("/atlantis/router") Zk.RecursiveDelete("/atlantis/apps") Zk.RecursiveDelete(helper.GetBaseInstancePath()) CreateRouterPaths() CreateAppPath() // fake register app CreateOrUpdateApp(false, false, app, "ssh://[email protected]/app", "/", "*****@*****.**") CreateOrUpdateApp(false, false, "app2", "ssh://[email protected]/app", "/", "*****@*****.**") // do tests instance, err := CreateInstance(app, sha, env, host+"-1") c.Assert(err, IsNil) instance.SetPort(uint16(1337)) instance2, err := CreateInstance(app, sha, env, host+"-2") c.Assert(err, IsNil) instance2.SetPort(uint16(1338)) c.Assert(AddToPool([]string{instance.ID, instance2.ID}), IsNil) theName := helper.CreatePoolName(app, sha, env) helper.SetRouterRoot(false) thePool, err := routerzk.GetPool(Zk.Conn, theName) c.Assert(err, IsNil) c.Assert(thePool.Name, Equals, theName) c.Assert(thePool.Config.HealthzEvery, Not(Equals), "") c.Assert(thePool.Config.HealthzTimeout, Not(Equals), "") c.Assert(thePool.Config.RequestTimeout, Not(Equals), "") c.Assert(thePool.Hosts, DeepEquals, map[string]config.Host{host + "-1:1337": config.Host{Address: host + "-1:1337"}, host + "-2:1338": config.Host{Address: host + "-2:1338"}}) newInstance, err := CreateInstance("app2", "sha1", "env1", host+"-1") c.Assert(err, IsNil) newInstance.SetPort(uint16(1339)) newInstance2, err := CreateInstance(app, sha, env, host+"-3") c.Assert(err, IsNil) newInstance2.SetPort(uint16(1340)) c.Assert(DeleteFromPool([]string{instance2.ID}), IsNil) instance2.Delete() c.Assert(AddToPool([]string{newInstance.ID, newInstance2.ID}), IsNil) helper.SetRouterRoot(false) thePool, err = routerzk.GetPool(Zk.Conn, theName) c.Assert(err, IsNil) c.Assert(thePool.Name, Equals, theName) c.Assert(thePool.Config.HealthzEvery, Not(Equals), "") c.Assert(thePool.Config.HealthzTimeout, Not(Equals), "") c.Assert(thePool.Config.RequestTimeout, Not(Equals), "") c.Assert(thePool.Hosts, DeepEquals, map[string]config.Host{host + "-1:1337": config.Host{Address: host + "-1:1337"}, host + "-3:1340": config.Host{Address: host + "-3:1340"}}) helper.SetRouterRoot(false) thePool2, err := routerzk.GetPool(Zk.Conn, helper.CreatePoolName("app2", "sha1", "env1")) c.Assert(err, IsNil) c.Assert(thePool2.Name, Equals, helper.CreatePoolName("app2", "sha1", "env1")) c.Assert(thePool2.Config.HealthzEvery, Not(Equals), "") c.Assert(thePool2.Config.HealthzTimeout, Not(Equals), "") c.Assert(thePool2.Config.RequestTimeout, Not(Equals), "") c.Assert(thePool2.Hosts, DeepEquals, map[string]config.Host{host + "-1:1339": config.Host{Address: host + "-1:1339"}}) helper.SetRouterRoot(false) pools, err := routerzk.ListPools(Zk.Conn) c.Assert(err, IsNil) sort.Strings(pools) c.Assert(pools, DeepEquals, []string{thePool2.Name, thePool.Name}) c.Assert(DeleteFromPool([]string{instance.ID, newInstance.ID, newInstance2.ID}), IsNil) instance.Delete() newInstance.Delete() newInstance2.Delete() helper.SetRouterRoot(false) thePool, err = routerzk.GetPool(Zk.Conn, theName) c.Assert(err, Not(IsNil)) }