diff --git a/commands/datacenter_get.go b/commands/datacenter_get.go new file mode 100644 index 0000000..88e90c3 --- /dev/null +++ b/commands/datacenter_get.go @@ -0,0 +1,27 @@ +package commands + +import ( + "github.com/centurylinkcloud/clc-go-cli/base" + "github.com/centurylinkcloud/clc-go-cli/models/datacenter" +) + +type DatacenterGet struct { + CommandBase +} + +func NewDatacenterGet(info CommandExcInfo) *DatacenterGet { + dcGet := DatacenterGet{} + dcGet.ExcInfo = info + dcGet.Input = &datacenter.GetReq{} + return &dcGet +} + +func (dcGet *DatacenterGet) Execute(cn base.Connection) error { + var err error + + input := dcGet.Input.(*datacenter.GetReq) + dcGet.Output, err = datacenter.Get(cn, input.DataCenter, input.WithComputeLimits.Set, + input.WithNetworkLimits.Set, input.WithAvailableOvfs.Set, input.WithLoadBalancers.Set) + + return err +} diff --git a/commands/datacenter_list.go b/commands/datacenter_list.go new file mode 100644 index 0000000..ad47031 --- /dev/null +++ b/commands/datacenter_list.go @@ -0,0 +1,27 @@ +package commands + +import ( + "github.com/centurylinkcloud/clc-go-cli/base" + "github.com/centurylinkcloud/clc-go-cli/models/datacenter" +) + +type DatacenterList struct { + CommandBase +} + +func NewDatacenterList(info CommandExcInfo) *DatacenterList { + dcList := DatacenterList{} + dcList.ExcInfo = info + dcList.Input = &datacenter.ListReq{} + return &dcList +} + +func (dcList *DatacenterList) Execute(cn base.Connection) error { + var err error + + input := dcList.Input.(*datacenter.ListReq) + dcList.Output, err = datacenter.All(cn, input.WithComputeLimits.Set, + input.WithNetworkLimits.Set, input.WithAvailableOvfs.Set, input.WithLoadBalancers.Set) + + return err +} diff --git a/init.go b/init.go index e213fed..5a4f25a 100644 --- a/init.go +++ b/init.go @@ -1317,18 +1317,32 @@ func init() { }, }) - registerCommandBase(&datacenter.ListReq{}, &[]datacenter.ListRes{}, commands.CommandExcInfo{ - Verb: "GET", - Url: "https://api.ctl.io/v2/datacenters/{accountAlias}", + registerCustomCommand(commands.NewDatacenterList(commands.CommandExcInfo{ Resource: "data-center", Command: "list", Help: help.Command{ Brief: []string{"Gets the list of data centers that a given account has access to."}, + Arguments: []help.Argument{ + { + "--with-compute-limits", + []string{"Get compute limits data"}, + }, + { + "--with-network-limits", + []string{"Get network limits data"}, + }, + { + "--with-available-ovfs", + []string{"Get available servers for import"}, + }, + { + "--with-load-balancers", + []string{"Get load balancers"}, + }, + }, }, - }) - registerCommandBase(&datacenter.GetReq{}, &datacenter.GetRes{}, commands.CommandExcInfo{ - Verb: "GET", - Url: "https://api.ctl.io/v2/datacenters/{accountAlias}/{DataCenter}?groupLinks={GroupLinks}", + })) + registerCustomCommand(commands.NewDatacenterGet(commands.CommandExcInfo{ Resource: "data-center", Command: "get", Help: help.Command{ @@ -1339,12 +1353,24 @@ func init() { []string{"Required. Short string representing the data center you are querying."}, }, { - "--group-links", - []string{"Required. Determine whether link collections are returned for each group."}, + "--with-compute-limits", + []string{"Get compute limits data"}, + }, + { + "--with-network-limits", + []string{"Get network limits data"}, + }, + { + "--with-available-ovfs", + []string{"Get available servers for import"}, + }, + { + "--with-load-balancers", + []string{"Get load balancers"}, }, }, }, - }) + })) registerCommandBase(&datacenter.GetDCReq{}, &datacenter.GetDCRes{}, commands.CommandExcInfo{ Verb: "GET", Url: "https://api.ctl.io/v2/datacenters/{accountAlias}/{DataCenter}/deploymentCapabilities", diff --git a/models/datacenter/get.go b/models/datacenter/get.go index 4a30ffe..2cde631 100644 --- a/models/datacenter/get.go +++ b/models/datacenter/get.go @@ -1,24 +1,54 @@ package datacenter import ( - "fmt" + "github.com/centurylinkcloud/clc-go-cli/base" "github.com/centurylinkcloud/clc-go-cli/models" ) type GetReq struct { - DataCenter string `valid:"required" URIParam:"yes"` - GroupLinks string `valid:"required" URIParam:"yes"` + DataCenter string `valid:"required"` + WithComputeLimits base.NilField + WithNetworkLimits base.NilField + WithAvailableOvfs base.NilField + WithLoadBalancers base.NilField } type GetRes struct { - Id string - Name string - Links []models.LinkEntity + Id string + Name string + ComputeLimits *DcComputeLimits `json:",omitempty"` + NetworkLimits *DcNetworkLimits `json:",omitempty"` + AvailableOVFs *[]DcAvailableOVF `json:",omitempty"` + LoadBalancers *[]DcLoadBalancer `json:",omitempty"` + Links models.Links } -func (r *GetReq) Validate() error { - if r.GroupLinks != "false" && r.GroupLinks != "true" { - return fmt.Errorf("group-links value must be either true or false.") - } - return nil +type DcComputeLimits struct { + Cpu DcResourceLimit + MemoryGB DcResourceLimit + StorageGB DcResourceLimit +} + +type DcNetworkLimits struct { + Networks DcResourceLimit +} + +type DcResourceLimit struct { + Value int + Inherited bool +} + +type DcAvailableOVF struct { + Id string + Name string + StorageSizeGB int + CpuCount int + MemorySizeMB int +} + +type DcLoadBalancer struct { + Name string + Description string + IpAddress string + Status string } diff --git a/models/datacenter/list.go b/models/datacenter/list.go index 7ea6614..28c299a 100644 --- a/models/datacenter/list.go +++ b/models/datacenter/list.go @@ -1,13 +1,14 @@ package datacenter import ( - "github.com/centurylinkcloud/clc-go-cli/models" + "github.com/centurylinkcloud/clc-go-cli/base" ) -type ListReq struct{} - -type ListRes struct { - Id string - Name string - Links []models.LinkEntity +type ListReq struct { + WithComputeLimits base.NilField + WithNetworkLimits base.NilField + WithAvailableOvfs base.NilField + WithLoadBalancers base.NilField } + +type ListRes GetRes diff --git a/models/datacenter/load.go b/models/datacenter/load.go new file mode 100644 index 0000000..25ee29e --- /dev/null +++ b/models/datacenter/load.go @@ -0,0 +1,288 @@ +package datacenter + +import ( + "fmt" + "sync" + + "github.com/centurylinkcloud/clc-go-cli/base" +) + +var ( + ListTimeout = 200 +) + +func All(cn base.Connection, withComputeLimits, withNetworkLimits, withAvailableOvfs, withLoadBalancers bool) ([]GetRes, error) { + fetcher := dcListFetcher{ + connection: cn, + withComputeLimits: withComputeLimits, + withNetworkLimits: withNetworkLimits, + withAvailableOvfs: withAvailableOvfs, + withLoadBalancers: withLoadBalancers, + } + return fetcher.Fetch() +} + +type dcListFetcher struct { + connection base.Connection + withComputeLimits bool + withNetworkLimits bool + withAvailableOvfs bool + withLoadBalancers bool +} + +func (f *dcListFetcher) Fetch() ([]GetRes, error) { + list, err := f.fetchList() + if err != nil { + return list, err + } + + if f.withComputeLimits { + err = f.fetchComputeLimits(list) + if err != nil { + return list, err + } + } + + if f.withNetworkLimits { + err = f.fetchNetworkLimits(list) + if err != nil { + return list, err + } + } + + if f.withAvailableOvfs { + err = f.fetchAvailableOvfs(list) + if err != nil { + return list, err + } + } + + if f.withLoadBalancers { + err = f.fetchLoadBalancers(list) + if err != nil { + return list, err + } + } + + return list, nil +} + +func (f *dcListFetcher) fetchList() ([]GetRes, error) { + var err error + + datacentersUrl := fmt.Sprintf("%s/v2/datacenters/{accountAlias}", base.URL) + res := []GetRes{} + err = f.connection.ExecuteRequest("GET", datacentersUrl, nil, &res) + if err != nil { + return res, err + } + + return res, nil +} + +func (f *dcListFetcher) fetchComputeLimits(list []GetRes) error { + var wg sync.WaitGroup + + wg.Add(len(list)) + + for i := 0; i < len(list); i++ { + item := list[i] + go func(i int) { + defer wg.Done() + singleFetcher := dcSingleFetcher{ + connection: f.connection, + } + singleFetcher.FetchComputeLimits(&item) + list[i] = item + }(i) + } + + wg.Wait() + + return nil +} + +func (f *dcListFetcher) fetchNetworkLimits(list []GetRes) error { + var wg sync.WaitGroup + + wg.Add(len(list)) + + for i := 0; i < len(list); i++ { + item := list[i] + go func(i int) { + defer wg.Done() + singleFetcher := dcSingleFetcher{ + connection: f.connection, + } + singleFetcher.FetchNetworkLimits(&item) + list[i] = item + }(i) + } + + wg.Wait() + + return nil +} + +func (f *dcListFetcher) fetchAvailableOvfs(list []GetRes) error { + var wg sync.WaitGroup + + wg.Add(len(list)) + + for i := 0; i < len(list); i++ { + item := list[i] + go func(i int) { + defer wg.Done() + singleFetcher := dcSingleFetcher{ + connection: f.connection, + } + singleFetcher.FetchAvailableOvfs(&item) + list[i] = item + }(i) + } + + wg.Wait() + + return nil +} + +func (f *dcListFetcher) fetchLoadBalancers(list []GetRes) error { + var wg sync.WaitGroup + + wg.Add(len(list)) + + for i := 0; i < len(list); i++ { + item := list[i] + go func(i int) { + defer wg.Done() + singleFetcher := dcSingleFetcher{ + connection: f.connection, + } + singleFetcher.FetchLoadBalancers(&item) + list[i] = item + }(i) + } + + wg.Wait() + + return nil +} + +func Get(cn base.Connection, dcId string, withComputeLimits, withNetworkLimits, withAvailableOvfs, withLoadBalancers bool) (GetRes, error) { + fetcher := dcSingleFetcher{ + connection: cn, + withComputeLimits: withComputeLimits, + withNetworkLimits: withNetworkLimits, + withAvailableOvfs: withAvailableOvfs, + withLoadBalancers: withLoadBalancers, + } + return fetcher.Fetch(dcId) +} + +type dcSingleFetcher struct { + connection base.Connection + withComputeLimits bool + withNetworkLimits bool + withAvailableOvfs bool + withLoadBalancers bool +} + +func (f *dcSingleFetcher) Fetch(dcId string) (GetRes, error) { + res, err := f.fetchDc(dcId) + + if f.withComputeLimits { + f.FetchComputeLimits(&res) + if err != nil { + return res, err + } + } + + if f.withNetworkLimits { + err = f.FetchNetworkLimits(&res) + if err != nil { + return res, err + } + } + + if f.withAvailableOvfs { + err = f.FetchAvailableOvfs(&res) + if err != nil { + return res, err + } + } + + if f.withLoadBalancers { + err = f.FetchLoadBalancers(&res) + if err != nil { + return res, err + } + } + + return res, err +} + +func (f *dcSingleFetcher) fetchDc(dcId string) (GetRes, error) { + dcUrl := fmt.Sprintf("%s/v2/datacenters/{accountAlias}/%s", base.URL, dcId) + res := GetRes{} + err := f.connection.ExecuteRequest("GET", dcUrl, struct{}{}, &res) + if err != nil { + return res, err + } + return res, nil +} + +func (f *dcSingleFetcher) FetchComputeLimits(item *GetRes) error { + limitsRelativePath, err := item.Links.Get("computeLimits") + if err != nil { + return err + } + + computeLimitsUrl := fmt.Sprintf("%s%s", base.URL, limitsRelativePath) + res := &DcComputeLimits{} + f.connection.ExecuteRequest("GET", computeLimitsUrl, struct{}{}, res) + item.ComputeLimits = res + + return nil +} + +func (f *dcSingleFetcher) FetchNetworkLimits(item *GetRes) error { + limitsRelativePath, err := item.Links.Get("networkLimits") + if err != nil { + return err + } + + networkLimitsUrl := fmt.Sprintf("%s%s", base.URL, limitsRelativePath) + res := &DcNetworkLimits{} + f.connection.ExecuteRequest("GET", networkLimitsUrl, struct{}{}, res) + item.NetworkLimits = res + + return nil +} + +func (f *dcSingleFetcher) FetchAvailableOvfs(item *GetRes) error { + availableOvfsRelativePath, err := item.Links.Get("availableOvfs") + if err != nil { + return err + } + + availableOvfsUrl := fmt.Sprintf("%s%s", base.URL, availableOvfsRelativePath) + res := []DcAvailableOVF{} + f.connection.ExecuteRequest("GET", availableOvfsUrl, struct{}{}, &res) + item.AvailableOVFs = &res + + return nil +} + +func (f *dcSingleFetcher) FetchLoadBalancers(item *GetRes) error { + loadBalancersRelativePath, err := item.Links.Get("loadBalancers") + if err != nil { + return err + } + + loadBalancersUrl := fmt.Sprintf("%s%s", base.URL, loadBalancersRelativePath) + res := []DcLoadBalancer{} + f.connection.ExecuteRequest("GET", loadBalancersUrl, struct{}{}, &res) + item.LoadBalancers = &res + + return nil +} diff --git a/models/link.go b/models/link.go index eb4bfe3..0a88817 100644 --- a/models/link.go +++ b/models/link.go @@ -20,3 +20,14 @@ func GetLink(links []LinkEntity, resource string) (string, error) { } return "", fmt.Errorf("No %s link found", resource) } + +type Links []LinkEntity + +func (l Links) Get(resource string) (string, error) { + for _, link := range l { + if link.Rel == resource { + return link.Href, nil + } + } + return "", fmt.Errorf("No %s link found", resource) +}