// handleHostListPost handles addition of a host to the current datacenter. // If the Host.AgentPort is not specified, root service is queried for // the default Agent port. func (topology *TopologySvc) handleHostListPost(input interface{}, ctx common.RestContext) (interface{}, error) { host := input.(*common.Host) // If no agent port is specfied in the creation of new host, // get the agent port from root service. log.Printf("Host requested with agent port %d", host.AgentPort) if host.AgentPort == 0 { // Get the one from configuration agentConfig, err := topology.client.GetServiceConfig("agent") if err != nil { return nil, err } host.AgentPort = agentConfig.Common.Api.Port if host.AgentPort == 0 { return nil, common.NewError500("Cannot determine port for agent") } } log.Printf("Host will be added with agent port %d", host.AgentPort) err := topology.store.addHost(topology.datacenter, host) if err != nil { return nil, err } agentURL := fmt.Sprintf("http://%s:%d", host.Ip, host.AgentPort) agentLink := common.LinkResponse{Href: agentURL, Rel: "agent"} hostLink := common.LinkResponse{Href: hostListPath + "/" + fmt.Sprintf("%d", host.ID), Rel: "self"} collectionLink := common.LinkResponse{Href: hostListPath, Rel: "self"} host.Links = []common.LinkResponse{agentLink, hostLink, collectionLink} return host, nil }
// findPolicyByName returns the first policy found corresponding // to the given policy name. Policy names are not unique unlike // policy ID's. func (policy *PolicySvc) findPolicyByName(input interface{}, ctx common.RestContext) (interface{}, error) { nameStr := ctx.PathVariables["policyName"] log.Printf("In findPolicy(%s)\n", nameStr) if nameStr == "" { return nil, common.NewError500(fmt.Sprintf("Expected policy name, got %s", nameStr)) } policyDoc, err := policy.store.findPolicyByName(nameStr) if err != nil { return nil, err } policyDoc.Datacenter = nil return policyDoc, nil }
// deletePolicy deletes policy based the following algorithm: //1. Mark the policy as "deleted" in the backend store. func (policy *PolicySvc) deletePolicy(id uint64) (interface{}, error) { // TODO do we need this to be transactional or not ... case can be made for either. err := policy.store.inactivatePolicy(id) if err != nil { return nil, err } policyDoc, err := policy.store.getPolicy(id, true) log.Printf("Found policy for ID %d: %s (%v)", id, policyDoc, err) if err != nil { return nil, err } hosts, err := policy.client.ListHosts() if err != nil { return nil, err } if policyDoc.ExternalID == "" { // TODO // Important! This should really be done in policy agent. // Only done here as temporary measure. externalId := makeId(policyDoc.AppliedTo, policyDoc.Name) log.Printf("Constructing internal policy name = %s", externalId) policyDoc.ExternalID = externalId } errStr := make([]string, 0) for _, host := range hosts { // TODO make schema configurable url := fmt.Sprintf("http://%s:%d/policies", host.Ip, host.AgentPort) result := make(map[string]interface{}) err = policy.client.Delete(url, policyDoc, result) log.Printf("Agent at %s returned %v", host.Ip, result) if err != nil { errStr = append(errStr, fmt.Sprintf("Error deleting policy %d (%s) from host %s: %v. ", id, policyDoc.Name, host.Ip, err)) } } if len(errStr) > 0 { return nil, common.NewError500(errStr) } err = policy.store.deletePolicy(id) if err != nil { return nil, err } policyDoc.Datacenter = nil return policyDoc, nil }
// distributePolicy distributes policy to all agents. // TODO how should error handling work here really? func (policy *PolicySvc) distributePolicy(policyDoc *common.Policy) error { hosts, err := policy.client.ListHosts() if err != nil { return err } errStr := make([]string, 0) for _, host := range hosts { // TODO make schema configurable url := fmt.Sprintf("http://%s:%d/policies", host.Ip, host.AgentPort) log.Printf("Sending policy %s to agent at %s", policyDoc.Name, url) result := make(map[string]interface{}) err = policy.client.Post(url, policyDoc, &result) log.Printf("Agent at %s returned %v", host.Ip, result) if err != nil { errStr = append(errStr, fmt.Sprintf("Error applying policy %d to host %s: %v. ", policyDoc.ID, host.Ip, err)) } } if len(errStr) > 0 { return common.NewError500(errStr) } return nil }
// deleteEndpoint releases the IP(s) owned by the endpoint into assignable // pool. func (ipamStore *ipamStore) deleteEndpoint(ip string) (Endpoint, error) { tx := ipamStore.DbStore.Db.Begin() results := make([]Endpoint, 0) tx.Where(&Endpoint{Ip: ip}).Find(&results) if len(results) == 0 { tx.Rollback() return Endpoint{}, common.NewError404("endpoint", ip) } if len(results) > 1 { // This cannot happen by constraints... tx.Rollback() errMsg := fmt.Sprintf("Expected one result for ip %s, got %v", ip, results) log.Printf(errMsg) return Endpoint{}, common.NewError500(errors.New(errMsg)) } tx = tx.Model(Endpoint{}).Where("ip = ?", ip).Update("in_use", false) err := common.MakeMultiError(tx.GetErrors()) if err != nil { tx.Rollback() return Endpoint{}, err } tx.Commit() return results[0], nil }