provider/clc: vendor deps, update to match latest SDK API
This commit is contained in:
parent
7775cc8ccc
commit
c4b23223ab
|
@ -150,6 +150,51 @@
|
|||
"Comment": "v1.2-315-g1cb9dff",
|
||||
"Rev": "1cb9dff8c37b2918ad1ebd7b294d01100a153d27"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/CenturyLinkCloud/clc-sdk",
|
||||
"Comment": "0.0.2-17-gb0c6106",
|
||||
"Rev": "b0c610652394ae6cac087e1e5d6de187c5f3f258"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/CenturyLinkCloud/clc-sdk/aa",
|
||||
"Comment": "0.0.2-17-gb0c6106",
|
||||
"Rev": "b0c610652394ae6cac087e1e5d6de187c5f3f258"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/CenturyLinkCloud/clc-sdk/alert",
|
||||
"Comment": "0.0.2-17-gb0c6106",
|
||||
"Rev": "b0c610652394ae6cac087e1e5d6de187c5f3f258"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/CenturyLinkCloud/clc-sdk/api",
|
||||
"Comment": "0.0.2-17-gb0c6106",
|
||||
"Rev": "b0c610652394ae6cac087e1e5d6de187c5f3f258"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/CenturyLinkCloud/clc-sdk/dc",
|
||||
"Comment": "0.0.2-17-gb0c6106",
|
||||
"Rev": "b0c610652394ae6cac087e1e5d6de187c5f3f258"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/CenturyLinkCloud/clc-sdk/group",
|
||||
"Comment": "0.0.2-17-gb0c6106",
|
||||
"Rev": "b0c610652394ae6cac087e1e5d6de187c5f3f258"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/CenturyLinkCloud/clc-sdk/lb",
|
||||
"Comment": "0.0.2-17-gb0c6106",
|
||||
"Rev": "b0c610652394ae6cac087e1e5d6de187c5f3f258"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/CenturyLinkCloud/clc-sdk/server",
|
||||
"Comment": "0.0.2-17-gb0c6106",
|
||||
"Rev": "b0c610652394ae6cac087e1e5d6de187c5f3f258"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/CenturyLinkCloud/clc-sdk/status",
|
||||
"Comment": "0.0.2-17-gb0c6106",
|
||||
"Rev": "b0c610652394ae6cac087e1e5d6de187c5f3f258"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/DreamItGetIT/statuscake",
|
||||
"Rev": "8cbe86575f00210a6df2c19cb2f59b00cd181de3"
|
||||
|
@ -814,6 +859,10 @@
|
|||
"ImportPath": "github.com/mattn/go-isatty",
|
||||
"Rev": "56b76bdf51f7708750eac80fa38b952bb9f32639"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mikebeyer/env",
|
||||
"Rev": "b6ce30ccdcad3ed9d5ca80329829f5aeaa856e99"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mitchellh/cli",
|
||||
"Rev": "cb6853d606ea4a12a15ac83cc43503df99fd28fb"
|
||||
|
|
|
@ -3,6 +3,7 @@ package clc
|
|||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
clc "github.com/CenturyLinkCloud/clc-sdk"
|
||||
|
@ -59,18 +60,21 @@ func Provider() terraform.ResourceProvider {
|
|||
func providerConfigure(d *schema.ResourceData) (interface{}, error) {
|
||||
un := d.Get("username").(string)
|
||||
pw := d.Get("password").(string)
|
||||
ac := d.Get("account").(string)
|
||||
url := d.Get("url").(string)
|
||||
|
||||
config, config_err := api.NewConfig(un, pw, ac, url)
|
||||
if config_err != nil {
|
||||
return nil, fmt.Errorf("Failed to create CLC config with provided details: %v", config_err)
|
||||
config, err := api.NewConfig(un, pw)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to create CLC config with provided details: %v", err)
|
||||
}
|
||||
config.UserAgent = "terraform-clc"
|
||||
if urlStr := d.Get("url").(string); urlStr != "" {
|
||||
uri, err := url.Parse(urlStr)
|
||||
if err == nil {
|
||||
config.BaseURL = uri
|
||||
}
|
||||
}
|
||||
config.UserAgent = fmt.Sprintf("terraform-clc terraform/%s", terraform.Version)
|
||||
|
||||
client := clc.New(config)
|
||||
err := client.Authenticate()
|
||||
if err != nil {
|
||||
if err := client.Authenticate(); err != nil {
|
||||
return nil, fmt.Errorf("Failed authenticated with provided credentials: %v", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -137,12 +137,16 @@ func resourceCLCGroupUpdate(d *schema.ResourceData, meta interface{}) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("Failed updating group %v: %v", id, err)
|
||||
}
|
||||
return resource.Retry(1*time.Minute, func() error {
|
||||
return resource.Retry(1*time.Minute, func() *resource.RetryError {
|
||||
_, err := client.Group.Get(id)
|
||||
if err == nil {
|
||||
return resourceCLCGroupRead(d, meta)
|
||||
if err != nil {
|
||||
return resource.RetryableError(err)
|
||||
}
|
||||
return &resource.RetryError{Err: err}
|
||||
err = resourceCLCGroupRead(d, meta)
|
||||
if err != nil {
|
||||
return resource.NonRetryableError(err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -62,12 +62,16 @@ func resourceCLCLoadBalancerCreate(d *schema.ResourceData, meta interface{}) err
|
|||
return fmt.Errorf("Failed creating load balancer under %v/%v: %v", dc, name, err)
|
||||
}
|
||||
d.SetId(l.ID)
|
||||
return resource.Retry(1*time.Minute, func() error {
|
||||
return resource.Retry(1*time.Minute, func() *resource.RetryError {
|
||||
_, err := client.LB.Get(dc, l.ID)
|
||||
if err == nil {
|
||||
return resourceCLCLoadBalancerRead(d, meta)
|
||||
if err != nil {
|
||||
return resource.RetryableError(err)
|
||||
}
|
||||
return &resource.RetryError{Err: err}
|
||||
err = resourceCLCLoadBalancerRead(d, meta)
|
||||
if err != nil {
|
||||
return resource.NonRetryableError(err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
service_name: travis-ci
|
|
@ -0,0 +1,3 @@
|
|||
*.swp
|
||||
*.cov
|
||||
Godeps/_workspace
|
|
@ -0,0 +1,8 @@
|
|||
language: go
|
||||
|
||||
go:
|
||||
- 1.5
|
||||
|
||||
install: make deps
|
||||
script:
|
||||
- make test
|
|
@ -0,0 +1,190 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2015 Mike Beyer
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,12 @@
|
|||
VERSION=0.1
|
||||
|
||||
.PHONY : test cover deps
|
||||
test:
|
||||
godep go test ./...
|
||||
cover:
|
||||
./cover.sh
|
||||
deps:
|
||||
go get github.com/tools/godep
|
||||
go get golang.org/x/tools/cmd/goimports
|
||||
go get github.com/mattn/goveralls
|
||||
godep restore
|
|
@ -0,0 +1,89 @@
|
|||
CLC SDK (for go!) [![Build Status](https://travis-ci.org/CenturyLinkCloud/clc-sdk.svg?branch=master)](https://travis-ci.org/CenturyLinkCloud/clc-sdk) [![Coverage Status](https://coveralls.io/repos/mikebeyer/clc-sdk/badge.svg?branch=master&service=github)](https://coveralls.io/github/mikebeyer/clc-sdk?branch=master)
|
||||
======
|
||||
|
||||
Installation
|
||||
---------------------
|
||||
|
||||
```sh
|
||||
$ go get github.com/CenturyLinkCloud/clc-sdk
|
||||
$ make deps
|
||||
$ make test
|
||||
```
|
||||
|
||||
|
||||
Configuration
|
||||
-------
|
||||
The SDK supports the following helpers for creating your configuration
|
||||
|
||||
|
||||
Reading from the environment
|
||||
|
||||
```go
|
||||
config, _ := api.EnvConfig()
|
||||
```
|
||||
|
||||
Reading from a file
|
||||
|
||||
|
||||
```go
|
||||
config, _ := api.FileConfig("./config.json")
|
||||
|
||||
```
|
||||
|
||||
Direct configuration
|
||||
|
||||
```go
|
||||
config, _ := api.NewConfig(un, pwd)
|
||||
// defaults:
|
||||
config.Alias = "" // resolved on Authentication
|
||||
config.UserAgent = "CenturyLinkCloud/clc-sdk"
|
||||
config.BaseURI = "https://api.ctl.io/v2"
|
||||
|
||||
```
|
||||
|
||||
Enable http wire tracing with env var `DEBUG=on`.
|
||||
|
||||
Additionally, callers of the SDK should set `config.UserAgent` to identify to platform appropriately.
|
||||
|
||||
|
||||
Examples
|
||||
-------
|
||||
To create a new server
|
||||
|
||||
```go
|
||||
client := clc.New(api.EnvConfig())
|
||||
|
||||
server := server.Server{
|
||||
Name: "server",
|
||||
CPU: 1,
|
||||
MemoryGB: 1,
|
||||
GroupID: "GROUP-ID",
|
||||
SourceServerID: "UBUNTU-14-64-TEMPLATE",
|
||||
Type: "standard",
|
||||
}
|
||||
|
||||
resp, _ := client.Server.Create(server)
|
||||
```
|
||||
|
||||
Check status of a server build
|
||||
|
||||
```go
|
||||
resp, _ := client.Server.Create(server)
|
||||
|
||||
status, _ := client.Status.Get(resp.GetStatusID())
|
||||
```
|
||||
|
||||
Async polling for complection
|
||||
|
||||
```go
|
||||
resp, _ := client.Server.Create(server)
|
||||
|
||||
poll := make(chan *status.Response, 1)
|
||||
service.Status.Poll(resp.GetStatusID(), poll)
|
||||
|
||||
status := <- poll
|
||||
```
|
||||
|
||||
License
|
||||
-------
|
||||
This project is licensed under the [Apache License v2.0](http://www.apache.org/licenses/LICENSE-2.0.html).
|
|
@ -0,0 +1,67 @@
|
|||
package aa
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/CenturyLinkCloud/clc-sdk/api"
|
||||
)
|
||||
|
||||
func New(client api.HTTP) *Service {
|
||||
return &Service{
|
||||
client: client,
|
||||
config: client.Config(),
|
||||
}
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
client api.HTTP
|
||||
config *api.Config
|
||||
}
|
||||
|
||||
func (s *Service) Get(id string) (*Policy, error) {
|
||||
url := fmt.Sprintf("%s/antiAffinityPolicies/%s/%s", s.config.BaseURL, s.config.Alias, id)
|
||||
policy := &Policy{}
|
||||
err := s.client.Get(url, policy)
|
||||
return policy, err
|
||||
}
|
||||
|
||||
func (s *Service) GetAll() (*Policies, error) {
|
||||
url := fmt.Sprintf("%s/antiAffinityPolicies/%s", s.config.BaseURL, s.config.Alias)
|
||||
policies := &Policies{}
|
||||
err := s.client.Get(url, policies)
|
||||
return policies, err
|
||||
}
|
||||
|
||||
func (s *Service) Create(name, location string) (*Policy, error) {
|
||||
policy := &Policy{Name: name, Location: location}
|
||||
resp := &Policy{}
|
||||
url := fmt.Sprintf("%s/antiAffinityPolicies/%s", s.config.BaseURL, s.config.Alias)
|
||||
err := s.client.Post(url, policy, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) Update(id string, name string) (*Policy, error) {
|
||||
policy := &Policy{Name: name}
|
||||
resp := &Policy{}
|
||||
url := fmt.Sprintf("%s/antiAffinityPolicies/%s/%s", s.config.BaseURL, s.config.Alias, id)
|
||||
err := s.client.Put(url, policy, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) Delete(id string) error {
|
||||
url := fmt.Sprintf("%s/antiAffinityPolicies/%s/%s", s.config.BaseURL, s.config.Alias, id)
|
||||
err := s.client.Delete(url, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
type Policy struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Location string `json:"location,omitempty"`
|
||||
Links api.Links `json:"links,omitempty"`
|
||||
}
|
||||
|
||||
type Policies struct {
|
||||
Items []Policy `json:"items,omitempty"`
|
||||
Links api.Links `json:"links,omitempty"`
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package alert
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/CenturyLinkCloud/clc-sdk/api"
|
||||
)
|
||||
|
||||
func New(client api.HTTP) *Service {
|
||||
return &Service{
|
||||
client: client,
|
||||
config: client.Config(),
|
||||
}
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
client api.HTTP
|
||||
config *api.Config
|
||||
}
|
||||
|
||||
func (s *Service) Get(id string) (*Alert, error) {
|
||||
url := fmt.Sprintf("%s/alertPolicies/%s/%s", s.config.BaseURL, s.config.Alias, id)
|
||||
resp := &Alert{}
|
||||
err := s.client.Get(url, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) GetAll() (*Alerts, error) {
|
||||
url := fmt.Sprintf("%s/alertPolicies/%s", s.config.BaseURL, s.config.Alias)
|
||||
resp := &Alerts{}
|
||||
err := s.client.Get(url, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) Create(alert Alert) (*Alert, error) {
|
||||
url := fmt.Sprintf("%s/alertPolicies/%s", s.config.BaseURL, s.config.Alias)
|
||||
resp := &Alert{}
|
||||
err := s.client.Post(url, alert, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) Update(id string, alert Alert) (*Alert, error) {
|
||||
url := fmt.Sprintf("%s/alertPolicies/%s/%s", s.config.BaseURL, s.config.Alias, id)
|
||||
resp := &Alert{}
|
||||
err := s.client.Put(url, alert, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) Delete(id string) error {
|
||||
url := fmt.Sprintf("%s/alertPolicies/%s/%s", s.config.BaseURL, s.config.Alias, id)
|
||||
return s.client.Delete(url, nil)
|
||||
}
|
||||
|
||||
type Alerts struct {
|
||||
Items []Alert `json:"items"`
|
||||
Links api.Links `json:"links"`
|
||||
}
|
||||
|
||||
type Alert struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Actions []Action `json:"actions,omitempty"`
|
||||
Triggers []Trigger `json:"triggers,omitempty"`
|
||||
Links api.Links `json:"links,omitempty"`
|
||||
}
|
||||
|
||||
type Action struct {
|
||||
Action string `json:"action"`
|
||||
Setting Setting `json:"settings"`
|
||||
}
|
||||
|
||||
type Setting struct {
|
||||
Recipients []string `json:"recipients"`
|
||||
}
|
||||
|
||||
type Trigger struct {
|
||||
Metric string `json:"metric"`
|
||||
Duration string `json:"duration"`
|
||||
Threshold float64 `json:"threshold"`
|
||||
}
|
|
@ -0,0 +1,235 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"github.com/mikebeyer/env"
|
||||
)
|
||||
|
||||
var debug = os.Getenv("DEBUG") != ""
|
||||
|
||||
const baseUriDefault = "https://api.ctl.io/v2"
|
||||
const userAgentDefault = "CenturyLinkCloud/clc-sdk"
|
||||
|
||||
func New(config Config) *Client {
|
||||
return &Client{
|
||||
config: config,
|
||||
client: http.DefaultClient,
|
||||
}
|
||||
}
|
||||
|
||||
type HTTP interface {
|
||||
Get(url string, resp interface{}) error
|
||||
Post(url string, body, resp interface{}) error
|
||||
Put(url string, body, resp interface{}) error
|
||||
Patch(url string, body, resp interface{}) error
|
||||
Delete(url string, resp interface{}) error
|
||||
Config() *Config
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
config Config
|
||||
Token Token
|
||||
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
func (c *Client) Config() *Config {
|
||||
return &c.config
|
||||
}
|
||||
|
||||
func (c *Client) Get(url string, resp interface{}) error {
|
||||
return c.DoWithAuth("GET", url, nil, resp)
|
||||
}
|
||||
|
||||
func (c *Client) Post(url string, body, resp interface{}) error {
|
||||
return c.DoWithAuth("POST", url, body, resp)
|
||||
}
|
||||
|
||||
func (c *Client) Put(url string, body, resp interface{}) error {
|
||||
return c.DoWithAuth("PUT", url, body, resp)
|
||||
}
|
||||
|
||||
func (c *Client) Patch(url string, body, resp interface{}) error {
|
||||
return c.DoWithAuth("PATCH", url, body, resp)
|
||||
}
|
||||
|
||||
func (c *Client) Delete(url string, resp interface{}) error {
|
||||
return c.DoWithAuth("DELETE", url, nil, resp)
|
||||
}
|
||||
|
||||
func (c *Client) Auth() error {
|
||||
url := fmt.Sprintf("%s/authentication/login", c.config.BaseURL)
|
||||
body, err := c.serialize(c.config.User)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", url, body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = c.Do(req, &c.Token)
|
||||
if err == nil {
|
||||
// set Alias from returned token
|
||||
c.config.Alias = c.Token.Alias
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Client) Do(req *http.Request, ret interface{}) error {
|
||||
if debug {
|
||||
v, _ := httputil.DumpRequest(req, true)
|
||||
log.Println(string(v))
|
||||
}
|
||||
|
||||
req.Header.Add("User-Agent", c.config.UserAgent)
|
||||
req.Header.Add("Accept", "application/json")
|
||||
if req.Body != nil {
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
}
|
||||
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return err
|
||||
}
|
||||
if debug && resp != nil {
|
||||
v, _ := httputil.DumpResponse(resp, true)
|
||||
log.Println(string(v))
|
||||
}
|
||||
if resp.StatusCode >= 400 {
|
||||
b, _ := ioutil.ReadAll(resp.Body)
|
||||
return fmt.Errorf("http err: [%s] - %s", resp.Status, b)
|
||||
}
|
||||
|
||||
if ret == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// FIXME? empty body: check status=204 or content-length=0 before parsing
|
||||
return json.NewDecoder(resp.Body).Decode(ret)
|
||||
}
|
||||
|
||||
func (c *Client) DoWithAuth(method, url string, body, ret interface{}) error {
|
||||
if !c.Token.Valid() {
|
||||
err := c.Auth()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
b, err := c.serialize(body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, url, b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Add("Authorization", "Bearer "+c.Token.Token)
|
||||
|
||||
return c.Do(req, ret)
|
||||
}
|
||||
|
||||
func (c *Client) serialize(body interface{}) (io.Reader, error) {
|
||||
if body == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
b := new(bytes.Buffer)
|
||||
err := json.NewEncoder(b).Encode(body)
|
||||
return b, err
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
User User `json:"user"`
|
||||
Alias string `json:"alias"`
|
||||
BaseURL *url.URL `json:"-"`
|
||||
UserAgent string `json:"agent,omitempty"`
|
||||
}
|
||||
|
||||
func (c Config) Valid() bool {
|
||||
return c.User.Username != "" && c.User.Password != "" && c.BaseURL != nil
|
||||
}
|
||||
|
||||
func EnvConfig() (Config, error) {
|
||||
user := os.Getenv("CLC_USERNAME")
|
||||
pass := os.Getenv("CLC_PASSWORD")
|
||||
config, err := NewConfig(user, pass)
|
||||
if err != nil {
|
||||
return config, err
|
||||
}
|
||||
|
||||
if !config.Valid() {
|
||||
return config, fmt.Errorf("missing environment variables [%s]", config)
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// NewConfig takes credentials and returns a Config object that may be further customized.
|
||||
// Defaults for Alias, BaseURL, and UserAgent will be taken from respective env vars.
|
||||
func NewConfig(username, password string) (Config, error) {
|
||||
alias := os.Getenv("CLC_ALIAS")
|
||||
agent := env.String("CLC_USER_AGENT", userAgentDefault)
|
||||
base := env.String("CLC_BASE_URL", baseUriDefault)
|
||||
uri, err := url.Parse(base)
|
||||
return Config{
|
||||
User: User{
|
||||
Username: username,
|
||||
Password: password,
|
||||
},
|
||||
Alias: alias,
|
||||
BaseURL: uri,
|
||||
UserAgent: agent,
|
||||
}, err
|
||||
}
|
||||
|
||||
func FileConfig(file string) (Config, error) {
|
||||
config := Config{}
|
||||
b, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
return config, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(b, &config)
|
||||
|
||||
u, err := url.Parse(baseUriDefault)
|
||||
config.BaseURL = u
|
||||
return config, err
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
type Token struct {
|
||||
Username string `json:"userName"`
|
||||
Alias string `json:"accountAlias"`
|
||||
Location string `json:"locationAlias"`
|
||||
Roles []string `json:"roles"`
|
||||
Token string `json:"bearerToken"`
|
||||
}
|
||||
|
||||
// TODO: Add some real validation logic
|
||||
func (t Token) Valid() bool {
|
||||
return t.Token != ""
|
||||
}
|
||||
|
||||
type Update struct {
|
||||
Op string `json:"op"`
|
||||
Member string `json:"member"`
|
||||
Value interface{} `json:"value"`
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package api
|
||||
|
||||
type Link struct {
|
||||
Rel string `json:"rel,omitempty"`
|
||||
Href string `json:"href,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Verbs []string `json:"verbs,omitempty"`
|
||||
}
|
||||
|
||||
type Links []Link
|
||||
|
||||
func (l Links) GetID(rel string) (bool, string) {
|
||||
if ok, v := l.GetLink(rel); ok {
|
||||
return true, (*v).ID
|
||||
}
|
||||
return false, ""
|
||||
}
|
||||
|
||||
func (l Links) GetLink(rel string) (bool, *Link) {
|
||||
for _, v := range l {
|
||||
if v.Rel == rel {
|
||||
return true, &v
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
type Customfields struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Value string `json:"value,omitempty"`
|
||||
Displayvalue string `json:"displayValue,omitempty"`
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package clc
|
||||
|
||||
import (
|
||||
"github.com/CenturyLinkCloud/clc-sdk/aa"
|
||||
"github.com/CenturyLinkCloud/clc-sdk/alert"
|
||||
"github.com/CenturyLinkCloud/clc-sdk/api"
|
||||
"github.com/CenturyLinkCloud/clc-sdk/dc"
|
||||
"github.com/CenturyLinkCloud/clc-sdk/group"
|
||||
"github.com/CenturyLinkCloud/clc-sdk/lb"
|
||||
"github.com/CenturyLinkCloud/clc-sdk/server"
|
||||
"github.com/CenturyLinkCloud/clc-sdk/status"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
client *api.Client
|
||||
|
||||
Server *server.Service
|
||||
Status *status.Service
|
||||
AA *aa.Service
|
||||
Alert *alert.Service
|
||||
LB *lb.Service
|
||||
Group *group.Service
|
||||
DC *dc.Service
|
||||
}
|
||||
|
||||
func New(config api.Config) *Client {
|
||||
c := &Client{
|
||||
client: api.New(config),
|
||||
}
|
||||
|
||||
c.Server = server.New(c.client)
|
||||
c.Status = status.New(c.client)
|
||||
c.AA = aa.New(c.client)
|
||||
c.Alert = alert.New(c.client)
|
||||
c.LB = lb.New(c.client)
|
||||
c.Group = group.New(c.client)
|
||||
c.DC = dc.New(c.client)
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) Alias(alias string) *Client {
|
||||
c.client.Config().Alias = alias
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) Authenticate() error {
|
||||
return c.client.Auth()
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
# Automatic checks
|
||||
test -z "$(gofmt -l -w . | tee /dev/stderr)"
|
||||
test -z "$(goimports -l -w . | tee /dev/stderr)"
|
||||
godep go test -race ./...
|
||||
|
||||
# Run test coverage on each subdirectories and merge the coverage profile.
|
||||
|
||||
echo "mode: count" > profile.cov
|
||||
|
||||
# Standard go tooling behavior is to ignore dirs with leading underscors
|
||||
for dir in $(find . -maxdepth 10 -not -path './.git*' -not -path '*/_*' -type d);
|
||||
do
|
||||
if ls $dir/*.go &> /dev/null; then
|
||||
godep go test -covermode=count -coverprofile=$dir/profile.tmp $dir
|
||||
if [ -f $dir/profile.tmp ]
|
||||
then
|
||||
cat $dir/profile.tmp | tail -n +2 >> profile.cov
|
||||
rm $dir/profile.tmp
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
go tool cover -func profile.cov
|
||||
|
||||
goveralls -coverprofile=profile.cov -service=travis-ci -repotoken $COVERALLS_REPO_TOKEN
|
|
@ -0,0 +1,65 @@
|
|||
package dc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/CenturyLinkCloud/clc-sdk/api"
|
||||
)
|
||||
|
||||
func New(client api.HTTP) *Service {
|
||||
return &Service{
|
||||
client: client,
|
||||
config: client.Config(),
|
||||
}
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
client api.HTTP
|
||||
config *api.Config
|
||||
}
|
||||
|
||||
func (s *Service) Get(id string) (*Response, error) {
|
||||
url := fmt.Sprintf("%s/datacenters/%s/%s?groupLinks=true", s.config.BaseURL, s.config.Alias, id)
|
||||
dc := &Response{}
|
||||
err := s.client.Get(url, dc)
|
||||
return dc, err
|
||||
}
|
||||
|
||||
func (s *Service) GetAll() ([]*Response, error) {
|
||||
url := fmt.Sprintf("%s/datacenters/%s", s.config.BaseURL, s.config.Alias)
|
||||
dcs := make([]*Response, 0)
|
||||
err := s.client.Get(url, &dcs)
|
||||
return dcs, err
|
||||
}
|
||||
|
||||
func (s *Service) GetCapabilities(id string) (*CapabilitiesResponse, error) {
|
||||
url := fmt.Sprintf("%s/datacenters/%s/%s/deploymentCapabilities", s.config.BaseURL, s.config.Alias, id)
|
||||
c := &CapabilitiesResponse{}
|
||||
err := s.client.Get(url, c)
|
||||
return c, err
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Links api.Links `json:"links"`
|
||||
}
|
||||
|
||||
type CapabilitiesResponse struct {
|
||||
SupportsPremiumStorage bool `json:"supportsPremiumStorage"`
|
||||
SupportsBareMetalServers bool `json:"supportsBareMetalServers"`
|
||||
SupportsSharedLoadBalancer bool `json:"supportsSharedLoadBalancer"`
|
||||
Templates []struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
StorageSizeGB string `json:"storageSizeGB"`
|
||||
Capabilities []string `json:"capabilities"`
|
||||
ReservedDrivePaths []string `json:"reservedDrivePaths"`
|
||||
} `json:"templates"`
|
||||
DeployableNetworks []struct {
|
||||
Name string `json:"name"`
|
||||
NetworkId string `json:"networkId"`
|
||||
Type string `json:"type"`
|
||||
AccountID string `json:"accountID"`
|
||||
} `json:deployableNetworks`
|
||||
}
|
|
@ -0,0 +1,187 @@
|
|||
package group
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/CenturyLinkCloud/clc-sdk/api"
|
||||
"github.com/CenturyLinkCloud/clc-sdk/status"
|
||||
)
|
||||
|
||||
func New(client api.HTTP) *Service {
|
||||
return &Service{
|
||||
client: client,
|
||||
config: client.Config(),
|
||||
}
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
client api.HTTP
|
||||
config *api.Config
|
||||
}
|
||||
|
||||
func (s *Service) Get(id string) (*Response, error) {
|
||||
url := fmt.Sprintf("%s/groups/%s/%s", s.config.BaseURL, s.config.Alias, id)
|
||||
resp := &Response{}
|
||||
err := s.client.Get(url, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) Create(group Group) (*Response, error) {
|
||||
resp := &Response{}
|
||||
url := fmt.Sprintf("%s/groups/%s", s.config.BaseURL, s.config.Alias)
|
||||
err := s.client.Post(url, group, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) Update(id string, updates ...api.Update) error {
|
||||
url := fmt.Sprintf("%s/groups/%s/%s", s.config.BaseURL, s.config.Alias, id)
|
||||
return s.client.Patch(url, updates, nil)
|
||||
}
|
||||
|
||||
func (s *Service) Delete(id string) (*status.Status, error) {
|
||||
url := fmt.Sprintf("%s/groups/%s/%s", s.config.BaseURL, s.config.Alias, id)
|
||||
resp := &status.Status{}
|
||||
err := s.client.Delete(url, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) Archive(id string) (*status.Status, error) {
|
||||
url := fmt.Sprintf("%s/groups/%s/%s/archive", s.config.BaseURL, s.config.Alias, id)
|
||||
resp := &status.Status{}
|
||||
err := s.client.Post(url, "", resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) Restore(id, intoGroup string) (*status.QueuedResponse, error) {
|
||||
url := fmt.Sprintf("%s/groups/%s/%s/restore", s.config.BaseURL, s.config.Alias, id)
|
||||
resp := &status.QueuedResponse{}
|
||||
body := fmt.Sprintf(`{"targetGroupId": "%v"}`, intoGroup)
|
||||
err := s.client.Post(url, body, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) SetDefaults(id string, defaults *GroupDefaults) error {
|
||||
url := fmt.Sprintf("%s/groups/%s/%s/defaults", s.config.BaseURL, s.config.Alias, id)
|
||||
var resp interface{}
|
||||
err := s.client.Post(url, defaults, resp)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Service) SetHorizontalAutoscalePolicy(id string, policy *HorizontalAutoscalePolicy) (*interface{}, error) {
|
||||
url := fmt.Sprintf("%s/groups/%s/%s/horizontalAutoscalePolicy", s.config.BaseURL, s.config.Alias, id)
|
||||
var resp interface{}
|
||||
err := s.client.Put(url, policy, resp)
|
||||
return &resp, err
|
||||
}
|
||||
|
||||
func UpdateName(name string) api.Update {
|
||||
return api.Update{
|
||||
Op: "set",
|
||||
Member: "name",
|
||||
Value: name,
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateDescription(desc string) api.Update {
|
||||
return api.Update{
|
||||
Op: "set",
|
||||
Member: "description",
|
||||
Value: desc,
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateParentGroupID(id string) api.Update {
|
||||
return api.Update{
|
||||
Op: "set",
|
||||
Member: "parentGroupId",
|
||||
Value: id,
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateCustomfields(fields []api.Customfields) api.Update {
|
||||
return api.Update{
|
||||
Op: "set",
|
||||
Member: "customFields",
|
||||
Value: fields,
|
||||
}
|
||||
}
|
||||
|
||||
// request body for creating groups
|
||||
type Group struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description,omitempty"`
|
||||
ParentGroupID string `json:"parentGroupId"`
|
||||
CustomFields []api.Customfields `json:"customFields,omitempty"`
|
||||
}
|
||||
|
||||
// response body for group get
|
||||
type Response struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Locationid string `json:"locationId"`
|
||||
Type string `json:"type"`
|
||||
Status string `json:"status"`
|
||||
Links api.Links `json:"links"`
|
||||
Groups []Groups `json:"groups"`
|
||||
Changeinfo struct {
|
||||
Createddate time.Time `json:"createdDate"`
|
||||
Createdby string `json:"createdBy"`
|
||||
Modifieddate time.Time `json:"modifiedDate"`
|
||||
Modifiedby string `json:"modifiedBy"`
|
||||
} `json:"changeInfo"`
|
||||
Customfields []api.Customfields `json:"customFields"`
|
||||
}
|
||||
|
||||
func (r *Response) ParentGroupID() string {
|
||||
if ok, link := r.Links.GetLink("parentGroup"); ok {
|
||||
return link.ID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (r *Response) Servers() []string {
|
||||
ids := make([]string, 0)
|
||||
for _, l := range r.Links {
|
||||
if l.Rel == "server" {
|
||||
ids = append(ids, l.ID)
|
||||
}
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
// nested groups under response
|
||||
type Groups struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Locationid string `json:"locationId"`
|
||||
Type string `json:"type"`
|
||||
Status string `json:"status"`
|
||||
Serverscount int `json:"serversCount"`
|
||||
Groups []Groups `json:"groups"`
|
||||
Links api.Links `json:"links"`
|
||||
}
|
||||
|
||||
// request body for /v2/groups/ALIAS/ID/defaults
|
||||
type GroupDefaults struct {
|
||||
CPU string `json:"cpu,omitempty"`
|
||||
MemoryGB string `json:"memoryGB,omitempty"`
|
||||
NetworkID string `json:"networkId,omitempty"`
|
||||
primaryDns string `json:"primaryDns,omitempty"`
|
||||
secondaryDns string `json:"secondaryDns,omitempty"`
|
||||
templateName string `json:"templateName,omitempty"`
|
||||
}
|
||||
|
||||
// request body for /v2/groups/ALIAS/ID/horizontalAutoscalePolicy
|
||||
type HorizontalAutoscalePolicy struct {
|
||||
PolicyId string `json:"policyId,omitempty"`
|
||||
LoadBalancerPool []PoolPolicy `json:"loadBalancerPool,omitempty"`
|
||||
}
|
||||
|
||||
type PoolPolicy struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
PrivatePort int `json:"privatePort,omitempty"`
|
||||
PublicPort int `json:"publicPort,omitempty"`
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
package lb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/CenturyLinkCloud/clc-sdk/api"
|
||||
)
|
||||
|
||||
func New(client api.HTTP) *Service {
|
||||
return &Service{
|
||||
client: client,
|
||||
config: client.Config(),
|
||||
}
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
client api.HTTP
|
||||
config *api.Config
|
||||
}
|
||||
|
||||
func (s *Service) Get(dc, id string) (*LoadBalancer, error) {
|
||||
url := fmt.Sprintf("%s/sharedLoadBalancers/%s/%s/%s", s.config.BaseURL, s.config.Alias, dc, id)
|
||||
resp := &LoadBalancer{}
|
||||
err := s.client.Get(url, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) GetAll(dc string) ([]*LoadBalancer, error) {
|
||||
url := fmt.Sprintf("%s/sharedLoadBalancers/%s/%s", s.config.BaseURL, s.config.Alias, dc)
|
||||
resp := make([]*LoadBalancer, 0)
|
||||
err := s.client.Get(url, &resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) Create(dc string, lb LoadBalancer) (*LoadBalancer, error) {
|
||||
url := fmt.Sprintf("%s/sharedLoadBalancers/%s/%s", s.config.BaseURL, s.config.Alias, dc)
|
||||
resp := &LoadBalancer{}
|
||||
err := s.client.Post(url, lb, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) Update(dc, id string, lb LoadBalancer) error {
|
||||
url := fmt.Sprintf("%s/sharedLoadBalancers/%s/%s/%s", s.config.BaseURL, s.config.Alias, dc, id)
|
||||
err := s.client.Put(url, lb, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Service) Delete(dc, id string) error {
|
||||
url := fmt.Sprintf("%s/sharedLoadBalancers/%s/%s/%s", s.config.BaseURL, s.config.Alias, dc, id)
|
||||
return s.client.Delete(url, nil)
|
||||
}
|
||||
|
||||
func (s *Service) GetPool(dc, lb, pool string) (*Pool, error) {
|
||||
url := fmt.Sprintf("%s/sharedLoadBalancers/%s/%s/%s/pools/%s", s.config.BaseURL, s.config.Alias, dc, lb, pool)
|
||||
resp := &Pool{}
|
||||
err := s.client.Get(url, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) GetAllPools(dc, lb string) ([]*Pool, error) {
|
||||
url := fmt.Sprintf("%s/sharedLoadBalancers/%s/%s/%s/pools", s.config.BaseURL, s.config.Alias, dc, lb)
|
||||
resp := make([]*Pool, 0)
|
||||
err := s.client.Get(url, &resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) CreatePool(dc, lb string, pool Pool) (*Pool, error) {
|
||||
url := fmt.Sprintf("%s/sharedLoadBalancers/%s/%s/%s/pools", s.config.BaseURL, s.config.Alias, dc, lb)
|
||||
resp := &Pool{}
|
||||
err := s.client.Post(url, pool, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) UpdatePool(dc, lb, id string, pool Pool) error {
|
||||
url := fmt.Sprintf("%s/sharedLoadBalancers/%s/%s/%s/pools/%s", s.config.BaseURL, s.config.Alias, dc, lb, id)
|
||||
err := s.client.Put(url, pool, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Service) DeletePool(dc, lb, pool string) error {
|
||||
url := fmt.Sprintf("%s/sharedLoadBalancers/%s/%s/%s/pools/%s", s.config.BaseURL, s.config.Alias, dc, lb, pool)
|
||||
return s.client.Delete(url, nil)
|
||||
}
|
||||
|
||||
func (s *Service) GetAllNodes(dc, lb, pool string) ([]*Node, error) {
|
||||
url := fmt.Sprintf("%s/sharedLoadBalancers/%s/%s/%s/pools/%s/nodes", s.config.BaseURL, s.config.Alias, dc, lb, pool)
|
||||
resp := make([]*Node, 0)
|
||||
err := s.client.Get(url, &resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) UpdateNodes(dc, lb, pool string, nodes ...Node) error {
|
||||
url := fmt.Sprintf("%s/sharedLoadBalancers/%s/%s/%s/pools/%s/nodes", s.config.BaseURL, s.config.Alias, dc, lb, pool)
|
||||
err := s.client.Put(url, nodes, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
type LoadBalancer struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
IPaddress string `json:"ipAddress,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
Pools []Pool `json:"pools,omitempty"`
|
||||
Links api.Links `json:"links,omitempty"`
|
||||
}
|
||||
|
||||
type Pool struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Port int `json:"port,omitempty"`
|
||||
Method Method `json:"method"`
|
||||
Persistence Persistence `json:"persistence"`
|
||||
Nodes []Node `json:"nodes,omitempty"`
|
||||
Links api.Links `json:"links,omitempty"`
|
||||
}
|
||||
|
||||
type Node struct {
|
||||
Status string `json:"status,omitempty"`
|
||||
IPaddress string `json:"ipAddress"`
|
||||
PrivatePort int `json:"privatePort"`
|
||||
}
|
||||
|
||||
type Persistence string
|
||||
|
||||
const (
|
||||
Standard Persistence = "standard"
|
||||
Sticky Persistence = "sticky"
|
||||
)
|
||||
|
||||
type Method string
|
||||
|
||||
const (
|
||||
LeastConn Method = "leastConnection"
|
||||
RoundRobin Method = "roundRobin"
|
||||
)
|
|
@ -0,0 +1,388 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/CenturyLinkCloud/clc-sdk/api"
|
||||
"github.com/CenturyLinkCloud/clc-sdk/status"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidServer = fmt.Errorf("server: server missing required field(s). (Name, CPU, MemoryGB, GroupID, SourceServerID, Type)")
|
||||
)
|
||||
|
||||
func New(client api.HTTP) *Service {
|
||||
return &Service{
|
||||
client: client,
|
||||
config: client.Config(),
|
||||
}
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
client api.HTTP
|
||||
config *api.Config
|
||||
}
|
||||
|
||||
func (s *Service) Get(name string) (*Response, error) {
|
||||
url := fmt.Sprintf("%s/servers/%s/%s", s.config.BaseURL, s.config.Alias, name)
|
||||
if regexp.MustCompile("^[0-9a-f]{32}$").MatchString(name) {
|
||||
url = fmt.Sprintf("%s?uuid=true", url)
|
||||
}
|
||||
resp := &Response{}
|
||||
err := s.client.Get(url, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) Create(server Server) (*status.QueuedResponse, error) {
|
||||
if !server.Valid() {
|
||||
return nil, ErrInvalidServer
|
||||
}
|
||||
|
||||
resp := &status.QueuedResponse{}
|
||||
url := fmt.Sprintf("%s/servers/%s", s.config.BaseURL, s.config.Alias)
|
||||
err := s.client.Post(url, server, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) Update(name string, updates ...api.Update) (*status.Status, error) {
|
||||
resp := &status.Status{}
|
||||
url := fmt.Sprintf("%s/servers/%s/%s", s.config.BaseURL, s.config.Alias, name)
|
||||
err := s.client.Patch(url, updates, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) Edit(name string, updates ...api.Update) error {
|
||||
url := fmt.Sprintf("%s/servers/%s/%s", s.config.BaseURL, s.config.Alias, name)
|
||||
err := s.client.Patch(url, updates, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Service) Delete(name string) (*status.QueuedResponse, error) {
|
||||
url := fmt.Sprintf("%s/servers/%s/%s", s.config.BaseURL, s.config.Alias, name)
|
||||
resp := &status.QueuedResponse{}
|
||||
err := s.client.Delete(url, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) GetCredentials(name string) (Credentials, error) {
|
||||
url := fmt.Sprintf("%s/servers/%s/%s/credentials", s.config.BaseURL, s.config.Alias, name)
|
||||
resp := Credentials{}
|
||||
err := s.client.Get(url, &resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
type Credentials struct {
|
||||
Username string `json:"userName"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
func (s *Service) Archive(servers ...string) ([]*status.QueuedResponse, error) {
|
||||
url := fmt.Sprintf("%s/operations/%s/servers/archive", s.config.BaseURL, s.config.Alias)
|
||||
var resp []*status.QueuedResponse
|
||||
err := s.client.Post(url, servers, &resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) Restore(name, group string) (*status.Status, error) {
|
||||
restore := map[string]string{"targetGroupId": group}
|
||||
url := fmt.Sprintf("%s/servers/%s/%s/restore", s.config.BaseURL, s.config.Alias, name)
|
||||
resp := &status.Status{}
|
||||
err := s.client.Post(url, restore, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) CreateSnapshot(expiration int, servers ...string) ([]*status.QueuedResponse, error) {
|
||||
snapshot := Snapshot{Expiration: expiration, Servers: servers}
|
||||
url := fmt.Sprintf("%s/operations/%s/servers/createSnapshot", s.config.BaseURL, s.config.Alias)
|
||||
var resp []*status.QueuedResponse
|
||||
err := s.client.Post(url, snapshot, &resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) DeleteSnapshot(server, id string) (*status.Status, error) {
|
||||
url := fmt.Sprintf("%s/servers/%s/%s/snapshots/%s", s.config.BaseURL, s.config.Alias, server, id)
|
||||
resp := &status.Status{}
|
||||
err := s.client.Delete(url, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) RevertSnapshot(server, id string) (*status.Status, error) {
|
||||
url := fmt.Sprintf("%s/servers/%s/%s/snapshots/%s/restore", s.config.BaseURL, s.config.Alias, server, id)
|
||||
resp := &status.Status{}
|
||||
err := s.client.Post(url, nil, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
type Snapshot struct {
|
||||
Expiration int `json:"snapshotExpirationDays"`
|
||||
Servers []string `json:"serverIds"`
|
||||
}
|
||||
|
||||
func (s *Service) ExecutePackage(pkg Package, servers ...string) ([]*status.QueuedResponse, error) {
|
||||
url := fmt.Sprintf("%s/operations/%s/servers/executePackage", s.config.BaseURL, s.config.Alias)
|
||||
var resp []*status.QueuedResponse
|
||||
exec := executePackage{Servers: servers, Package: pkg}
|
||||
err := s.client.Post(url, exec, &resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
type executePackage struct {
|
||||
Servers []string `json:"servers"`
|
||||
Package Package `json:"package"`
|
||||
}
|
||||
|
||||
type Package struct {
|
||||
ID string `json:"packageId"`
|
||||
Params map[string]string `json:"parameters"`
|
||||
}
|
||||
|
||||
func (s *Service) PowerState(state PowerState, servers ...string) ([]*status.QueuedResponse, error) {
|
||||
url := fmt.Sprintf("%s/operations/%s/servers/%s", s.config.BaseURL, s.config.Alias, state)
|
||||
var resp []*status.QueuedResponse
|
||||
err := s.client.Post(url, servers, &resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
type PowerState int
|
||||
|
||||
const (
|
||||
On = iota
|
||||
Off
|
||||
Pause
|
||||
Reboot
|
||||
Reset
|
||||
ShutDown
|
||||
StartMaintenance
|
||||
StopMaintenance
|
||||
)
|
||||
|
||||
func (p PowerState) String() string {
|
||||
switch p {
|
||||
case On:
|
||||
return "powerOn"
|
||||
case Off:
|
||||
return "powerOff"
|
||||
case Pause:
|
||||
return "pause"
|
||||
case Reboot:
|
||||
return "reboot"
|
||||
case Reset:
|
||||
return "reset"
|
||||
case ShutDown:
|
||||
return "shutDown"
|
||||
case StartMaintenance:
|
||||
return "startMaintenance"
|
||||
case StopMaintenance:
|
||||
return "stopMaintenance"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (s *Service) GetPublicIP(name string, ip string) (*PublicIP, error) {
|
||||
url := fmt.Sprintf("%s/servers/%s/%s/publicIPAddresses/%s", s.config.BaseURL, s.config.Alias, name, ip)
|
||||
resp := &PublicIP{}
|
||||
err := s.client.Get(url, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) AddPublicIP(name string, ip PublicIP) (*status.Status, error) {
|
||||
url := fmt.Sprintf("%s/servers/%s/%s/publicIPAddresses", s.config.BaseURL, s.config.Alias, name)
|
||||
resp := &status.Status{}
|
||||
err := s.client.Post(url, ip, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) UpdatePublicIP(name string, public string, ip PublicIP) (*status.Status, error) {
|
||||
url := fmt.Sprintf("%s/servers/%s/%s/publicIPAddresses/%s", s.config.BaseURL, s.config.Alias, name, public)
|
||||
resp := &status.Status{}
|
||||
err := s.client.Put(url, ip, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (s *Service) DeletePublicIP(name, ip string) (*status.Status, error) {
|
||||
url := fmt.Sprintf("%s/servers/%s/%s/publicIPAddresses/%s", s.config.BaseURL, s.config.Alias, name, ip)
|
||||
resp := &status.Status{}
|
||||
err := s.client.Delete(url, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
type PublicIP struct {
|
||||
InternalIP string `json:"internalIPAddress,omitempty"`
|
||||
Ports []Port `json:"ports,omitempty"`
|
||||
SourceRestrictions []SourceRestriction `json:"sourceRestrictions,omitempty"`
|
||||
}
|
||||
|
||||
type Port struct {
|
||||
Protocol string `json:"protocol"`
|
||||
Port int `json:"port"`
|
||||
PortTo int `json:"portTo,omitempty"`
|
||||
}
|
||||
|
||||
type SourceRestriction struct {
|
||||
CIDR string `json:"cidr"`
|
||||
}
|
||||
|
||||
type Disk struct {
|
||||
DiskID string `json:"diskId,omitempty"`
|
||||
Path string `json:"path,omitempty"`
|
||||
SizeGB int `json:"sizeGB,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Service) AddSecondaryNetwork(name, networkId, ip string) (*status.Status, error) {
|
||||
url := fmt.Sprintf("%s/servers/%s/%s/networks", s.config.BaseURL, s.config.Alias, name)
|
||||
req := &SecondaryNetwork{
|
||||
NetworkID: networkId,
|
||||
IPAddress: ip,
|
||||
}
|
||||
// returned a non-standard status object, repackage into a proper one
|
||||
resp := &status.QueuedOperation{}
|
||||
err := s.client.Post(url, req, resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp.Status(), nil
|
||||
}
|
||||
|
||||
type SecondaryNetwork struct {
|
||||
NetworkID string `json:"networkId,omitempty"`
|
||||
IPAddress string `json:"ipAddress,omitempty"`
|
||||
}
|
||||
|
||||
func UpdateCPU(num int) api.Update {
|
||||
return api.Update{
|
||||
Op: "set",
|
||||
Member: "cpu",
|
||||
Value: num,
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateMemory(num int) api.Update {
|
||||
return api.Update{
|
||||
Op: "set",
|
||||
Member: "memory",
|
||||
Value: num,
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateCredentials(current, updated string) api.Update {
|
||||
return api.Update{
|
||||
Op: "set",
|
||||
Member: "password",
|
||||
Value: struct {
|
||||
Current string `json:"current"`
|
||||
Password string `json:"password"`
|
||||
}{
|
||||
current,
|
||||
updated,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateGroup(group string) api.Update {
|
||||
return api.Update{
|
||||
Op: "set",
|
||||
Member: "groupId",
|
||||
Value: group,
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateDescription(desc string) api.Update {
|
||||
return api.Update{
|
||||
Op: "set",
|
||||
Member: "description",
|
||||
Value: desc,
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateAdditionaldisks(disks []Disk) api.Update {
|
||||
return api.Update{
|
||||
Op: "set",
|
||||
Member: "disks",
|
||||
Value: disks,
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateCustomfields(fields []api.Customfields) api.Update {
|
||||
return api.Update{
|
||||
Op: "set",
|
||||
Member: "customFields",
|
||||
Value: fields,
|
||||
}
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description,omitempty"`
|
||||
GroupID string `json:"groupId"`
|
||||
SourceServerID string `json:"sourceServerId"`
|
||||
IsManagedOS bool `json:"isManagedOS,omitempty"`
|
||||
PrimaryDNS string `json:"primaryDns,omitempty"`
|
||||
SecondaryDNS string `json:"secondaryDns,omitempty"`
|
||||
NetworkID string `json:"networkId,omitempty"`
|
||||
IPaddress string `json:"ipAddress,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
CPU int `json:"cpu"`
|
||||
MemoryGB int `json:"memoryGB"`
|
||||
Type string `json:"type"`
|
||||
Storagetype string `json:"storageType,omitempty"`
|
||||
Customfields []api.Customfields `json:"customFields,omitempty"`
|
||||
Additionaldisks []Disk `json:"additionalDisks,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Server) Valid() bool {
|
||||
return s.Name != "" && s.CPU != 0 && s.MemoryGB != 0 && s.GroupID != "" && s.SourceServerID != ""
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
GroupID string `json:"groupId"`
|
||||
IsTemplate bool `json:"isTemplate"`
|
||||
LocationID string `json:"locationId"`
|
||||
OStype string `json:"osType"`
|
||||
Status string `json:"status"`
|
||||
Details struct {
|
||||
IPaddresses []struct {
|
||||
Internal string `json:"internal"`
|
||||
Public string `json:"public"`
|
||||
} `json:"ipAddresses"`
|
||||
AlertPolicies []struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Links api.Links `json:"links"`
|
||||
} `json:"alertPolicies"`
|
||||
CPU int `json:"cpu"`
|
||||
Diskcount int `json:"diskCount"`
|
||||
Hostname string `json:"hostName"`
|
||||
InMaintenanceMode bool `json:"inMaintenanceMode"`
|
||||
MemoryMB int `json:"memoryMB"`
|
||||
Powerstate string `json:"powerState"`
|
||||
Storagegb int `json:"storageGB"`
|
||||
Disks []struct {
|
||||
ID string `json:"id"`
|
||||
SizeGB int `json:"sizeGB"`
|
||||
PartitionPaths []interface{} `json:"partitionPaths"`
|
||||
} `json:"disks"`
|
||||
Partitions []struct {
|
||||
SizeGB float64 `json:"sizeGB"`
|
||||
Path string `json:"path"`
|
||||
} `json:"partitions"`
|
||||
Snapshots []struct {
|
||||
Name string `json:"name"`
|
||||
Links api.Links `json:"links"`
|
||||
} `json:"snapshots"`
|
||||
Customfields []api.Customfields `json:"customFields,omitempty"`
|
||||
} `json:"details"`
|
||||
Type string `json:"type"`
|
||||
Storagetype string `json:"storageType"`
|
||||
ChangeInfo struct {
|
||||
CreatedDate string `json:"createdDate"`
|
||||
CreatedBy string `json:"createdBy"`
|
||||
ModifiedDate string `json:"modifiedDate"`
|
||||
ModifiedBy string `json:"modifiedBy"`
|
||||
} `json:"changeInfo"`
|
||||
Links api.Links `json:"links"`
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
package status
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/CenturyLinkCloud/clc-sdk/api"
|
||||
)
|
||||
|
||||
func New(client api.HTTP) *Service {
|
||||
return &Service{
|
||||
client: client,
|
||||
config: client.Config(),
|
||||
PollInterval: 30 * time.Second,
|
||||
}
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
client api.HTTP
|
||||
config *api.Config
|
||||
|
||||
PollInterval time.Duration
|
||||
}
|
||||
|
||||
func (s *Service) Get(id string) (*Response, error) {
|
||||
url := fmt.Sprintf("%s/operations/%s/status/%s", s.config.BaseURL, s.config.Alias, id)
|
||||
status := &Response{}
|
||||
err := s.client.Get(url, status)
|
||||
return status, err
|
||||
}
|
||||
|
||||
func (s *Service) Poll(id string, poll chan *Response) error {
|
||||
for {
|
||||
status, err := s.Get(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !status.Running() {
|
||||
poll <- status
|
||||
return nil
|
||||
}
|
||||
time.Sleep(s.PollInterval)
|
||||
}
|
||||
}
|
||||
|
||||
type Status struct {
|
||||
ID string `json:"id"`
|
||||
Rel string `json:"rel"`
|
||||
Href string `json:"href"`
|
||||
}
|
||||
|
||||
/*
|
||||
Response represents a running async job
|
||||
result from polling status
|
||||
{"status": "succeeded"}
|
||||
*/
|
||||
type Response struct {
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
func (s *Response) Complete() bool {
|
||||
return s.Status == Complete
|
||||
}
|
||||
|
||||
func (s *Response) Failed() bool {
|
||||
return s.Status == Failed
|
||||
}
|
||||
|
||||
func (s *Response) Running() bool {
|
||||
return !s.Complete() && !s.Failed() && s.Status != ""
|
||||
}
|
||||
|
||||
const (
|
||||
Complete = "succeeded"
|
||||
Failed = "failed"
|
||||
)
|
||||
|
||||
/* QueuedResponse represents a returned response for an async platform job
|
||||
eg. create server
|
||||
{"server":"web", "isQueued":true, "links":[
|
||||
{"rel":"status", "href":"...", "id":"wa1-12345"},
|
||||
{"rel":"self", "href":"...", "id":"8134c91a66784c6dada651eba90a5123"}]}
|
||||
*/
|
||||
type QueuedResponse struct {
|
||||
Server string `json:"server,omitempty"`
|
||||
IsQueued bool `json:"isQueued,omitempty"`
|
||||
Links api.Links `json:"links,omitempty"`
|
||||
Error string `json:"errorMessage,omitempty"`
|
||||
}
|
||||
|
||||
func (q *QueuedResponse) GetStatusID() (bool, string) {
|
||||
return q.Links.GetID("status")
|
||||
}
|
||||
|
||||
/* QueuedOperation may be a one-off and/or experimental version of QueuedResponse
|
||||
eg. add secondary network
|
||||
{"operationId": "2b70710dba4142dcaf3ab2de68e4f40c", "uri": "..."}
|
||||
*/
|
||||
type QueuedOperation struct {
|
||||
OperationID string `json:"operationId,omitempty"`
|
||||
URI string `json:"uri,omitempty"`
|
||||
}
|
||||
|
||||
func (q *QueuedOperation) GetStatusID() (bool, string) {
|
||||
return q.OperationID != "", q.OperationID
|
||||
}
|
||||
|
||||
func (q *QueuedOperation) GetHref() (bool, string) {
|
||||
var path = ""
|
||||
if q.URI != "" {
|
||||
u, err := url.Parse(q.URI)
|
||||
if err == nil {
|
||||
path = u.Path
|
||||
}
|
||||
}
|
||||
return path != "", path
|
||||
}
|
||||
|
||||
func (q *QueuedOperation) Status() *Status {
|
||||
st := &Status{}
|
||||
if ok, id := q.GetStatusID(); ok {
|
||||
st.ID = id
|
||||
}
|
||||
if ok, href := q.GetHref(); ok {
|
||||
st.Href = href
|
||||
}
|
||||
return st
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
The MIT License
|
||||
===============
|
||||
|
||||
Copyright (c) 2015 Mike Beyer
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
|
@ -0,0 +1,18 @@
|
|||
env
|
||||
===
|
||||
|
||||
[ ![Codeship Status for mikebeyer/env](https://codeship.io/projects/d046ac90-ae6d-0132-79aa-6a5d0765ab36/status)](https://codeship.io/projects/68901)
|
||||
|
||||
|
||||
Go implementation for default values for environment variables.
|
||||
|
||||
~~~ go
|
||||
package main
|
||||
|
||||
import "github.com/mikebeyer/env"
|
||||
|
||||
func main() {
|
||||
port := env.String("PORT", "8080")
|
||||
fmt.Printf("port: %s", port)
|
||||
}
|
||||
~~~
|
|
@ -0,0 +1,73 @@
|
|||
// Package env provides convenience wrapper around getting environment variables.
|
||||
package env
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// String gets string variable from the environment and
|
||||
// returns it if it exists, otherwise it returns the default.
|
||||
func String(key string, def string) string {
|
||||
val := os.Getenv(key)
|
||||
if val == "" {
|
||||
return def
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// MustString exits if an environment variable is not present.
|
||||
func MustString(key string) string {
|
||||
val := os.Getenv(key)
|
||||
if val == "" {
|
||||
fmt.Printf("%s must be provided.", key)
|
||||
os.Exit(1)
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// Int gets int variable from the environment and
|
||||
// returns it if it exists, otherwise it returns the default.
|
||||
func Int(key string, def int) int {
|
||||
val := os.Getenv(key)
|
||||
if val == "" {
|
||||
return def
|
||||
}
|
||||
|
||||
i, err := strconv.Atoi(val)
|
||||
if err != nil {
|
||||
return def
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// Bool gets boolean variable from the environment and
|
||||
// returns it if it exists, otherwise it returns the default.
|
||||
func Bool(key string, def bool) bool {
|
||||
val := os.Getenv(key)
|
||||
if val == "" {
|
||||
return def
|
||||
}
|
||||
|
||||
b, err := strconv.ParseBool(val)
|
||||
if err != nil {
|
||||
return def
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Float gets float variable with a provided bit type from the environment and
|
||||
// returns it if it exists, otherwise it returns the default.
|
||||
func Float(key string, def float64, bit int) float64 {
|
||||
val := os.Getenv(key)
|
||||
if val == "" {
|
||||
return def
|
||||
}
|
||||
|
||||
f, err := strconv.ParseFloat(val, bit)
|
||||
if err != nil {
|
||||
return def
|
||||
}
|
||||
return f
|
||||
}
|
Loading…
Reference in New Issue