diff --git a/cmd/cca/cca.go b/cmd/cca/cca.go index e728c34..00d7e6d 100644 --- a/cmd/cca/cca.go +++ b/cmd/cca/cca.go @@ -21,6 +21,7 @@ import ( "github.com/cloud-ca/cca/cmd/cca/completion" "github.com/cloud-ca/cca/cmd/cca/version" "github.com/cloud-ca/cca/pkg/cli" + "github.com/cloud-ca/cca/pkg/client" "github.com/cloud-ca/cca/pkg/flags" "github.com/cloud-ca/cca/pkg/output" "github.com/sirupsen/logrus" @@ -44,7 +45,9 @@ func NewCommand() *cobra.Command { if err := flg.Normalize(cmd, viper.Get, args); err != nil { return err } - cli.Flags = flg + cli.GlobalFlags = flg + cli.OutputBuilder = output.NewBuilder(flg.OutputFormat, flg.OutputColored) + cli.CcaClient = client.NewClient(flg.APIURL, flg.APIKey) return nil }, } diff --git a/go.mod b/go.mod index 335f419..5c5d31d 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,12 @@ module github.com/cloud-ca/cca go 1.12 require ( + github.com/cloud-ca/go-cloudca v1.4.0 github.com/lithammer/dedent v1.1.0 github.com/sirupsen/logrus v1.4.2 github.com/spf13/cobra v0.0.5 github.com/spf13/viper v1.4.0 + github.com/tidwall/pretty v1.0.0 + gopkg.in/yaml.v2 v2.2.2 sigs.k8s.io/kind v0.4.0 ) diff --git a/go.sum b/go.sum index b0114af..ad433ac 100644 --- a/go.sum +++ b/go.sum @@ -13,6 +13,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloud-ca/go-cloudca v1.4.0 h1:R8ZWca1EtZrMS3t05Un11LwGX21/phuPp7kpMNT82DU= +github.com/cloud-ca/go-cloudca v1.4.0/go.mod h1:+BpT2i2e5Zn+IDBVcZiqOBrZXSQpo/ObZ/MMTUh/RhI= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= @@ -21,6 +23,7 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= @@ -47,6 +50,7 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -131,9 +135,13 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= @@ -168,6 +176,7 @@ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/pkg/cli/wrapper.go b/pkg/cli/wrapper.go index 3439bfe..a0a362e 100644 --- a/pkg/cli/wrapper.go +++ b/pkg/cli/wrapper.go @@ -16,10 +16,14 @@ package cli import ( + "github.com/cloud-ca/cca/pkg/client" "github.com/cloud-ca/cca/pkg/flags" + "github.com/cloud-ca/cca/pkg/output" ) // Wrapper of different parts of cca cli type Wrapper struct { - Flags *flags.GlobalFlags + GlobalFlags *flags.GlobalFlags + OutputBuilder *output.Builder + CcaClient *client.Client } diff --git a/pkg/client/client.go b/pkg/client/client.go new file mode 100644 index 0000000..58daac4 --- /dev/null +++ b/pkg/client/client.go @@ -0,0 +1,33 @@ +// Copyright © 2019 cloud.ca Authors. +// +// 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. + +// Package client contains the client library to interact with cloud.ca infrastructure +package client + +import ( + gocca "github.com/cloud-ca/go-cloudca" +) + +// Client to interact with cloud.ca infrastructure +type Client struct { + *gocca.CcaClient +} + +// NewClient returns a new client to interact with cloud.ca +// infrastructure with provided API URL and Key +func NewClient(url string, key string) *Client { + return &Client{ + CcaClient: gocca.NewCcaClientWithURL(url, key), + } +} diff --git a/pkg/output/builder.go b/pkg/output/builder.go new file mode 100644 index 0000000..09583b8 --- /dev/null +++ b/pkg/output/builder.go @@ -0,0 +1,41 @@ +// Copyright © 2019 cloud.ca Authors. +// +// 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. + +// Package output contains helper utility to build and format the output +package output + +// Builder is used to prepare the output. It internally +// create a Formatter and use it to print the 'object' +// to different formats and colors (based on the flags) +type Builder struct { + format string + colored bool +} + +// NewBuilder returns a new output.Builder with desired format and colored output +func NewBuilder(format string, colored bool) *Builder { + return &Builder{ + format: format, + colored: colored, + } +} + +// Build builds the callback function to be used directly in cobra.Command +// in order not to pass around private structs from go-cloudca library +func (b *Builder) Build(fn func(*Formatter) error) error { + formatter := &Formatter{ + builder: b, + } + return fn(formatter) +} diff --git a/pkg/output/formatter.go b/pkg/output/formatter.go new file mode 100644 index 0000000..d378782 --- /dev/null +++ b/pkg/output/formatter.go @@ -0,0 +1,74 @@ +// Copyright © 2019 cloud.ca Authors. +// +// 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. + +// Package output contains helper utility to build and format the output +package output + +import ( + "encoding/json" + "fmt" + + "github.com/tidwall/pretty" + yaml "gopkg.in/yaml.v2" +) + +// Formatter is used to format retrieved object to selected +// format and print it out on STDOUT and also colorized it +// if the flag is set. +type Formatter struct { + builder *Builder +} + +// Format prints the representation of input 'object' to +// STDOUT based on the requested 'format' (JSON or YAML). +// The output will also be colorized if flag is set. +func (f *Formatter) Format(object interface{}) error { + builder := f.builder + if builder.format == "json" { + return f.toJSON(object, builder) + } else if builder.format == "yaml" { + return f.toYAML(object, builder) + } + return nil +} + +// toJSON prints the JSON representation of input 'object' +// to STDOUT. The output will be colorized if flag is set. +func (f *Formatter) toJSON(object interface{}, builder *Builder) error { + jsoned, err := json.Marshal(object) + if err != nil { + return err + } + jsoned = pretty.Pretty(jsoned) + if builder.colored { + jsoned = pretty.Color(jsoned, nil) + } + _, err = fmt.Printf("%s", jsoned) + return err +} + +// toYAML prints the YAML representation of input 'object' +// to STDOUT. The output will be colorized if flag is set. +func (f *Formatter) toYAML(object interface{}, builder *Builder) error { + yamled, err := yaml.Marshal(object) + if err != nil { + return err + } + // TODO colorize yaml + // if builder.colored { + // yamled = Color(yamled, nil) + // } + _, err = fmt.Printf("%s", yamled) + return err +} diff --git a/pkg/output/util.go b/pkg/output/types.go similarity index 92% rename from pkg/output/util.go rename to pkg/output/types.go index be2e934..7da5fb7 100644 --- a/pkg/output/util.go +++ b/pkg/output/types.go @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Package output contains helper utility to build and format the output package output import ( @@ -20,7 +21,7 @@ import ( var outputFormats = []string{"json", "yaml"} -// Get return available output formats +// Get returns available output formats func Get() []string { return outputFormats } @@ -49,5 +50,4 @@ func FormatStrings() string { } b.WriteString("]") return b.String() - } diff --git a/vendor/github.com/cloud-ca/go-cloudca/.gometalinter.json b/vendor/github.com/cloud-ca/go-cloudca/.gometalinter.json new file mode 100644 index 0000000..d179497 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/.gometalinter.json @@ -0,0 +1,27 @@ +{ + "Concurrency": 2, + "Deadline": "10m", + "DisableAll": true, + "EnableGC": true, + "Enable": [ + "vet", + "golint", + "varcheck", + "structcheck", + "staticcheck", + "errcheck", + "misspell", + "unconvert" + ], + "Exclude": [ + "composite literal uses unkeyed fields" + ], + "Linters": { + }, + "Sort": [ + "path", + "line" + ], + "Vendor": true, + "WarnUnmatchedDirective": true +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/LICENSE b/vendor/github.com/cloud-ca/go-cloudca/LICENSE new file mode 100644 index 0000000..1c81b1c --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 CloudOps + +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. diff --git a/vendor/github.com/cloud-ca/go-cloudca/Makefile b/vendor/github.com/cloud-ca/go-cloudca/Makefile new file mode 100644 index 0000000..dcf64d3 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/Makefile @@ -0,0 +1,115 @@ +# Project variables +NAME := go-cloudca +DESCRIPTION := A cloud.ca client for the Go programming language +VENDOR := cloud.ca +URL := https://github.com/cloud-ca/go-cloudca +LICENSE := MIT + +# Build variables +BUILD_DIR := bin +COMMIT_HASH := $(shell git rev-parse --short HEAD 2>/dev/null) +VERSION := $(shell git describe --tags --exact-match 2>/dev/null || git describe --tags 2>/dev/null || echo "v0.0.0-$(COMMIT_HASH)") +BUILD_DATE := $(shell date +%FT%T%z) + +# Go variables +GOPKGS := $(shell go list ./... | grep -v /vendor) +GOFILES := $(shell find . -type f -name '*.go' -not -path "./vendor/*") + +# General variables +BLUE_COLOR := \033[36m +NO_COLOR := \033[0m + +.PHONY: version +version: ## Show version of provider + @echo "$(NAME) - $(VERSION) - $(BUILD_DATE)" + +######################### +## Development targets ## +######################### +.PHONY: clean +clean: log-clean ## Clean builds + rm -rf ./$(BUILD_DIR) $(NAME) + +.PHONY: vendor +vendor: log-vendor ## Install 'vendor' dependencies + GO111MODULE=on go mod vendor + +.PHONY: verify +verify: log-verify ## Verify 'vendor' dependencies + GO111MODULE=on go mod verify + +.PHONY: lint +lint: log-lint ## Run linter + @bash -c "GO111MODULE=off gometalinter -d ./... 2> >(egrep '(^DEBUG.*linter took|^DEBUG.*total elapsed|^[^D])' >&2)" + +.PHONY: format +format: log-format ## Format all go files + go fmt $(GOPKGS) + +.PHONY: checkfmt +checkfmt: SHELL :=/bin/bash +checkfmt: RESULT = $(shell gofmt -l $(GOFILES) | tee >(if [ "$$(wc -l)" = 0 ]; then echo "OK"; fi)) +checkfmt: log-checkfmt ## Check formatting of all go files + @echo "$(RESULT)" + @if [ "$(RESULT)" != "OK" ]; then exit 1; fi + +.PHONY: test +test: log-test ## Run tests + go test -v $(GOPKGS) + +.PHONY: tools +tools: log-tools ## Install required tools + @cd $$GOPATH && curl -L https://git.io/vp6lP | sh # gometalinter + @cd /tmp && go get -v -u github.com/git-chglog/git-chglog/cmd/git-chglog # git-chglog + +##################### +## Release targets ## +##################### +.PHONY: authors +authors: log-authors ## Generate list of Authors + @echo "# Authors\n" > AUTHORS.md + git log --all --format='- %aN \<%aE\>' | sort -u | egrep -v noreply >> AUTHORS.md + +.PHONY: changelog +changelog: log-changelog ## Generate content of Changelog + git-chglog --output CHANGELOG.md + +.PHONY: release patch minor major +PATTERN = + +release: version ?= $(shell echo $(VERSION) | sed 's/^v//' | awk -F'[ .]' '{print $(PATTERN)}') +release: push ?= false +release: SHELL :=/bin/bash +release: log-release ## Prepare Module release + @ if [ -z "$(version)" ]; then \ + echo "Error: missing value for 'version'. e.g. 'make release version=x.y.z'"; \ + elif [ "v$(version)" = "$(VERSION)" ] ; then \ + echo "Error: provided version (v$(version)) exists."; \ + else \ + git tag --annotate --message "v$(version) Release" v$(version); \ + echo "Tag v$(version) Release"; \ + if [ $(push) = "true" ]; then \ + git push origin v$(version); \ + echo "Push v$(version) Release"; \ + fi \ + fi + +patch: PATTERN = '\$$1\".\"\$$2\".\"\$$3+1' +patch: release ## Prepare Module Patch release + +minor: PATTERN = '\$$1\".\"\$$2+1\".0\"' +minor: release ## Prepare Module Minor release + +major: PATTERN = '\$$1+1\".0.0\"' +major: release ## Prepare Module Major release + +#################################### +## Self-Documenting Makefile Help ## +#################################### +.PHONY: help +.DEFAULT_GOAL := help +help: + @grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "$(BLUE_COLOR)%-20s$(NO_COLOR) %s\n", $$1, $$2}' + +log-%: + @grep -h -E '^$*:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "$(BLUE_COLOR)==> %s$(NO_COLOR)\n", $$2}' diff --git a/vendor/github.com/cloud-ca/go-cloudca/README.md b/vendor/github.com/cloud-ca/go-cloudca/README.md new file mode 100644 index 0000000..620b232 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/README.md @@ -0,0 +1,118 @@ +# go-cloudca + +[![GoDoc](https://godoc.org/github.com/cloud-ca/go-cloudca?status.svg)](https://godoc.org/github.com/cloud-ca/go-cloudca) +[![Build Status](https://circleci.com/gh/cloud-ca/go-cloudca.svg?style=svg)](https://circleci.com/gh/cloud-ca/go-cloudca) +[![license](https://img.shields.io/github/license/cloud-ca/go-cloudca.svg)](https://github.com/cloud-ca/go-cloudca/blob/master/LICENSE) + +A cloud.ca client for the Go programming language + +## How to use + +Import + +```go +import "github.com/cloud-ca/go-cloudca" + +/* import the services you need */ +import "github.com/cloud-ca/go-cloudca/services/cloudca" +``` + +Create a new CcaClient. + +```go +ccaClient := cca.NewCcaClient("[your-api-key]") +``` + +Retrieve the list of environments + +```go +environments, _ := ccaClient.Environments.List() +``` + +Get the ServiceResources object for a specific environment and service. Here, we assume that it is a cloudca service. + +```go +resources, _ := ccaClient.GetResources("[service-code]", "[environment-name]") +ccaResources := resources.(cloudca.Resources) +``` + +Now with the cloudca ServiceResources object, we can execute operations on cloudca resources in the specified environment. + +Retrieve the list of instances in the environment. + +```go +instances, _ := ccaResources.Instances.List() +``` + +Get a specific volume in the environment. + +```go +volume, _ := ccaResources.Volumes.Get("[some-volume-id]") +``` + +Create a new instance in the environment. + +```go +createdInstance, _ := ccaResources.Instances.Create(cloudca.Instance{ + Name: "[new-instance-name]", + TemplateId: "[some-template-id]", + ComputeOfferingId:"[some-compute-offering-id]", + NetworkId:"[some-network-id]", +}) +``` + +## Handling Errors + +When trying to get a volume with a bogus id, an error will be returned. + +```go +// Get a volume with a bogus id +_, err := ccaResources.Volumes.Get("[some-volume-id]") +``` + +Two types of error can occur: an unexpected error (ex: unable to connect to server) or an API error (ex: service resource not found) +If an error has occured, then we first try to cast the error into a CcaErrorResponse. This object contains the HTTP status code returned by the server, an error code and a list of CcaError objects. If it's not a CcaErrorResponse, then the error was not returned by the API. + +```go +if err != nil { + if errorResponse, ok := err.(api.CcaErrorResponse); ok { + if errorResponse.StatusCode == api.NOT_FOUND { + fmt.Println("Volume was not found") + } else { + // Can get more details from the CcaErrors + fmt.Println(errorResponse.Errors) + } + } else { + // handle unexpected error + panic("Unexpected error") + } +} +``` + +## License + +This project is licensed under the terms of the MIT license. + +```txt +The MIT License (MIT) + +Copyright (c) 2019 cloud.ca + +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. +``` diff --git a/vendor/github.com/cloud-ca/go-cloudca/api/api.go b/vendor/github.com/cloud-ca/go-cloudca/api/api.go new file mode 100644 index 0000000..bd00e53 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/api/api.go @@ -0,0 +1,88 @@ +package api + +import ( + "bytes" + "crypto/tls" + "io" + "net/http" + "net/url" + "strings" +) + +type ApiClient interface { + Do(request CcaRequest) (*CcaResponse, error) + GetApiURL() string + GetApiKey() string +} + +type CcaApiClient struct { + apiURL string + apiKey string + httpClient *http.Client +} + +const API_KEY_HEADER = "MC-Api-Key" + +func NewApiClient(apiURL, apiKey string) ApiClient { + return CcaApiClient{ + apiURL: apiURL, + apiKey: apiKey, + httpClient: &http.Client{}, + } +} + +func NewInsecureApiClient(apiURL, apiKey string) ApiClient { + tr := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + return CcaApiClient{ + apiURL: apiURL, + apiKey: apiKey, + httpClient: &http.Client{Transport: tr}, + } +} + +//Build a URL by using endpoint and options. Options will be set as query parameters. +func (ccaClient CcaApiClient) buildUrl(endpoint string, options map[string]string) string { + query := url.Values{} + if options != nil { + for k, v := range options { + query.Add(k, v) + } + } + u, _ := url.Parse(ccaClient.apiURL + "/" + strings.Trim(endpoint, "/") + "?" + query.Encode()) + return u.String() +} + +//Does the API call to server and returns a CCAResponse. Cloud.ca errors will be returned in the +//CCAResponse body, not in the error return value. The error return value is reserved for unexpected errors. +func (ccaClient CcaApiClient) Do(request CcaRequest) (*CcaResponse, error) { + var bodyBuffer io.Reader + if request.Body != nil { + bodyBuffer = bytes.NewBuffer(request.Body) + } + method := request.Method + if method == "" { + method = "GET" + } + req, err := http.NewRequest(request.Method, ccaClient.buildUrl(request.Endpoint, request.Options), bodyBuffer) + if err != nil { + return nil, err + } + req.Header.Add(API_KEY_HEADER, ccaClient.apiKey) + req.Header.Add("Content-Type", "application/json") + resp, err := ccaClient.httpClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + return NewCcaResponse(resp) +} + +func (ccaClient CcaApiClient) GetApiKey() string { + return ccaClient.apiKey +} + +func (ccaClient CcaApiClient) GetApiURL() string { + return ccaClient.apiURL +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/api/request.go b/vendor/github.com/cloud-ca/go-cloudca/api/request.go new file mode 100644 index 0000000..3697532 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/api/request.go @@ -0,0 +1,17 @@ +package api + +//HTTP Methods +const ( + GET = "GET" + POST = "POST" + DELETE = "DELETE" + PUT = "PUT" +) + +//A request object +type CcaRequest struct { + Method string + Endpoint string + Body []byte + Options map[string]string +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/api/response.go b/vendor/github.com/cloud-ca/go-cloudca/api/response.go new file mode 100644 index 0000000..7a2b9da --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/api/response.go @@ -0,0 +1,93 @@ +package api + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "strconv" +) + +//Status codes +const ( + OK = 200 + MUTIPLE_CHOICES = 300 + BAD_REQUEST = 400 + NOT_FOUND = 404 +) + +//An API error +type CcaError struct { + ErrorCode string `json:"errorCode"` + Message string `json:"message"` + Context map[string]interface{} `json:"context"` +} + +//An Api Response +type CcaResponse struct { + TaskId string + TaskStatus string + StatusCode int + Data []byte + Errors []CcaError + MetaData map[string]interface{} +} + +//Returns true if API response has errors +func (ccaResponse CcaResponse) IsError() bool { + return !isInOKRange(ccaResponse.StatusCode) +} + +//An Api Response with errors +type CcaErrorResponse CcaResponse + +func (errorResponse CcaErrorResponse) Error() string { + var errorStr string = "[ERROR] Received HTTP status code " + strconv.Itoa(errorResponse.StatusCode) + "\n" + for _, e := range errorResponse.Errors { + context, _ := json.Marshal(e.Context) + errorStr += "[ERROR] Error Code: " + e.ErrorCode + ", Message: " + e.Message + ", Context: " + string(context) + "\n" + } + return errorStr +} + +func NewCcaResponse(response *http.Response) (*CcaResponse, error) { + respBody, err := ioutil.ReadAll(response.Body) + if err != nil { + return nil, err + } + ccaResponse := CcaResponse{} + ccaResponse.StatusCode = response.StatusCode + responseMap := map[string]*json.RawMessage{} + json.Unmarshal(respBody, &responseMap) + + if val, ok := responseMap["taskId"]; ok { + json.Unmarshal(*val, &ccaResponse.TaskId) + } + + if val, ok := responseMap["taskStatus"]; ok { + json.Unmarshal(*val, &ccaResponse.TaskStatus) + } + + if val, ok := responseMap["data"]; ok { + ccaResponse.Data = []byte(*val) + } + + if val, ok := responseMap["metadata"]; ok { + metadata := map[string]interface{}{} + json.Unmarshal(*val, &metadata) + ccaResponse.MetaData = metadata + } + + if val, ok := responseMap["errors"]; ok { + errors := []CcaError{} + json.Unmarshal(*val, &errors) + ccaResponse.Errors = errors + } else if !isInOKRange(response.StatusCode) { + return nil, fmt.Errorf("Unexpected. Received status " + response.Status + " but no errors in response body") + } + return &ccaResponse, nil +} + +func isInOKRange(statusCode int) bool { + return statusCode >= OK && statusCode < MUTIPLE_CHOICES +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/client.go b/vendor/github.com/cloud-ca/go-cloudca/client.go new file mode 100644 index 0000000..b087c24 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/client.go @@ -0,0 +1,72 @@ +package cca + +import ( + "github.com/cloud-ca/go-cloudca/api" + "github.com/cloud-ca/go-cloudca/configuration" + "github.com/cloud-ca/go-cloudca/services" + "github.com/cloud-ca/go-cloudca/services/cloudca" +) + +const ( + DEFAULT_API_URL = "https://api.cloud.ca/v1/" +) + +type CcaClient struct { + apiClient api.ApiClient + Tasks services.TaskService + Environments configuration.EnvironmentService + Users configuration.UserService + ServiceConnections configuration.ServiceConnectionService + Organizations configuration.OrganizationService +} + +//Create a CcaClient with the default URL +func NewCcaClient(apiKey string) *CcaClient { + return NewCcaClientWithURL(DEFAULT_API_URL, apiKey) +} + +//Create a CcaClient with a custom URL +func NewCcaClientWithURL(apiURL string, apiKey string) *CcaClient { + apiClient := api.NewApiClient(apiURL, apiKey) + return NewCcaClientWithApiClient(apiClient) +} + +//Create a CcaClient with a custom URL that accepts insecure connections +func NewInsecureCcaClientWithURL(apiURL string, apiKey string) *CcaClient { + apiClient := api.NewInsecureApiClient(apiURL, apiKey) + return NewCcaClientWithApiClient(apiClient) +} + +func NewCcaClientWithApiClient(apiClient api.ApiClient) *CcaClient { + ccaClient := CcaClient{ + apiClient: apiClient, + Tasks: services.NewTaskService(apiClient), + Environments: configuration.NewEnvironmentService(apiClient), + Users: configuration.NewUserService(apiClient), + ServiceConnections: configuration.NewServiceConnectionService(apiClient), + Organizations: configuration.NewOrganizationService(apiClient), + } + return &ccaClient +} + +//Get the Resources for a specific serviceCode and environmentName +//For now it assumes that the serviceCode belongs to a cloud.ca service type +func (c CcaClient) GetResources(serviceCode string, environmentName string) (services.ServiceResources, error) { + //TODO: change to check service type of service code + return cloudca.NewResources(c.apiClient, serviceCode, environmentName), nil +} + +//Get the API url used to do he calls +func (c CcaClient) GetApiURL() string { + return c.apiClient.GetApiURL() +} + +//Get the API key used in the calls +func (c CcaClient) GetApiKey() string { + return c.apiClient.GetApiKey() +} + +//Get the API Client used by all the services +func (c CcaClient) GetApiClient() api.ApiClient { + return c.apiClient +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/configuration/configuration.go b/vendor/github.com/cloud-ca/go-cloudca/configuration/configuration.go new file mode 100644 index 0000000..b7d4b7b --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/configuration/configuration.go @@ -0,0 +1,113 @@ +package configuration + +import ( + "github.com/cloud-ca/go-cloudca/api" +) + +type ConfigurationService interface { + Get(id string, options map[string]string) ([]byte, error) + List(options map[string]string) ([]byte, error) + Create(body []byte, options map[string]string) ([]byte, error) + Update(id string, body []byte, options map[string]string) ([]byte, error) + Delete(id string, body []byte, options map[string]string) ([]byte, error) +} + +//Implementation of the ConfigurationService +type ConfigurationApi struct { + apiClient api.ApiClient + configurationType string +} + +func NewConfigurationService(apiClient api.ApiClient, configurationType string) ConfigurationService { + return &ConfigurationApi{ + apiClient: apiClient, + configurationType: configurationType, + } +} + +func (configurationApi *ConfigurationApi) buildEndpoint() string { + return "/" + configurationApi.configurationType +} + +//Get. Returns a []byte (of a json object) that should be unmarshalled to a specific entity +func (configurationApi *ConfigurationApi) Get(id string, options map[string]string) ([]byte, error) { + request := api.CcaRequest{ + Method: api.GET, + Endpoint: configurationApi.buildEndpoint() + "/" + id, + Options: options, + } + response, err := configurationApi.apiClient.Do(request) + if err != nil { + return nil, err + } else if response.IsError() { + return nil, api.CcaErrorResponse(*response) + } + return response.Data, nil +} + +//Get list. Returns a []byte (of a json object) that should be unmarshalled to a specific entity +func (configurationApi *ConfigurationApi) List(options map[string]string) ([]byte, error) { + request := api.CcaRequest{ + Method: api.GET, + Endpoint: configurationApi.buildEndpoint(), + Options: options, + } + response, err := configurationApi.apiClient.Do(request) + if err != nil { + return nil, err + } else if response.IsError() { + return nil, api.CcaErrorResponse(*response) + } + return response.Data, nil +} + +//Create as described in the body parameter (json object). Returns a []byte (of a json object) that should be unmarshalled to a specific entity +func (configurationApi *ConfigurationApi) Create(body []byte, options map[string]string) ([]byte, error) { + request := api.CcaRequest{ + Method: api.POST, + Body: body, + Endpoint: configurationApi.buildEndpoint(), + Options: options, + } + response, err := configurationApi.apiClient.Do(request) + if err != nil { + return nil, err + } else if response.IsError() { + return nil, api.CcaErrorResponse(*response) + } + return response.Data, nil +} + +//Update specified id as described in the body parameter (json object). Returns a []byte (of a json object) that should be unmarshalled to a specific entity +func (configurationApi *ConfigurationApi) Update(id string, body []byte, options map[string]string) ([]byte, error) { + request := api.CcaRequest{ + Method: api.PUT, + Body: body, + Endpoint: configurationApi.buildEndpoint() + "/" + id, + Options: options, + } + response, err := configurationApi.apiClient.Do(request) + if err != nil { + return nil, err + } else if response.IsError() { + return nil, api.CcaErrorResponse(*response) + } + return response.Data, nil +} + +//Delete. A body (json object) can be provided if some fields must be sent to server. Returns a []byte (of a json object) that should be unmarshalled to a specific entity +func (configurationApi ConfigurationApi) Delete(id string, body []byte, options map[string]string) ([]byte, error) { + request := api.CcaRequest{ + Method: api.DELETE, + Body: body, + Endpoint: configurationApi.buildEndpoint() + "/" + id, + Options: options, + } + response, err := configurationApi.apiClient.Do(request) + if err != nil { + return nil, err + } else if response.IsError() { + return nil, api.CcaErrorResponse(*response) + } + return response.Data, nil +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/configuration/environment.go b/vendor/github.com/cloud-ca/go-cloudca/configuration/environment.go new file mode 100644 index 0000000..e2414ed --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/configuration/environment.go @@ -0,0 +1,105 @@ +package configuration + +import ( + "encoding/json" + + "github.com/cloud-ca/go-cloudca/api" +) + +const ( + ENVIRONMENT_CONFIGURATION_TYPE = "environments" +) + +type Environment struct { + Id string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + Organization Organization `json:"organization,omitempty"` + ServiceConnection ServiceConnection `json:"serviceConnection,omitempty"` + Users []User `json:"users"` + Roles []Role `json:"roles"` +} + +type EnvironmentService interface { + Get(id string) (*Environment, error) + List() ([]Environment, error) + ListWithOptions(options map[string]string) ([]Environment, error) + Create(environment Environment) (*Environment, error) + Update(id string, environment Environment) (*Environment, error) + Delete(id string) (bool, error) +} + +type EnvironmentApi struct { + configurationService ConfigurationService +} + +func NewEnvironmentService(apiClient api.ApiClient) EnvironmentService { + return &EnvironmentApi{ + configurationService: NewConfigurationService(apiClient, ENVIRONMENT_CONFIGURATION_TYPE), + } +} + +func parseEnvironment(data []byte) *Environment { + environment := Environment{} + json.Unmarshal(data, &environment) + return &environment +} + +func parseEnvironmentList(data []byte) []Environment { + environments := []Environment{} + json.Unmarshal(data, &environments) + return environments +} + +//Get environment with the specified id +func (environmentApi *EnvironmentApi) Get(id string) (*Environment, error) { + data, err := environmentApi.configurationService.Get(id, map[string]string{}) + if err != nil { + return nil, err + } + return parseEnvironment(data), nil +} + +//List all environments +func (environmentApi *EnvironmentApi) List() ([]Environment, error) { + return environmentApi.ListWithOptions(map[string]string{}) +} + +//List all instances for the current environment. Can use options to do sorting and paging. +func (environmentApi *EnvironmentApi) ListWithOptions(options map[string]string) ([]Environment, error) { + data, err := environmentApi.configurationService.List(options) + if err != nil { + return nil, err + } + return parseEnvironmentList(data), nil +} + +//Create environment +func (environmentApi *EnvironmentApi) Create(environment Environment) (*Environment, error) { + send, merr := json.Marshal(environment) + if merr != nil { + return nil, merr + } + body, err := environmentApi.configurationService.Create(send, map[string]string{}) + if err != nil { + return nil, err + } + return parseEnvironment(body), nil +} + +func (environmentApi *EnvironmentApi) Update(id string, environment Environment) (*Environment, error) { + send, merr := json.Marshal(environment) + if merr != nil { + return nil, merr + } + body, err := environmentApi.configurationService.Update(id, send, map[string]string{}) + if err != nil { + return nil, err + } + return parseEnvironment(body), nil +} + +func (environmentApi *EnvironmentApi) Delete(id string) (bool, error) { + _, err := environmentApi.configurationService.Delete(id, []byte{}, map[string]string{}) + return err == nil, err +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/configuration/organization.go b/vendor/github.com/cloud-ca/go-cloudca/configuration/organization.go new file mode 100644 index 0000000..22f1bef --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/configuration/organization.go @@ -0,0 +1,66 @@ +package configuration + +import ( + "encoding/json" + + "github.com/cloud-ca/go-cloudca/api" +) + +type Organization struct { + Id string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + EntryPoint string `json:"entryPoint,omitempty"` + Users []User `json:"users"` + Environments []Environment `json:"environments"` + Roles []Role `json:"roles"` +} + +type OrganizationService interface { + Get(id string) (*Organization, error) + List() ([]Organization, error) + ListWithOptions(options map[string]string) ([]Organization, error) +} + +type OrganizationApi struct { + configurationService ConfigurationService +} + +func NewOrganizationService(apiClient api.ApiClient) OrganizationService { + return &OrganizationApi{ + configurationService: NewConfigurationService(apiClient, "organizations"), + } +} + +func parseOrganization(data []byte) *Organization { + organization := Organization{} + json.Unmarshal(data, &organization) + return &organization +} + +func parseOrganizationList(data []byte) []Organization { + organizations := []Organization{} + json.Unmarshal(data, &organizations) + return organizations +} + +func (organizationApi *OrganizationApi) Get(id string) (*Organization, error) { + data, err := organizationApi.configurationService.Get(id, map[string]string{}) + if err != nil { + return nil, err + } + return parseOrganization(data), nil +} + +//List all organizations +func (organizationApi *OrganizationApi) List() ([]Organization, error) { + return organizationApi.ListWithOptions(map[string]string{}) +} + +//List all organizations. Can use options to do sorting and paging. +func (organizationApi *OrganizationApi) ListWithOptions(options map[string]string) ([]Organization, error) { + data, err := organizationApi.configurationService.List(options) + if err != nil { + return nil, err + } + return parseOrganizationList(data), nil +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/configuration/role.go b/vendor/github.com/cloud-ca/go-cloudca/configuration/role.go new file mode 100644 index 0000000..ff9ff86 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/configuration/role.go @@ -0,0 +1,9 @@ +package configuration + +type Role struct { + Id string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Environment Environment `json:"environment,omitempty"` + Users []User `json:"users"` + Organization Organization `json:"organization,omitempty"` +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/configuration/service_connection.go b/vendor/github.com/cloud-ca/go-cloudca/configuration/service_connection.go new file mode 100644 index 0000000..9cbe494 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/configuration/service_connection.go @@ -0,0 +1,62 @@ +package configuration + +import ( + "encoding/json" + "github.com/cloud-ca/go-cloudca/api" +) + +type ServiceConnection struct { + Id string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + ServiceCode string `json:"serviceCode,omitempty"` +} + +type ServiceConnectionService interface { + Get(id string) (*ServiceConnection, error) + List() ([]ServiceConnection, error) + ListWithOptions(options map[string]string) ([]ServiceConnection, error) +} + +type ServiceConnectionApi struct { + configurationService ConfigurationService +} + +func NewServiceConnectionService(apiClient api.ApiClient) ServiceConnectionService { + return &ServiceConnectionApi{ + configurationService: NewConfigurationService(apiClient, "services/connections"), + } +} + +func parseServiceConnection(data []byte) *ServiceConnection { + service_connection := ServiceConnection{} + json.Unmarshal(data, &service_connection) + return &service_connection +} + +func parseServiceConnectionList(data []byte) []ServiceConnection { + service_connections := []ServiceConnection{} + json.Unmarshal(data, &service_connections) + return service_connections +} + +func (serviceConnectionApi *ServiceConnectionApi) Get(id string) (*ServiceConnection, error) { + data, err := serviceConnectionApi.configurationService.Get(id, map[string]string{}) + if err != nil { + return nil, err + } + return parseServiceConnection(data), nil +} + +//List all service connections +func (serviceConnectionApi *ServiceConnectionApi) List() ([]ServiceConnection, error) { + return serviceConnectionApi.ListWithOptions(map[string]string{}) +} + +//List all service connections. Can use options to do sorting and paging. +func (serviceConnectionApi *ServiceConnectionApi) ListWithOptions(options map[string]string) ([]ServiceConnection, error) { + data, err := serviceConnectionApi.configurationService.List(options) + if err != nil { + return nil, err + } + return parseServiceConnectionList(data), nil +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/configuration/user.go b/vendor/github.com/cloud-ca/go-cloudca/configuration/user.go new file mode 100644 index 0000000..a35d900 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/configuration/user.go @@ -0,0 +1,64 @@ +package configuration + +import ( + "encoding/json" + "github.com/cloud-ca/go-cloudca/api" +) + +type User struct { + Id string `json:"id,omitempty"` + Username string `json:"username,omitempty"` + Roles []Role `json:"roles"` + Organization Organization `json:"organization,omitempty"` +} + +type UserService interface { + Get(id string) (*User, error) + List() ([]User, error) + ListWithOptions(options map[string]string) ([]User, error) +} + +type UserApi struct { + configurationService ConfigurationService +} + +func NewUserService(apiClient api.ApiClient) UserService { + return &UserApi{ + configurationService: NewConfigurationService(apiClient, "users"), + } +} + +func parseUser(data []byte) *User { + user := User{} + json.Unmarshal(data, &user) + return &user +} + +func parseUserList(data []byte) []User { + users := []User{} + json.Unmarshal(data, &users) + return users +} + +//Get user with the specified id +func (userApi *UserApi) Get(id string) (*User, error) { + data, err := userApi.configurationService.Get(id, map[string]string{}) + if err != nil { + return nil, err + } + return parseUser(data), nil +} + +//List all users +func (userApi *UserApi) List() ([]User, error) { + return userApi.ListWithOptions(map[string]string{}) +} + +//List all instances for the current user. Can use options to do sorting and paging. +func (userApi *UserApi) ListWithOptions(options map[string]string) ([]User, error) { + data, err := userApi.configurationService.List(options) + if err != nil { + return nil, err + } + return parseUserList(data), nil +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/go.mod b/vendor/github.com/cloud-ca/go-cloudca/go.mod new file mode 100644 index 0000000..d46d1a8 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/go.mod @@ -0,0 +1,8 @@ +module github.com/cloud-ca/go-cloudca + +go 1.12 + +require ( + github.com/golang/mock v1.2.0 + github.com/stretchr/testify v1.3.0 +) diff --git a/vendor/github.com/cloud-ca/go-cloudca/go.sum b/vendor/github.com/cloud-ca/go-cloudca/go.sum new file mode 100644 index 0000000..e5e94ca --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/go.sum @@ -0,0 +1,9 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= diff --git a/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/affinity_groups.go b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/affinity_groups.go new file mode 100644 index 0000000..6f3f50e --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/affinity_groups.go @@ -0,0 +1,65 @@ +package cloudca + +import ( + "encoding/json" + "github.com/cloud-ca/go-cloudca/api" + "github.com/cloud-ca/go-cloudca/services" +) + +type AffinityGroup struct { + Id string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + Type string `json:"type,omitempty"` + InstanceIds []string `json:"instanceIds,omitempty"` + InstanceNames []string `json:"instanceNames,omitempty"` + ZoneIds []string `json:"zoneIds,omitempty"` +} + +type AffinityGroupService interface { + Get(string) (*AffinityGroup, error) + List() ([]AffinityGroup, error) + ListWithOptions(map[string]string) ([]AffinityGroup, error) +} + +type AffinityGroupApi struct { + entityService services.EntityService +} + +func NewAffinityGroupsService(apiClient api.ApiClient, serviceCode string, environmentName string) AffinityGroupService { + return &AffinityGroupApi{ + entityService: services.NewEntityService(apiClient, serviceCode, environmentName, AFFINITY_GROUP_ENTITY_TYPE), + } +} + +func parseAffinityGroup(data []byte) *AffinityGroup { + affinityGroup := AffinityGroup{} + json.Unmarshal(data, &affinityGroup) + return &affinityGroup +} + +func parseAffinityGroupList(data []byte) []AffinityGroup { + affinityGroups := []AffinityGroup{} + json.Unmarshal(data, &affinityGroups) + return affinityGroups +} + +func (api *AffinityGroupApi) Get(id string) (*AffinityGroup, error) { + resp, err := api.entityService.Get(id, map[string]string{}) + if err != nil { + return nil, err + } + return parseAffinityGroup(resp), nil +} + +func (api *AffinityGroupApi) List() ([]AffinityGroup, error) { + return api.ListWithOptions(map[string]string{}) +} + +func (api *AffinityGroupApi) ListWithOptions(options map[string]string) ([]AffinityGroup, error) { + resp, err := api.entityService.List(options) + if err != nil { + return nil, err + } + return parseAffinityGroupList(resp), nil +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/compute_offering.go b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/compute_offering.go new file mode 100644 index 0000000..c8694d1 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/compute_offering.go @@ -0,0 +1,66 @@ +package cloudca + +import ( + "encoding/json" + "github.com/cloud-ca/go-cloudca/api" + "github.com/cloud-ca/go-cloudca/services" +) + +type ComputeOffering struct { + Id string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + MemoryInMB int `json:"memoryInMB,omitempty"` + CpuCount int `json:"cpuCount,omitempty"` + Custom bool `json:"custom,omitempty"` +} + +type ComputeOfferingService interface { + Get(id string) (*ComputeOffering, error) + List() ([]ComputeOffering, error) + ListWithOptions(options map[string]string) ([]ComputeOffering, error) +} + +type ComputeOfferingApi struct { + entityService services.EntityService +} + +func NewComputeOfferingService(apiClient api.ApiClient, serviceCode string, environmentName string) ComputeOfferingService { + return &ComputeOfferingApi{ + entityService: services.NewEntityService(apiClient, serviceCode, environmentName, COMPUTE_OFFERING_ENTITY_TYPE), + } +} + +func parseComputeOffering(data []byte) *ComputeOffering { + computeOffering := ComputeOffering{} + json.Unmarshal(data, &computeOffering) + return &computeOffering +} + +func parseComputeOfferingList(data []byte) []ComputeOffering { + computeOfferings := []ComputeOffering{} + json.Unmarshal(data, &computeOfferings) + return computeOfferings +} + +//Get compute offering with the specified id for the current environment +func (computeOfferingApi *ComputeOfferingApi) Get(id string) (*ComputeOffering, error) { + data, err := computeOfferingApi.entityService.Get(id, map[string]string{}) + if err != nil { + return nil, err + } + return parseComputeOffering(data), nil +} + +//List all compute offerings for the current environment +func (computeOfferingApi *ComputeOfferingApi) List() ([]ComputeOffering, error) { + return computeOfferingApi.ListWithOptions(map[string]string{}) +} + +//List all compute offerings for the current environment. Can use options to do sorting and paging. +func (computeOfferingApi *ComputeOfferingApi) ListWithOptions(options map[string]string) ([]ComputeOffering, error) { + data, err := computeOfferingApi.entityService.List(options) + if err != nil { + return nil, err + } + return parseComputeOfferingList(data), nil +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/disk_offering.go b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/disk_offering.go new file mode 100644 index 0000000..83b15f4 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/disk_offering.go @@ -0,0 +1,69 @@ +package cloudca + +import ( + "encoding/json" + + "github.com/cloud-ca/go-cloudca/api" + "github.com/cloud-ca/go-cloudca/services" +) + +type DiskOffering struct { + Id string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + GbSize int `json:"gbSize,omitempty"` + MinIops int `json:"minIops,omitempty"` + MaxIops int `json:"maxIops,omitempty"` + CustomSize bool `json:"customSize,omitempty"` + CustomIops bool `json:"customIops,omitempty"` +} + +type DiskOfferingService interface { + Get(id string) (*DiskOffering, error) + List() ([]DiskOffering, error) + ListWithOptions(options map[string]string) ([]DiskOffering, error) +} + +type DiskOfferingApi struct { + entityService services.EntityService +} + +func NewDiskOfferingService(apiClient api.ApiClient, serviceCode string, environmentName string) DiskOfferingService { + return &DiskOfferingApi{ + entityService: services.NewEntityService(apiClient, serviceCode, environmentName, DISK_OFFERING_ENTITY_TYPE), + } +} + +func parseDiskOffering(data []byte) *DiskOffering { + diskOffering := DiskOffering{} + json.Unmarshal(data, &diskOffering) + return &diskOffering +} + +func parseDiskOfferingList(data []byte) []DiskOffering { + diskOfferings := []DiskOffering{} + json.Unmarshal(data, &diskOfferings) + return diskOfferings +} + +//Get disk offering with the specified id for the current environment +func (diskOfferingApi *DiskOfferingApi) Get(id string) (*DiskOffering, error) { + data, err := diskOfferingApi.entityService.Get(id, map[string]string{}) + if err != nil { + return nil, err + } + return parseDiskOffering(data), nil +} + +//List all disk offerings for the current environment +func (diskOfferingApi *DiskOfferingApi) List() ([]DiskOffering, error) { + return diskOfferingApi.ListWithOptions(map[string]string{}) +} + +//List all disk offerings for the current environment. Can use options to do sorting and paging. +func (diskOfferingApi *DiskOfferingApi) ListWithOptions(options map[string]string) ([]DiskOffering, error) { + data, err := diskOfferingApi.entityService.List(options) + if err != nil { + return nil, err + } + return parseDiskOfferingList(data), nil +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/entity_type.go b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/entity_type.go new file mode 100644 index 0000000..e8fa609 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/entity_type.go @@ -0,0 +1,24 @@ +package cloudca + +//All entity types for the cloudca service +const ( + AFFINITY_GROUP_ENTITY_TYPE = "affinitygroups" + INSTANCE_ENTITY_TYPE = "instances" + VOLUME_ENTITY_TYPE = "volumes" + TEMPLATE_ENTITY_TYPE = "templates" + NETWORK_ENTITY_TYPE = "networks" + COMPUTE_OFFERING_ENTITY_TYPE = "computeofferings" + DISK_OFFERING_ENTITY_TYPE = "diskofferings" + SSH_KEY_ENTITY_TYPE = "sshkeys" + VPC_ENTITY_TYPE = "vpcs" + VPC_OFFERING_ENTITY_TYPE = "vpcofferings" + NETWORK_OFFERING_ENTITY_TYPE = "networkofferings" + NETWORK_ACL_ENTITY_TYPE = "networkacls" + NETWORK_ACL_RULE_ENTITY_TYPE = "networkaclrules" + PORT_FORWARDING_RULE_ENTITY_TYPE = "portforwardingrules" + LOAD_BALANCER_RULE_ENTITY_TYPE = "loadbalancerrules" + PUBLIC_IP_ENTITY_TYPE = "publicipaddresses" + ZONE_ENTITY_TYPE = "zones" + REMOTE_ACCESS_VPN_ENTITY_TYPE = "remoteaccessvpns" + REMOTE_ACCESS_VPN_USER_ENTITY_TYPE = "vpnusers" +) diff --git a/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/instance.go b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/instance.go new file mode 100644 index 0000000..4edd61d --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/instance.go @@ -0,0 +1,284 @@ +package cloudca + +import ( + "encoding/json" + "strings" + + "github.com/cloud-ca/go-cloudca/api" + "github.com/cloud-ca/go-cloudca/services" +) + +const ( + INSTANCE_STATE_RUNNING = "Running" + INSTANCE_STATE_STOPPED = "Stopped" +) + +const ( + INSTANCE_START_OPERATION = "start" + INSTANCE_STOP_OPERATION = "stop" + INSTANCE_REBOOT_OPERATION = "reboot" + INSTANCE_RECOVER_OPERATION = "recover" + INSTANCE_PURGE_OPERATION = "purge" + INSTANCE_RESET_PASSWORD_OPERATION = "resetPassword" + INSTANCE_CREATE_RECOVERY_POINT_OPERATION = "createRecoveryPoint" + INSTANCE_CHANGE_COMPUTE_OFFERING_OPERATION = "changeComputeOffering" + INSTANCE_ASSOCIATE_SSH_KEY_OPERATION = "associateSSHKey" +) + +type Instance struct { + Id string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + State string `json:"state,omitempty"` + TemplateId string `json:"templateId,omitempty"` + TemplateName string `json:"templateName,omitempty"` + IsPasswordEnabled bool `json:"isPasswordEnabled,omitempty"` + IsSSHKeyEnabled bool `json:"isSshKeyEnabled,omitempty"` + Username string `json:"username,omitempty"` + Password string `json:"password,omitempty"` + SSHKeyName string `json:"sshKeyName,omitempty"` + ComputeOfferingId string `json:"computeOfferingId,omitempty"` + ComputeOfferingName string `json:"computeOfferingName,omitempty"` + NewComputeOfferingId string `json:"newComputeOfferingId,omitempty"` + CpuCount int `json:"cpuCount,omitempty"` + MemoryInMB int `json:"memoryInMB,omitempty"` + ZoneId string `json:"zoneId,omitempty"` + ZoneName string `json:"zoneName,omitempty"` + ProjectId string `json:"projectId,omitempty"` + NetworkId string `json:"networkId,omitempty"` + NetworkName string `json:"networkName,omitempty"` + VpcId string `json:"vpcId,omitempty"` + VpcName string `json:"vpcName,omitempty"` + MacAddress string `json:"macAddress,omitempty"` + UserData string `json:"userData,omitempty"` + RecoveryPoint RecoveryPoint `json:"recoveryPoint,omitempty"` + IpAddress string `json:"ipAddress,omitempty"` + IpAddressId string `json:"ipAddressId,omitempty"` + PublicIps []PublicIp `json:"publicIPs,omitempty"` + PublicKey string `json:"publicKey,omitempty"` + AdditionalDiskOfferingId string `json:"diskOfferingId,omitempty"` + AdditionalDiskSizeInGb string `json:"additionalDiskSizeInGb,omitempty"` + AdditionalDiskIops string `json:"additionalDiskIops,omitempty"` + VolumeIdToAttach string `json:"volumeIdToAttach,omitempty"` + PortsToForward []string `json:"portsToForward,omitempty"` + RootVolumeSizeInGb int `json:"rootVolumeSizeInGb,omitempty"` + DedicatedGroupId string `json:"dedicatedGroupId,omitempty"` + AffinityGroupIds []string `json:"affinityGroupIds,omitempty"` +} + +type DestroyOptions struct { + PurgeImmediately bool `json:"purgeImmediately,omitempty"` + DeleteSnapshots bool `json:"deleteSnapshots,omitempty"` + PublicIpIdsToRelease []string `json:"publicIpIdsToRelease,omitempty"` + VolumeIdsToDelete []string `json:"volumeIdsToDelete,omitempty"` +} + +func (instance *Instance) IsRunning() bool { + return strings.EqualFold(instance.State, INSTANCE_STATE_RUNNING) +} + +func (instance *Instance) IsStopped() bool { + return strings.EqualFold(instance.State, INSTANCE_STATE_STOPPED) +} + +type InstanceService interface { + Get(id string) (*Instance, error) + List() ([]Instance, error) + ListWithOptions(options map[string]string) ([]Instance, error) + Create(Instance) (*Instance, error) + Destroy(id string, purge bool) (bool, error) + DestroyWithOptions(id string, options DestroyOptions) (bool, error) + Purge(id string) (bool, error) + Recover(id string) (bool, error) + Exists(id string) (bool, error) + Start(id string) (bool, error) + Stop(id string) (bool, error) + AssociateSSHKey(id string, sshKeyName string) (bool, error) + Reboot(id string) (bool, error) + ChangeComputeOffering(Instance) (bool, error) + ChangeNetwork(id string, newNetworkId string) (bool, error) + ResetPassword(id string) (string, error) + CreateRecoveryPoint(id string, recoveryPoint RecoveryPoint) (bool, error) +} + +type InstanceApi struct { + entityService services.EntityService +} + +func NewInstanceService(apiClient api.ApiClient, serviceCode string, environmentName string) InstanceService { + return &InstanceApi{ + entityService: services.NewEntityService(apiClient, serviceCode, environmentName, INSTANCE_ENTITY_TYPE), + } +} + +func parseInstance(data []byte) *Instance { + instance := Instance{} + json.Unmarshal(data, &instance) + return &instance +} + +func parseInstanceList(data []byte) []Instance { + instances := []Instance{} + json.Unmarshal(data, &instances) + return instances +} + +//Get instance with the specified id for the current environment +func (instanceApi *InstanceApi) Get(id string) (*Instance, error) { + data, err := instanceApi.entityService.Get(id, map[string]string{}) + if err != nil { + return nil, err + } + return parseInstance(data), nil +} + +//List all instances for the current environment +func (instanceApi *InstanceApi) List() ([]Instance, error) { + return instanceApi.ListWithOptions(map[string]string{}) +} + +//List all instances for the current environment. Can use options to do sorting and paging. +func (instanceApi *InstanceApi) ListWithOptions(options map[string]string) ([]Instance, error) { + data, err := instanceApi.entityService.List(options) + if err != nil { + return nil, err + } + return parseInstanceList(data), nil +} + +//Create an instance in the current environment +func (instanceApi *InstanceApi) Create(instance Instance) (*Instance, error) { + send, merr := json.Marshal(instance) + if merr != nil { + return nil, merr + } + body, err := instanceApi.entityService.Create(send, map[string]string{}) + if err != nil { + return nil, err + } + return parseInstance(body), nil +} + +//Destroy an instance with specified id in the current environment +//Set the purge flag to true if you want to purge immediately +func (instanceApi *InstanceApi) Destroy(id string, purge bool) (bool, error) { + send, merr := json.Marshal(DestroyOptions{ + PurgeImmediately: purge, + }) + if merr != nil { + return false, merr + } + _, err := instanceApi.entityService.Delete(id, send, map[string]string{}) + return err == nil, err +} + +//Destroy an instance with specified id in the current environment +//Set the purge flag to true if you want to purge immediately +func (instanceApi *InstanceApi) DestroyWithOptions(id string, options DestroyOptions) (bool, error) { + send, merr := json.Marshal(options) + if merr != nil { + return false, merr + } + _, err := instanceApi.entityService.Delete(id, send, map[string]string{}) + return err == nil, err +} + +//Purge an instance with the specified id in the current environment +//The instance must be in the Destroyed state. To destroy and purge an instance, see the Destroy method +func (instanceApi *InstanceApi) Purge(id string) (bool, error) { + _, err := instanceApi.entityService.Execute(id, INSTANCE_PURGE_OPERATION, []byte{}, map[string]string{}) + return err == nil, err +} + +//Recover a destroyed instance with the specified id in the current environment +//Note: Cannot recover instances that have been purged +func (instanceApi *InstanceApi) Recover(id string) (bool, error) { + _, err := instanceApi.entityService.Execute(id, INSTANCE_RECOVER_OPERATION, []byte{}, map[string]string{}) + return err == nil, err +} + +//Check if instance with specified id exists in the current environment +func (instanceApi *InstanceApi) Exists(id string) (bool, error) { + _, err := instanceApi.Get(id) + if err != nil { + if ccaError, ok := err.(api.CcaErrorResponse); ok && ccaError.StatusCode == 404 { + return false, nil + } + return false, err + } + return true, nil +} + +//Start a stopped instance with specified id exists in the current environment +func (instanceApi *InstanceApi) Start(id string) (bool, error) { + _, err := instanceApi.entityService.Execute(id, INSTANCE_START_OPERATION, []byte{}, map[string]string{}) + return err == nil, err +} + +//Stop a running instance with specified id exists in the current environment +func (instanceApi *InstanceApi) Stop(id string) (bool, error) { + _, err := instanceApi.entityService.Execute(id, INSTANCE_STOP_OPERATION, []byte{}, map[string]string{}) + return err == nil, err +} + +//Associate an SSH key to the instance with the specified id exists in the current environment +//Note: This will reboot your instance if running +func (instanceApi *InstanceApi) AssociateSSHKey(id string, sshKeyName string) (bool, error) { + send, merr := json.Marshal(Instance{ + SSHKeyName: sshKeyName, + }) + if merr != nil { + return false, merr + } + _, err := instanceApi.entityService.Execute(id, INSTANCE_ASSOCIATE_SSH_KEY_OPERATION, send, map[string]string{}) + return err == nil, err +} + +//Reboot a running instance with specified id exists in the current environment +func (instanceApi *InstanceApi) Reboot(id string) (bool, error) { + _, err := instanceApi.entityService.Execute(id, INSTANCE_REBOOT_OPERATION, []byte{}, map[string]string{}) + return err == nil, err +} + +//Change the compute offering of the instance with the specified id exists in the current environment +//Note: This will reboot your instance if running +func (instanceApi *InstanceApi) ChangeComputeOffering(instance Instance) (bool, error) { + send, merr := json.Marshal(instance) + if merr != nil { + return false, merr + } + _, err := instanceApi.entityService.Execute(instance.Id, INSTANCE_CHANGE_COMPUTE_OFFERING_OPERATION, send, map[string]string{}) + return err == nil, err +} + +//Reset the password of the instance with the specified id exists in the current environment +func (instanceApi *InstanceApi) ResetPassword(id string) (string, error) { + body, err := instanceApi.entityService.Execute(id, INSTANCE_RESET_PASSWORD_OPERATION, []byte{}, map[string]string{}) + if err != nil { + return "", err + } + instance := parseInstance(body) + return instance.Password, nil +} + +//Change the network of the instance with the specified id +//Note: This will reboot your instance, remove all pfrs of this instance and remove the instance from all lbrs. +func (instanceApi *InstanceApi) ChangeNetwork(id string, networkId string) (bool, error) { + send, merr := json.Marshal(Instance{NetworkId: networkId}) + if merr != nil { + return false, merr + } + _, err := instanceApi.entityService.Execute(id, INSTANCE_CHANGE_COMPUTE_OFFERING_OPERATION, send, map[string]string{}) + return err == nil, err +} + +//Create a recovery point of the instance with the specified id exists in the current environment +func (instanceApi *InstanceApi) CreateRecoveryPoint(id string, recoveryPoint RecoveryPoint) (bool, error) { + send, merr := json.Marshal(Instance{ + RecoveryPoint: recoveryPoint, + }) + if merr != nil { + return false, merr + } + _, err := instanceApi.entityService.Execute(id, INSTANCE_CREATE_RECOVERY_POINT_OPERATION, send, map[string]string{}) + return err == nil, err +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/load_balancer_rule.go b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/load_balancer_rule.go new file mode 100644 index 0000000..bcfafe8 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/load_balancer_rule.go @@ -0,0 +1,151 @@ +package cloudca + +import ( + "encoding/json" + + "github.com/cloud-ca/go-cloudca/api" + "github.com/cloud-ca/go-cloudca/services" +) + +const ( + UPDATE_INSTANCES = "updateInstances" + UPDATE_STICKINESS = "updateStickiness" +) + +type LoadBalancerRule struct { + Id string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + InstanceIds []string `json:"instanceIds,omitempty"` + NetworkId string `json:"networkId,omitempty"` + PublicIp string `json:"publicIp,omitempty"` + PublicIpId string `json:"publicIpId,omitempty"` + PublicPort string `json:"publicPort,omitempty"` + PrivatePort string `json:"privatePort,omitempty"` + Protocol string `json:"protocol,omitempty"` + Algorithm string `json:"algorithm,omitempty"` + StickinessMethod string `json:"stickinessMethod,omitempty"` + StickinessPolicyParameters map[string]string `json:"stickinessPolicyParameters,omitempty"` +} + +type LoadBalancerRuleService interface { + Get(id string) (*LoadBalancerRule, error) + List() ([]LoadBalancerRule, error) + ListWithOptions(options map[string]string) ([]LoadBalancerRule, error) + Create(lbr LoadBalancerRule) (*LoadBalancerRule, error) + Delete(id string) error + Update(lbr LoadBalancerRule) (*LoadBalancerRule, error) + SetLoadBalancerRuleInstances(id string, instanceIds []string) error + SetLoadBalancerRuleStickinessPolicy(id string, method string, stickinessPolicyParameters map[string]string) error + RemoveLoadBalancerRuleStickinessPolicy(id string) error +} + +type LoadBalancerRuleApi struct { + entityService services.EntityService +} + +func NewLoadBalancerRuleService(apiClient api.ApiClient, serviceCode string, environmentName string) LoadBalancerRuleService { + return &LoadBalancerRuleApi{ + entityService: services.NewEntityService(apiClient, serviceCode, environmentName, LOAD_BALANCER_RULE_ENTITY_TYPE), + } +} + +func parseLoadBalancerRule(data []byte) *LoadBalancerRule { + lbr := LoadBalancerRule{} + json.Unmarshal(data, &lbr) + return &lbr +} + +func parseLoadBalancerRuleList(data []byte) []LoadBalancerRule { + lbrs := []LoadBalancerRule{} + json.Unmarshal(data, &lbrs) + return lbrs +} + +func (api *LoadBalancerRuleApi) Get(id string) (*LoadBalancerRule, error) { + data, err := api.entityService.Get(id, map[string]string{}) + if err != nil { + return nil, err + } + return parseLoadBalancerRule(data), nil +} + +func (api *LoadBalancerRuleApi) ListWithOptions(options map[string]string) ([]LoadBalancerRule, error) { + data, err := api.entityService.List(options) + if err != nil { + return nil, err + } + return parseLoadBalancerRuleList(data), nil +} + +func (api *LoadBalancerRuleApi) List() ([]LoadBalancerRule, error) { + return api.ListWithOptions(map[string]string{}) +} + +func (api *LoadBalancerRuleApi) Create(lbr LoadBalancerRule) (*LoadBalancerRule, error) { + msg, err := json.Marshal(lbr) + if err != nil { + return nil, err + } + result, err := api.entityService.Create(msg, map[string]string{}) + if err != nil { + return nil, err + } + return parseLoadBalancerRule(result), nil +} + +func (api *LoadBalancerRuleApi) Update(lbr LoadBalancerRule) (*LoadBalancerRule, error) { + msg, err := json.Marshal(lbr) + if err != nil { + return nil, err + } + result, err := api.entityService.Update(lbr.Id, msg, map[string]string{}) + if err != nil { + return nil, err + } + return parseLoadBalancerRule(result), nil +} + +func (api *LoadBalancerRuleApi) SetLoadBalancerRuleInstances(id string, instanceIds []string) error { + lbr := LoadBalancerRule{ + Id: id, + InstanceIds: instanceIds, + } + msg, err := json.Marshal(lbr) + if err != nil { + return err + } + _, updateErr := api.entityService.Execute(id, UPDATE_INSTANCES, msg, map[string]string{}) + return updateErr +} + +func (api *LoadBalancerRuleApi) SetLoadBalancerRuleStickinessPolicy(id string, method string, stickinessPolicyParameters map[string]string) error { + lbr := LoadBalancerRule{ + Id: id, + StickinessMethod: method, + StickinessPolicyParameters: stickinessPolicyParameters, + } + msg, err := json.Marshal(lbr) + if err != nil { + return err + } + _, updateErr := api.entityService.Execute(id, UPDATE_STICKINESS, msg, map[string]string{}) + return updateErr +} + +func (api *LoadBalancerRuleApi) RemoveLoadBalancerRuleStickinessPolicy(id string) error { + lbr := LoadBalancerRule{ + Id: id, + StickinessMethod: "none", + } + msg, err := json.Marshal(lbr) + if err != nil { + return err + } + _, updateErr := api.entityService.Execute(id, UPDATE_STICKINESS, msg, map[string]string{}) + return updateErr +} + +func (api *LoadBalancerRuleApi) Delete(id string) error { + _, err := api.entityService.Delete(id, []byte{}, map[string]string{}) + return err +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/network.go b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/network.go new file mode 100644 index 0000000..3f69c7e --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/network.go @@ -0,0 +1,138 @@ +package cloudca + +import ( + "encoding/json" + + "github.com/cloud-ca/go-cloudca/api" + "github.com/cloud-ca/go-cloudca/services" +) + +type Service struct { + Name string `json:"name,omitempty"` + Capabilities map[string]interface{} `json:"capabilities,omitempty"` +} + +type Network struct { + Id string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + VpcId string `json:"vpcId,omitempty"` + NetworkOfferingId string `json:"networkOfferingId,omitempty"` + NetworkAclId string `json:"networkAclId,omitempty"` + NetworkAclName string `json:"networkAclName,omitempty"` + ZoneId string `json:"zoneid,omitempty"` + ZoneName string `json:"zonename,omitempty"` + Cidr string `json:"cidr,omitempty"` + Type string `json:"type,omitempty"` + State string `json:"state,omitempty"` + Gateway string `json:"gateway,omitempty"` + IsSystem bool `json:"issystem,omitempty"` + Domain string `json:"domain,omitempty"` + DomainId string `json:"domainid,omitempty"` + Project string `json:"project,omitempty"` + ProjectId string `json:"projectid,omitempty"` + Services []Service `json:"service,omitempty"` +} + +type NetworkService interface { + Get(id string) (*Network, error) + List() ([]Network, error) + ListOfVpc(vpcId string) ([]Network, error) + ListWithOptions(options map[string]string) ([]Network, error) + Create(network Network, options map[string]string) (*Network, error) + Update(id string, network Network) (*Network, error) + Delete(id string) (bool, error) + ChangeAcl(id string, aclId string) (bool, error) +} + +type NetworkApi struct { + entityService services.EntityService +} + +func NewNetworkService(apiClient api.ApiClient, serviceCode string, environmentName string) NetworkService { + return &NetworkApi{ + entityService: services.NewEntityService(apiClient, serviceCode, environmentName, NETWORK_ENTITY_TYPE), + } +} + +func parseNetwork(data []byte) *Network { + network := Network{} + json.Unmarshal(data, &network) + return &network +} + +func parseNetworkList(data []byte) []Network { + networks := []Network{} + json.Unmarshal(data, &networks) + return networks +} + +//Get network with the specified id for the current environment +func (networkApi *NetworkApi) Get(id string) (*Network, error) { + data, err := networkApi.entityService.Get(id, map[string]string{}) + if err != nil { + return nil, err + } + return parseNetwork(data), nil +} + +//List all networks for the current environment +func (networkApi *NetworkApi) List() ([]Network, error) { + return networkApi.ListWithOptions(map[string]string{}) +} + +//List all networks of a vpc for the current environment +func (networkApi *NetworkApi) ListOfVpc(vpcId string) ([]Network, error) { + return networkApi.ListWithOptions(map[string]string{ + vpcId: vpcId, + }) +} + +//List all networks for the current environment. Can use options to do sorting and paging. +func (networkApi *NetworkApi) ListWithOptions(options map[string]string) ([]Network, error) { + data, err := networkApi.entityService.List(options) + if err != nil { + return nil, err + } + return parseNetworkList(data), nil +} + +func (networkApi *NetworkApi) Create(network Network, options map[string]string) (*Network, error) { + send, merr := json.Marshal(network) + if merr != nil { + return nil, merr + } + body, err := networkApi.entityService.Create(send, options) + if err != nil { + return nil, err + } + return parseNetwork(body), nil +} + +func (networkApi *NetworkApi) Update(id string, network Network) (*Network, error) { + send, merr := json.Marshal(network) + if merr != nil { + return nil, merr + } + body, err := networkApi.entityService.Update(id, send, map[string]string{}) + if err != nil { + return nil, err + } + return parseNetwork(body), nil +} + +func (networkApi *NetworkApi) Delete(id string) (bool, error) { + _, err := networkApi.entityService.Delete(id, []byte{}, map[string]string{}) + return err == nil, err +} + +func (networkApi *NetworkApi) ChangeAcl(id string, aclId string) (bool, error) { + send, merr := json.Marshal(Network{ + NetworkAclId: aclId, + }) + if merr != nil { + return false, merr + } + _, err := networkApi.entityService.Execute(id, "replace", send, map[string]string{}) + return err == nil, err +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/network_acl.go b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/network_acl.go new file mode 100644 index 0000000..1f9c17c --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/network_acl.go @@ -0,0 +1,90 @@ +package cloudca + +import ( + "encoding/json" + "github.com/cloud-ca/go-cloudca/api" + "github.com/cloud-ca/go-cloudca/services" +) + +type NetworkAcl struct { + Id string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + VpcId string `json:"vpcId,omitempty"` +} + +type NetworkAclService interface { + Get(id string) (*NetworkAcl, error) + List() ([]NetworkAcl, error) + ListByVpcId(vpcId string) ([]NetworkAcl, error) + ListWithOptions(options map[string]string) ([]NetworkAcl, error) + Create(networkAcl NetworkAcl) (*NetworkAcl, error) + Delete(id string) (bool, error) +} + +type NetworkAclApi struct { + entityService services.EntityService +} + +func NewNetworkAclService(apiClient api.ApiClient, serviceCode string, environmentName string) NetworkAclService { + return &NetworkAclApi{ + entityService: services.NewEntityService(apiClient, serviceCode, environmentName, NETWORK_ACL_ENTITY_TYPE), + } +} + +func parseNetworkAcl(data []byte) *NetworkAcl { + networkAcl := NetworkAcl{} + json.Unmarshal(data, &networkAcl) + return &networkAcl +} + +func parseNetworkAclList(data []byte) []NetworkAcl { + networkAcls := []NetworkAcl{} + json.Unmarshal(data, &networkAcls) + return networkAcls +} + +//Get network acl with the specified id for the current environment +func (networkAclApi *NetworkAclApi) Get(id string) (*NetworkAcl, error) { + data, err := networkAclApi.entityService.Get(id, map[string]string{}) + if err != nil { + return nil, err + } + return parseNetworkAcl(data), nil +} + +//List all network offerings for the current environment +func (networkAclApi *NetworkAclApi) List() ([]NetworkAcl, error) { + return networkAclApi.ListWithOptions(map[string]string{}) +} + +//List all network offerings for the current environment +func (networkAclApi *NetworkAclApi) ListByVpcId(vpcId string) ([]NetworkAcl, error) { + return networkAclApi.ListWithOptions(map[string]string{"vpc_id": vpcId}) +} + +//List all network offerings for the current environment. Can use options to do sorting and paging. +func (networkAclApi *NetworkAclApi) ListWithOptions(options map[string]string) ([]NetworkAcl, error) { + data, err := networkAclApi.entityService.List(options) + if err != nil { + return nil, err + } + return parseNetworkAclList(data), nil +} + +func (networkAclApi *NetworkAclApi) Create(networkAcl NetworkAcl) (*NetworkAcl, error) { + msg, err := json.Marshal(networkAcl) + if err != nil { + return nil, err + } + result, err := networkAclApi.entityService.Create(msg, map[string]string{}) + if err != nil { + return nil, err + } + return parseNetworkAcl(result), nil +} + +func (networkAclApi *NetworkAclApi) Delete(id string) (bool, error) { + _, err := networkAclApi.entityService.Delete(id, []byte{}, map[string]string{}) + return err == nil, err +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/network_acl_rule.go b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/network_acl_rule.go new file mode 100644 index 0000000..99c4924 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/network_acl_rule.go @@ -0,0 +1,110 @@ +package cloudca + +import ( + "encoding/json" + + "github.com/cloud-ca/go-cloudca/api" + "github.com/cloud-ca/go-cloudca/services" +) + +type NetworkAclRule struct { + Id string `json:"id,omitempty"` + NetworkAclId string `json:"networkAclId,omitempty"` + RuleNumber string `json:"ruleNumber,omitempty"` + Cidr string `json:"cidr,omitempty"` + Action string `json:"action,omitempty"` + Protocol string `json:"protocol,omitempty"` + StartPort string `json:"startPort,omitempty"` + EndPort string `json:"endPort,omitempty"` + IcmpType string `json:"icmpType,omitempty"` + IcmpCode string `json:"icmpCode,omitempty"` + TrafficType string `json:"trafficType,omitempty"` + State string `json:"state,omitempty"` +} + +type NetworkAclRuleService interface { + Get(id string) (*NetworkAclRule, error) + List() ([]NetworkAclRule, error) + ListByNetworkAclId(networkAclId string) ([]NetworkAclRule, error) + ListWithOptions(options map[string]string) ([]NetworkAclRule, error) + Create(networkAclRule NetworkAclRule) (*NetworkAclRule, error) + Update(id string, networkAclRule NetworkAclRule) (*NetworkAclRule, error) + Delete(id string) (bool, error) +} + +type NetworkAclRuleApi struct { + entityService services.EntityService +} + +func NewNetworkAclRuleService(apiClient api.ApiClient, serviceCode string, environmentName string) NetworkAclRuleService { + return &NetworkAclRuleApi{ + entityService: services.NewEntityService(apiClient, serviceCode, environmentName, NETWORK_ACL_RULE_ENTITY_TYPE), + } +} + +func parseNetworkAclRule(data []byte) *NetworkAclRule { + networkAclRule := NetworkAclRule{} + json.Unmarshal(data, &networkAclRule) + return &networkAclRule +} + +func parseNetworkAclRuleList(data []byte) []NetworkAclRule { + aclRules := []NetworkAclRule{} + json.Unmarshal(data, &aclRules) + return aclRules +} + +//Get network acl rule with the specified id for the current environment +func (networkAclRuleApi *NetworkAclRuleApi) Get(id string) (*NetworkAclRule, error) { + data, err := networkAclRuleApi.entityService.Get(id, map[string]string{}) + if err != nil { + return nil, err + } + return parseNetworkAclRule(data), nil +} + +func (networkAclRuleApi *NetworkAclRuleApi) ListWithOptions(options map[string]string) ([]NetworkAclRule, error) { + data, err := networkAclRuleApi.entityService.List(options) + if err != nil { + return nil, err + } + return parseNetworkAclRuleList(data), nil +} + +func (networkAclRuleApi *NetworkAclRuleApi) List() ([]NetworkAclRule, error) { + return networkAclRuleApi.ListWithOptions(map[string]string{}) +} + +//List all network acl rules for the NetworkAcl +func (networkAclRuleApi *NetworkAclRuleApi) ListByNetworkAclId(networkAclId string) ([]NetworkAclRule, error) { + return networkAclRuleApi.ListWithOptions(map[string]string{"network_acl_id": networkAclId}) +} + +func (networkAclRuleApi *NetworkAclRuleApi) Create(networkAclRule NetworkAclRule) (*NetworkAclRule, error) { + msg, err := json.Marshal(networkAclRule) + if err != nil { + return nil, err + } + result, err := networkAclRuleApi.entityService.Create(msg, map[string]string{}) + if err != nil { + return nil, err + } + return parseNetworkAclRule(result), nil +} + +func (networkAclRuleApi *NetworkAclRuleApi) Update(id string, networkAclRule NetworkAclRule) (*NetworkAclRule, error) { + msg, err := json.Marshal(networkAclRule) + if err != nil { + return nil, err + } + result, err := networkAclRuleApi.entityService.Update(id, msg, map[string]string{}) + if err != nil { + return nil, err + } + return parseNetworkAclRule(result), nil +} + +func (networkAclRuleApi *NetworkAclRuleApi) Delete(id string) (bool, error) { + _, err := networkAclRuleApi.entityService.Delete(id, []byte{}, map[string]string{}) + return err == nil, err +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/network_offering.go b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/network_offering.go new file mode 100644 index 0000000..d028603 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/network_offering.go @@ -0,0 +1,63 @@ +package cloudca + +import ( + "encoding/json" + "github.com/cloud-ca/go-cloudca/api" + "github.com/cloud-ca/go-cloudca/services" +) + +type NetworkOffering struct { + Id string `json:"id,omitempty"` + Name string `json:"name,omitempty"` +} + +type NetworkOfferingService interface { + Get(id string) (*NetworkOffering, error) + List() ([]NetworkOffering, error) + ListWithOptions(options map[string]string) ([]NetworkOffering, error) +} + +type NetworkOfferingApi struct { + entityService services.EntityService +} + +func NewNetworkOfferingService(apiClient api.ApiClient, serviceCode string, environmentName string) NetworkOfferingService { + return &NetworkOfferingApi{ + entityService: services.NewEntityService(apiClient, serviceCode, environmentName, NETWORK_OFFERING_ENTITY_TYPE), + } +} + +func parseNetworkOffering(data []byte) *NetworkOffering { + networkOffering := NetworkOffering{} + json.Unmarshal(data, &networkOffering) + return &networkOffering +} + +func parseNetworkOfferingList(data []byte) []NetworkOffering { + networkOfferings := []NetworkOffering{} + json.Unmarshal(data, &networkOfferings) + return networkOfferings +} + +//Get network offering with the specified id for the current environment +func (networkOfferingApi *NetworkOfferingApi) Get(id string) (*NetworkOffering, error) { + data, err := networkOfferingApi.entityService.Get(id, map[string]string{}) + if err != nil { + return nil, err + } + return parseNetworkOffering(data), nil +} + +//List all network offerings for the current environment +func (networkOfferingApi *NetworkOfferingApi) List() ([]NetworkOffering, error) { + return networkOfferingApi.ListWithOptions(map[string]string{}) +} + +//List all network offerings for the current environment. Can use options to do sorting and paging. +func (networkOfferingApi *NetworkOfferingApi) ListWithOptions(options map[string]string) ([]NetworkOffering, error) { + data, err := networkOfferingApi.entityService.List(options) + if err != nil { + return nil, err + } + return parseNetworkOfferingList(data), nil +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/port_forwarding_rule.go b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/port_forwarding_rule.go new file mode 100644 index 0000000..edd9766 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/port_forwarding_rule.go @@ -0,0 +1,98 @@ +package cloudca + +import ( + "encoding/json" + + "github.com/cloud-ca/go-cloudca/api" + "github.com/cloud-ca/go-cloudca/services" +) + +const ( + PFR_CREATE = "create" + PFR_DELETE = "delete" +) + +type PortForwardingRule struct { + Id string `json:"id,omitempty"` + InstanceId string `json:"instanceId,omitempty"` + InstanceName string `json:"instanceName,omitempty"` + NetworkId string `json:"networkId,omitempty"` + PrivateIp string `json:"privateIp,omitempty"` + PrivateIpId string `json:"privateIpId,omitempty"` + PrivatePortStart string `json:"privatePortStart,omitempty"` + PrivatePortEnd string `json:"privatePortEnd,omitempty"` + PublicIp string `json:"ipAddress,omitempty"` + PublicIpId string `json:"ipAddressId,omitempty"` + PublicPortStart string `json:"publicPortStart,omitempty"` + PublicPortEnd string `json:"publicPortEnd,omitempty"` + Protocol string `json:"protocol,omitempty"` + State string `json:"state,omitempty"` + VpcId string `json:"vpcId,omitempty"` +} + +type PortForwardingRuleService interface { + Get(id string) (*PortForwardingRule, error) + List() ([]PortForwardingRule, error) + ListWithOptions(options map[string]string) ([]PortForwardingRule, error) + Create(pfr PortForwardingRule) (*PortForwardingRule, error) + Delete(id string) (bool, error) +} + +type PortForwardingRuleApi struct { + entityService services.EntityService +} + +func NewPortForwardingRuleService(apiClient api.ApiClient, serviceCode string, environmentName string) PortForwardingRuleService { + return &PortForwardingRuleApi{ + entityService: services.NewEntityService(apiClient, serviceCode, environmentName, PORT_FORWARDING_RULE_ENTITY_TYPE), + } +} + +func parsePortForwardingRule(data []byte) *PortForwardingRule { + pfr := PortForwardingRule{} + json.Unmarshal(data, &pfr) + return &pfr +} + +func parsePortForwardingRuleList(data []byte) []PortForwardingRule { + pfrs := []PortForwardingRule{} + json.Unmarshal(data, &pfrs) + return pfrs +} + +func (api *PortForwardingRuleApi) Get(id string) (*PortForwardingRule, error) { + data, err := api.entityService.Get(id, map[string]string{}) + if err != nil { + return nil, err + } + return parsePortForwardingRule(data), nil +} + +func (api *PortForwardingRuleApi) ListWithOptions(options map[string]string) ([]PortForwardingRule, error) { + data, err := api.entityService.List(options) + if err != nil { + return nil, err + } + return parsePortForwardingRuleList(data), nil +} + +func (api *PortForwardingRuleApi) List() ([]PortForwardingRule, error) { + return api.ListWithOptions(map[string]string{}) +} + +func (api *PortForwardingRuleApi) Create(pfr PortForwardingRule) (*PortForwardingRule, error) { + msg, err := json.Marshal(pfr) + if err != nil { + return nil, err + } + result, err := api.entityService.Create(msg, map[string]string{}) + if err != nil { + return nil, err + } + return parsePortForwardingRule(result), nil +} + +func (api *PortForwardingRuleApi) Delete(id string) (bool, error) { + _, err := api.entityService.Delete(id, []byte{}, map[string]string{}) + return err == nil, err +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/public_ip.go b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/public_ip.go new file mode 100644 index 0000000..1809562 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/public_ip.go @@ -0,0 +1,111 @@ +package cloudca + +import ( + "encoding/json" + "github.com/cloud-ca/go-cloudca/api" + "github.com/cloud-ca/go-cloudca/services" +) + +const ( + PUBLIC_IP_ENABLE_STATIC_NAT_OPERATION = "enableStaticNat" + PUBLIC_IP_DISABLE_STATIC_NAT_OPERATION = "disableStaticNat" +) + +type PublicIp struct { + Id string `json:"id,omitempty"` + IpAddress string `json:"ipaddress,omitempty"` + State string `json:"state,omitempty"` + ZoneId string `json:"zoneId,omitempty"` + ZoneName string `json:"zoneName,omitempty"` + NetworkId string `json:"networkId,omitempty"` + NetworkName string `json:"networkName,omitempty"` + VpcId string `json:"vpcId,omitempty"` + VpcName string `json:"vpcName,omitempty"` + PrivateIpId string `json:"privateIpId,omitempty"` + InstanceNames []string `json:"instanceNames,omitempty"` + InstanceId string `json:"instanceId,omitempty"` + Purposes []string `json:"purposes,omitempty"` + Ports []string `json:"ports,omitempty"` +} + +type PublicIpService interface { + Get(id string) (*PublicIp, error) + List() ([]PublicIp, error) + Acquire(publicIp PublicIp) (*PublicIp, error) + Release(id string) (bool, error) + EnableStaticNat(publicIp PublicIp) (bool, error) + DisableStaticNat(id string) (bool, error) +} + +type PublicIpApi struct { + entityService services.EntityService +} + +func NewPublicIpService(apiClient api.ApiClient, serviceCode string, environmentName string) PublicIpService { + return &PublicIpApi{ + entityService: services.NewEntityService(apiClient, serviceCode, environmentName, PUBLIC_IP_ENTITY_TYPE), + } +} + +func parsePublicIp(data []byte) *PublicIp { + publicIp := PublicIp{} + json.Unmarshal(data, &publicIp) + return &publicIp +} + +func parsePublicIpList(data []byte) []PublicIp { + publicIps := []PublicIp{} + json.Unmarshal(data, &publicIps) + return publicIps +} + +func (publicIpApi *PublicIpApi) Get(id string) (*PublicIp, error) { + data, err := publicIpApi.entityService.Get(id, map[string]string{}) + if err != nil { + return nil, err + } + return parsePublicIp(data), nil +} + +func (publicIpApi *PublicIpApi) List() ([]PublicIp, error) { + return publicIpApi.ListWithOptions(map[string]string{}) +} + +func (publicIpApi *PublicIpApi) ListWithOptions(options map[string]string) ([]PublicIp, error) { + data, err := publicIpApi.entityService.List(options) + if err != nil { + return nil, err + } + return parsePublicIpList(data), nil +} + +func (publicIpApi *PublicIpApi) Acquire(publicIp PublicIp) (*PublicIp, error) { + send, merr := json.Marshal(publicIp) + if merr != nil { + return nil, merr + } + body, err := publicIpApi.entityService.Create(send, map[string]string{}) + if err != nil { + return nil, err + } + return parsePublicIp(body), nil +} + +func (publicIpApi *PublicIpApi) Release(id string) (bool, error) { + _, err := publicIpApi.entityService.Delete(id, []byte{}, map[string]string{}) + return err == nil, err +} + +func (publicIpApi *PublicIpApi) EnableStaticNat(publicIp PublicIp) (bool, error) { + send, merr := json.Marshal(publicIp) + if merr != nil { + return false, merr + } + _, err := publicIpApi.entityService.Execute(publicIp.Id, PUBLIC_IP_ENABLE_STATIC_NAT_OPERATION, send, map[string]string{}) + return err == nil, err +} + +func (publicIpApi *PublicIpApi) DisableStaticNat(id string) (bool, error) { + _, err := publicIpApi.entityService.Execute(id, PUBLIC_IP_DISABLE_STATIC_NAT_OPERATION, []byte{}, map[string]string{}) + return err == nil, err +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/recovery_point.go b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/recovery_point.go new file mode 100644 index 0000000..e19eaf8 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/recovery_point.go @@ -0,0 +1,6 @@ +package cloudca + +type RecoveryPoint struct { + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/remote_access_vpn.go b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/remote_access_vpn.go new file mode 100644 index 0000000..d9b08e6 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/remote_access_vpn.go @@ -0,0 +1,92 @@ +package cloudca + +import ( + "encoding/json" + + "github.com/cloud-ca/go-cloudca/api" + "github.com/cloud-ca/go-cloudca/services" +) + +const ( + REMOTE_ACCESS_VPN_ENABLE_OPERATION = "enable" + REMOTE_ACCESS_VPN_DISABLE_OPERATION = "disable" +) + +// RemoteAccessVpn is a VPN configuration which can connect a RemoteAccessVpnUser +type RemoteAccessVpn struct { + Certificate string `json:"certificate,omitempty"` + Id string `json:"id,omitempty"` + PresharedKey string `json:"presharedKey,omitempty"` + PublicIpAddress string `json:"publicIpAddress,omitempty"` + PublicIpAddressId string `json:"publicIpAddressId,omitempty"` + State string `json:"state,omitempty"` + Type string `json:"type,omitempty"` +} + +// RemoteAccessVpnService defines the interface which is implemented +type RemoteAccessVpnService interface { + Get(id string) (*RemoteAccessVpn, error) + List() ([]RemoteAccessVpn, error) + ListWithOptions(options map[string]string) ([]RemoteAccessVpn, error) + Enable(id string) (bool, error) + Disable(id string) (bool, error) +} + +// RemoteAccessVpnApi wraps the EntityService +type RemoteAccessVpnApi struct { + entityService services.EntityService +} + +// NewRemoteAccessVpnService creates a new VPN Service for this specific service and environment +func NewRemoteAccessVpnService(apiClient api.ApiClient, serviceCode string, environmentName string) RemoteAccessVpnService { + return &RemoteAccessVpnApi{ + entityService: services.NewEntityService(apiClient, serviceCode, environmentName, REMOTE_ACCESS_VPN_ENTITY_TYPE), + } +} + +func parseRemoteAccessVpn(data []byte) *RemoteAccessVpn { + remoteAccessVpn := RemoteAccessVpn{} + json.Unmarshal(data, &remoteAccessVpn) + return &remoteAccessVpn +} + +func parseRemoteAccessVpnList(data []byte) []RemoteAccessVpn { + remoteAccessVpns := []RemoteAccessVpn{} + json.Unmarshal(data, &remoteAccessVpns) + return remoteAccessVpns +} + +// Get a specific VPN in the current environment by its ID +func (remoteAccessVpnApi *RemoteAccessVpnApi) Get(id string) (*RemoteAccessVpn, error) { + data, err := remoteAccessVpnApi.entityService.Get(id, map[string]string{}) + if err != nil { + return nil, err + } + return parseRemoteAccessVpn(data), nil +} + +// List the available VPNs in the current environment +func (remoteAccessVpnApi *RemoteAccessVpnApi) List() ([]RemoteAccessVpn, error) { + return remoteAccessVpnApi.ListWithOptions(map[string]string{}) +} + +// ListWithOptions lists the available VPNs in the current environment with options +func (remoteAccessVpnApi *RemoteAccessVpnApi) ListWithOptions(options map[string]string) ([]RemoteAccessVpn, error) { + data, err := remoteAccessVpnApi.entityService.List(options) + if err != nil { + return nil, err + } + return parseRemoteAccessVpnList(data), nil +} + +// Enable a specific VPN in the current environment by its ID +func (remoteAccessVpnApi *RemoteAccessVpnApi) Enable(id string) (bool, error) { + _, err := remoteAccessVpnApi.entityService.Execute(id, REMOTE_ACCESS_VPN_ENABLE_OPERATION, []byte{}, map[string]string{}) + return err == nil, err +} + +// Disable a specific VPN in the current environment by its ID +func (remoteAccessVpnApi *RemoteAccessVpnApi) Disable(id string) (bool, error) { + _, err := remoteAccessVpnApi.entityService.Execute(id, REMOTE_ACCESS_VPN_DISABLE_OPERATION, []byte{}, map[string]string{}) + return err == nil, err +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/remote_access_vpn_user.go b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/remote_access_vpn_user.go new file mode 100644 index 0000000..63dc970 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/remote_access_vpn_user.go @@ -0,0 +1,85 @@ +package cloudca + +import ( + "encoding/json" + + "github.com/cloud-ca/go-cloudca/api" + "github.com/cloud-ca/go-cloudca/services" +) + +// RemoteAccessVpnUser is an environment wide user for a RemoteAccessVpn +type RemoteAccessVpnUser struct { + Id string `json:"id,omitempty"` + Username string `json:"username,omitempty"` + Password string `json:"password,omitempty"` +} + +// RemoteAccessVpnUserService defines the interface which is implemented +type RemoteAccessVpnUserService interface { + Get(id string) (*RemoteAccessVpnUser, error) + List() ([]RemoteAccessVpnUser, error) + Create(remoteAccessVpnUser RemoteAccessVpnUser) (bool, error) + Delete(remoteAccessVpnUser RemoteAccessVpnUser) (bool, error) +} + +// RemoteAccessVpnUserApi wraps the EntityService +type RemoteAccessVpnUserApi struct { + entityService services.EntityService +} + +// NewRemoteAccessVpnUserService creates a new VPN User Service for this specific service and environment +func NewRemoteAccessVpnUserService(apiClient api.ApiClient, serviceCode string, environmentName string) RemoteAccessVpnUserService { + return &RemoteAccessVpnUserApi{ + entityService: services.NewEntityService(apiClient, serviceCode, environmentName, REMOTE_ACCESS_VPN_USER_ENTITY_TYPE), + } +} + +func parseRemoteAccessVpnUser(data []byte) *RemoteAccessVpnUser { + remoteAccessVpnUser := RemoteAccessVpnUser{} + json.Unmarshal(data, &remoteAccessVpnUser) + return &remoteAccessVpnUser +} + +func parseRemoteAccessVpnUserList(data []byte) []RemoteAccessVpnUser { + remoteAccessVpnUsers := []RemoteAccessVpnUser{} + json.Unmarshal(data, &remoteAccessVpnUsers) + return remoteAccessVpnUsers +} + +// Get a specific VPN User in the current environment by their ID +func (remoteAccessVpnUserApi *RemoteAccessVpnUserApi) Get(id string) (*RemoteAccessVpnUser, error) { + data, err := remoteAccessVpnUserApi.entityService.Get(id, map[string]string{}) + if err != nil { + return nil, err + } + return parseRemoteAccessVpnUser(data), nil +} + +// List VPN Users for this environment +func (remoteAccessVpnUserApi *RemoteAccessVpnUserApi) List() ([]RemoteAccessVpnUser, error) { + data, err := remoteAccessVpnUserApi.entityService.List(map[string]string{}) + if err != nil { + return nil, err + } + return parseRemoteAccessVpnUserList(data), nil +} + +// Create a VPN User in the current environment +func (remoteAccessVpnUserApi *RemoteAccessVpnUserApi) Create(remoteAccessVpnUser RemoteAccessVpnUser) (bool, error) { + send, merr := json.Marshal(remoteAccessVpnUser) + if merr != nil { + return false, merr + } + _, err := remoteAccessVpnUserApi.entityService.Create(send, map[string]string{}) + return err == nil, err +} + +// Delete a specific VPN User in the current environment by their ID +func (remoteAccessVpnUserApi *RemoteAccessVpnUserApi) Delete(remoteAccessVpnUser RemoteAccessVpnUser) (bool, error) { + send, merr := json.Marshal(remoteAccessVpnUser) + if merr != nil { + return false, merr + } + _, err := remoteAccessVpnUserApi.entityService.Delete(remoteAccessVpnUser.Id, send, map[string]string{}) + return err == nil, err +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/resources.go b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/resources.go new file mode 100644 index 0000000..9af736f --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/resources.go @@ -0,0 +1,65 @@ +package cloudca + +import ( + "github.com/cloud-ca/go-cloudca/api" +) + +const ( + CLOUD_CA_SERVICE = "cloudca" +) + +type Resources struct { + apiClient api.ApiClient + serviceCode string + environmentName string + AffinityGroups AffinityGroupService + Instances InstanceService + Volumes VolumeService + Templates TemplateService + ComputeOfferings ComputeOfferingService + DiskOfferings DiskOfferingService + SSHKeys SSHKeyService + Networks NetworkService + Vpcs VpcService + VpcOfferings VpcOfferingService + NetworkOfferings NetworkOfferingService + PublicIps PublicIpService + NetworkAcls NetworkAclService + NetworkAclRules NetworkAclRuleService + Zones ZoneService + PortForwardingRules PortForwardingRuleService + LoadBalancerRules LoadBalancerRuleService + RemoteAccessVpn RemoteAccessVpnService + RemoteAccessVpnUser RemoteAccessVpnUserService +} + +func NewResources(apiClient api.ApiClient, serviceCode string, environmentName string) Resources { + return Resources{ + apiClient: apiClient, + serviceCode: serviceCode, + environmentName: environmentName, + AffinityGroups: NewAffinityGroupsService(apiClient, serviceCode, environmentName), + Instances: NewInstanceService(apiClient, serviceCode, environmentName), + Volumes: NewVolumeService(apiClient, serviceCode, environmentName), + Templates: NewTemplateService(apiClient, serviceCode, environmentName), + ComputeOfferings: NewComputeOfferingService(apiClient, serviceCode, environmentName), + DiskOfferings: NewDiskOfferingService(apiClient, serviceCode, environmentName), + Networks: NewNetworkService(apiClient, serviceCode, environmentName), + Vpcs: NewVpcService(apiClient, serviceCode, environmentName), + VpcOfferings: NewVpcOfferingService(apiClient, serviceCode, environmentName), + NetworkOfferings: NewNetworkOfferingService(apiClient, serviceCode, environmentName), + NetworkAcls: NewNetworkAclService(apiClient, serviceCode, environmentName), + NetworkAclRules: NewNetworkAclRuleService(apiClient, serviceCode, environmentName), + PublicIps: NewPublicIpService(apiClient, serviceCode, environmentName), + PortForwardingRules: NewPortForwardingRuleService(apiClient, serviceCode, environmentName), + LoadBalancerRules: NewLoadBalancerRuleService(apiClient, serviceCode, environmentName), + Zones: NewZoneService(apiClient, serviceCode, environmentName), + SSHKeys: NewSSHKeyService(apiClient, serviceCode, environmentName), + RemoteAccessVpn: NewRemoteAccessVpnService(apiClient, serviceCode, environmentName), + RemoteAccessVpnUser: NewRemoteAccessVpnUserService(apiClient, serviceCode, environmentName), + } +} + +func (resources Resources) GetServiceType() string { + return CLOUD_CA_SERVICE +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/ssh_key.go b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/ssh_key.go new file mode 100644 index 0000000..3e54b03 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/ssh_key.go @@ -0,0 +1,87 @@ +package cloudca + +import ( + "encoding/json" + + "github.com/cloud-ca/go-cloudca/api" + "github.com/cloud-ca/go-cloudca/services" +) + +type SSHKey struct { + ID string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + PublicKey string `json:"publicKey,omitempty"` + Fingerprint string `json:"fingerprint,omitempty"` +} + +type SSHKeyService interface { + Get(name string) (*SSHKey, error) + List() ([]SSHKey, error) + ListWithOptions(options map[string]string) ([]SSHKey, error) + Create(key SSHKey) (*SSHKey, error) + Delete(id string) (bool, error) +} + +type SSHKeyApi struct { + entityService services.EntityService +} + +func NewSSHKeyService(apiClient api.ApiClient, serviceCode string, environmentName string) SSHKeyService { + return &SSHKeyApi{ + entityService: services.NewEntityService(apiClient, serviceCode, environmentName, SSH_KEY_ENTITY_TYPE), + } +} + +func parseSSHKey(data []byte) *SSHKey { + var sshKey SSHKey + json.Unmarshal(data, &sshKey) + return &sshKey +} + +func parseSSHKeyList(data []byte) []SSHKey { + sshKeys := []SSHKey{} + json.Unmarshal(data, &sshKeys) + return sshKeys +} + +//Get SSH key with the specified id for the current environment +func (sshKeyApi *SSHKeyApi) Get(name string) (*SSHKey, error) { + data, err := sshKeyApi.entityService.Get(name, map[string]string{}) + if err != nil { + return nil, err + } + return parseSSHKey(data), nil +} + +//List all SSH keys for the current environment +func (sshKeyApi *SSHKeyApi) List() ([]SSHKey, error) { + return sshKeyApi.ListWithOptions(map[string]string{}) +} + +//List all SSH keys for the current environment. Can use options to do sorting and paging. +func (sshKeyApi *SSHKeyApi) ListWithOptions(options map[string]string) ([]SSHKey, error) { + data, err := sshKeyApi.entityService.List(options) + if err != nil { + return nil, err + } + return parseSSHKeyList(data), nil +} + +//Create an SSH key in the current environment +func (sshKeyApi *SSHKeyApi) Create(key SSHKey) (*SSHKey, error) { + send, merr := json.Marshal(key) + if merr != nil { + return nil, merr + } + body, err := sshKeyApi.entityService.Create(send, map[string]string{}) + if err != nil { + return nil, err + } + return parseSSHKey(body), nil +} + +//Delete an SSH Key with specified id in the current environment +func (sshKeyApi *SSHKeyApi) Delete(id string) (bool, error) { + _, err := sshKeyApi.entityService.Delete(id, []byte{}, map[string]string{}) + return err == nil, err +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/template.go b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/template.go new file mode 100644 index 0000000..66ac2f6 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/template.go @@ -0,0 +1,99 @@ +package cloudca + +import ( + "encoding/json" + + "github.com/cloud-ca/go-cloudca/api" + "github.com/cloud-ca/go-cloudca/services" +) + +type Template struct { + ID string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + Size int `json:"size,omitempty"` + AvailablePublicly bool `json:availablePublicly` + Ready bool `json:"ready,omitempty"` + SSHKeyEnabled bool `json:"sshKeyEnabled,omitempty"` + PassowordEnabled bool `json:"passwordEnabled,omitempty"` + Extractable bool `json:"extractable,omitempty"` + Resizable bool `json:"resizable,omitempty"` + OSType string `json:"osType,omitempty"` + OSTypeID string `json:"osTypeId,omitempty"` + Hypervisor string `json:"hypervisor,omitempty"` + Format string `json:"format,omitempty"` + ProjectID string `json:"projectId,omitempty"` + URL string `json:"url,omitempty"` + ZoneID string `json:"zoneId,omitempty"` + AvailableInZones []string `json:"availableInZones,omitempty"` +} + +type TemplateService interface { + Get(id string) (*Template, error) + List() ([]Template, error) + ListWithOptions(options map[string]string) ([]Template, error) + Create(Template) (*Template, error) + Delete(id string) (bool, error) +} + +type TemplateApi struct { + entityService services.EntityService +} + +func NewTemplateService(apiClient api.ApiClient, serviceCode string, environmentName string) TemplateService { + return &TemplateApi{ + entityService: services.NewEntityService(apiClient, serviceCode, environmentName, TEMPLATE_ENTITY_TYPE), + } +} + +func parseTemplate(data []byte) *Template { + template := Template{} + json.Unmarshal(data, &template) + return &template +} + +func parseTemplateList(data []byte) []Template { + templates := []Template{} + json.Unmarshal(data, &templates) + return templates +} + +//Get template with the specified id for the current environment +func (templateApi *TemplateApi) Get(id string) (*Template, error) { + data, err := templateApi.entityService.Get(id, map[string]string{}) + if err != nil { + return nil, err + } + return parseTemplate(data), nil +} + +//List all templates for the current environment +func (templateApi *TemplateApi) List() ([]Template, error) { + return templateApi.ListWithOptions(map[string]string{}) +} + +//List all templates for the current environment. Can use options to do sorting and paging. +func (templateApi *TemplateApi) ListWithOptions(options map[string]string) ([]Template, error) { + data, err := templateApi.entityService.List(options) + if err != nil { + return nil, err + } + return parseTemplateList(data), nil +} + +func (templateApi *TemplateApi) Create(t Template) (*Template, error) { + send, merr := json.Marshal(t) + if merr != nil { + return nil, merr + } + body, err := templateApi.entityService.Create(send, map[string]string{}) + if err != nil { + return nil, err + } + return parseTemplate(body), nil +} + +func (templateApi *TemplateApi) Delete(id string) (bool, error) { + _, err := templateApi.entityService.Delete(id, []byte{}, map[string]string{}) + return err == nil, err +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/volume.go b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/volume.go new file mode 100644 index 0000000..930d85c --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/volume.go @@ -0,0 +1,138 @@ +package cloudca + +import ( + "encoding/json" + + "github.com/cloud-ca/go-cloudca/api" + "github.com/cloud-ca/go-cloudca/services" +) + +const ( + VOLUME_TYPE_OS = "OS" + VOLUME_TYPE_DATA = "DATA" +) + +type Volume struct { + Id string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Type string `json:"type,omitempty"` + CreationDate string `json:"creationDate,omitempty"` + Size int `json:"size,omitempty"` + GbSize int `json:"sizeInGb,omitempty"` + DiskOfferingId string `json:"diskOfferingId,omitempty"` + DiskOfferingName string `json:"diskOfferingName,omitempty"` + TemplateId string `json:"templateId,omitempty"` + ZoneName string `json:"zoneName,omitempty"` + ZoneId string `json:"zoneId,omitempty"` + State string `json:"state,omitempty"` + InstanceName string `json:"instanceName,omitempty"` + InstanceId string `json:"instanceId,omitempty"` + InstanceState string `json:"instanceState,omitempty"` + Iops int `json:"iops,omitempty"` +} + +type VolumeService interface { + Get(id string) (*Volume, error) + List() ([]Volume, error) + ListOfType(volumeType string) ([]Volume, error) + ListWithOptions(options map[string]string) ([]Volume, error) + Create(Volume) (*Volume, error) + Resize(*Volume) error + Delete(string) error + AttachToInstance(*Volume, string) error + DetachFromInstance(*Volume) error +} + +type VolumeApi struct { + entityService services.EntityService +} + +func NewVolumeService(apiClient api.ApiClient, serviceCode string, environmentName string) VolumeService { + return &VolumeApi{ + entityService: services.NewEntityService(apiClient, serviceCode, environmentName, VOLUME_ENTITY_TYPE), + } +} + +func parseVolume(data []byte) *Volume { + volume := Volume{} + json.Unmarshal(data, &volume) + return &volume +} + +func parseVolumeList(data []byte) []Volume { + volumes := []Volume{} + json.Unmarshal(data, &volumes) + return volumes +} + +//Get volume with the specified id for the current environment +func (volumeApi *VolumeApi) Get(id string) (*Volume, error) { + data, err := volumeApi.entityService.Get(id, map[string]string{}) + if err != nil { + return nil, err + } + return parseVolume(data), nil +} + +//List all volumes for the current environment +func (volumeApi *VolumeApi) List() ([]Volume, error) { + return volumeApi.ListWithOptions(map[string]string{}) +} + +//List all volumes of specified type for the current environment +func (volumeApi *VolumeApi) ListOfType(volumeType string) ([]Volume, error) { + return volumeApi.ListWithOptions(map[string]string{ + "type": volumeType, + }) +} + +//List all volumes for the current environment. Can use options to do sorting and paging. +func (volumeApi *VolumeApi) ListWithOptions(options map[string]string) ([]Volume, error) { + data, err := volumeApi.entityService.List(options) + if err != nil { + return nil, err + } + return parseVolumeList(data), nil +} + +func (api *VolumeApi) Create(volume Volume) (*Volume, error) { + body, err := json.Marshal(volume) + if err != nil { + return nil, err + } + res, err := api.entityService.Create(body, map[string]string{}) + if err != nil { + return nil, err + } + return parseVolume(res), nil +} + +func (api *VolumeApi) Delete(volumeId string) error { + _, err := api.entityService.Delete(volumeId, []byte{}, map[string]string{}) + return err +} + +func (api *VolumeApi) Resize(volume *Volume) error { + body, err := json.Marshal(volume) + if err != nil { + return err + } + _, err = api.entityService.Execute(volume.Id, "resize", body, map[string]string{}) + return err +} + +func (api *VolumeApi) AttachToInstance(volume *Volume, instanceId string) error { + body, err := json.Marshal(Volume{ + InstanceId: instanceId, + }) + if err != nil { + return err + } + _, err = api.entityService.Execute(volume.Id, "attachToInstance", body, map[string]string{}) + return err +} + +func (api *VolumeApi) DetachFromInstance(volume *Volume) error { + _, err := api.entityService.Execute(volume.Id, "detachFromInstance", []byte{}, map[string]string{}) + return err +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/vpc.go b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/vpc.go new file mode 100644 index 0000000..bbde7a4 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/vpc.go @@ -0,0 +1,119 @@ +package cloudca + +import ( + "encoding/json" + "github.com/cloud-ca/go-cloudca/api" + "github.com/cloud-ca/go-cloudca/services" +) + +const ( + VPC_RESTART_ROUTER_OPERATION = "restart" +) + +type Vpc struct { + Id string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + VpcOfferingId string `json:"vpcOfferingId,omitempty"` + State string `json:"state,omitempty"` + Cidr string `json:"cidr,omitempty"` + ZoneId string `json:"zoneId,omitempty"` + ZoneName string `json:"zoneName,omitempty"` + NetworkDomain string `json:"networkDomain,omitempty"` + SourceNatIp string `json:"sourceNatIp,omitempty"` + VpnStatus string `json:"vpnStatus,omitempty"` + Type string `json:"type,omitempty"` +} + +type VpcService interface { + Get(id string) (*Vpc, error) + List() ([]Vpc, error) + ListWithOptions(options map[string]string) ([]Vpc, error) + Create(vpc Vpc) (*Vpc, error) + Update(vpc Vpc) (*Vpc, error) + Destroy(id string) (bool, error) + RestartRouter(id string) (bool, error) +} + +type VpcApi struct { + entityService services.EntityService +} + +func NewVpcService(apiClient api.ApiClient, serviceCode string, environmentName string) VpcService { + return &VpcApi{ + entityService: services.NewEntityService(apiClient, serviceCode, environmentName, VPC_ENTITY_TYPE), + } +} + +func parseVpc(data []byte) *Vpc { + vpc := Vpc{} + json.Unmarshal(data, &vpc) + return &vpc +} + +func parseVpcList(data []byte) []Vpc { + vpcs := []Vpc{} + json.Unmarshal(data, &vpcs) + return vpcs +} + +//Get vpc with the specified id for the current environment +func (vpcApi *VpcApi) Get(id string) (*Vpc, error) { + data, err := vpcApi.entityService.Get(id, map[string]string{}) + if err != nil { + return nil, err + } + return parseVpc(data), nil +} + +//List all vpcs for the current environment +func (vpcApi *VpcApi) List() ([]Vpc, error) { + return vpcApi.ListWithOptions(map[string]string{}) +} + +//List all vpcs for the current environment. Can use options to do sorting and paging. +func (vpcApi *VpcApi) ListWithOptions(options map[string]string) ([]Vpc, error) { + data, err := vpcApi.entityService.List(options) + if err != nil { + return nil, err + } + return parseVpcList(data), nil +} + +//Create an vpc in the current environment +func (vpcApi *VpcApi) Create(vpc Vpc) (*Vpc, error) { + send, merr := json.Marshal(vpc) + if merr != nil { + return nil, merr + } + body, err := vpcApi.entityService.Create(send, map[string]string{}) + if err != nil { + return nil, err + } + return parseVpc(body), nil +} + +//Create an vpc in the current environment +func (vpcApi *VpcApi) Update(vpc Vpc) (*Vpc, error) { + send, merr := json.Marshal(vpc) + if merr != nil { + return nil, merr + } + body, err := vpcApi.entityService.Update(vpc.Id, send, map[string]string{}) + if err != nil { + return nil, err + } + return parseVpc(body), nil +} + +//Destroy a vpc with specified id in the current environment +func (vpcApi *VpcApi) Destroy(id string) (bool, error) { + _, err := vpcApi.entityService.Delete(id, []byte{}, map[string]string{}) + return err == nil, err +} + +//Restart the router of the vpc with the specified id exists in the current environment +func (vpcApi *VpcApi) RestartRouter(id string) (bool, error) { + _, err := vpcApi.entityService.Execute(id, VPC_RESTART_ROUTER_OPERATION, []byte{}, map[string]string{}) + return err == nil, err +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/vpc_offering.go b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/vpc_offering.go new file mode 100644 index 0000000..1f5b52d --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/vpc_offering.go @@ -0,0 +1,64 @@ +package cloudca + +import ( + "encoding/json" + "github.com/cloud-ca/go-cloudca/api" + "github.com/cloud-ca/go-cloudca/services" +) + +type VpcOffering struct { + Id string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + State string `json:"state,omitempty"` +} + +type VpcOfferingService interface { + Get(id string) (*VpcOffering, error) + List() ([]VpcOffering, error) + ListWithOptions(options map[string]string) ([]VpcOffering, error) +} + +type VpcOfferingApi struct { + entityService services.EntityService +} + +func NewVpcOfferingService(apiClient api.ApiClient, serviceCode string, environmentName string) VpcOfferingService { + return &VpcOfferingApi{ + entityService: services.NewEntityService(apiClient, serviceCode, environmentName, VPC_OFFERING_ENTITY_TYPE), + } +} + +func parseVpcOffering(data []byte) *VpcOffering { + vpcOffering := VpcOffering{} + json.Unmarshal(data, &vpcOffering) + return &vpcOffering +} + +func parseVpcOfferingList(data []byte) []VpcOffering { + vpcOfferings := []VpcOffering{} + json.Unmarshal(data, &vpcOfferings) + return vpcOfferings +} + +//Get disk offering with the specified id for the current environment +func (vpcOfferingApi *VpcOfferingApi) Get(id string) (*VpcOffering, error) { + data, err := vpcOfferingApi.entityService.Get(id, map[string]string{}) + if err != nil { + return nil, err + } + return parseVpcOffering(data), nil +} + +//List all disk offerings for the current environment +func (vpcOfferingApi *VpcOfferingApi) List() ([]VpcOffering, error) { + return vpcOfferingApi.ListWithOptions(map[string]string{}) +} + +//List all disk offerings for the current environment. Can use options to do sorting and paging. +func (vpcOfferingApi *VpcOfferingApi) ListWithOptions(options map[string]string) ([]VpcOffering, error) { + data, err := vpcOfferingApi.entityService.List(options) + if err != nil { + return nil, err + } + return parseVpcOfferingList(data), nil +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/zone.go b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/zone.go new file mode 100644 index 0000000..c64d491 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/services/cloudca/zone.go @@ -0,0 +1,60 @@ +package cloudca + +import ( + "encoding/json" + "github.com/cloud-ca/go-cloudca/api" + "github.com/cloud-ca/go-cloudca/services" +) + +type Zone struct { + Id string `json:"id,omitempty"` + Name string `json:"name,omitempty"` +} + +type ZoneService interface { + Get(string) (*Zone, error) + List() ([]Zone, error) + ListWithOptions(map[string]string) ([]Zone, error) +} + +type ZoneApi struct { + entityService services.EntityService +} + +func NewZoneService(apiClient api.ApiClient, serviceCode string, environmentName string) ZoneService { + return &ZoneApi{ + entityService: services.NewEntityService(apiClient, serviceCode, environmentName, ZONE_ENTITY_TYPE), + } +} + +func parseZone(data []byte) *Zone { + zone := Zone{} + json.Unmarshal(data, &zone) + return &zone +} + +func parseZoneList(data []byte) []Zone { + zones := []Zone{} + json.Unmarshal(data, &zones) + return zones +} + +func (api *ZoneApi) Get(id string) (*Zone, error) { + resp, err := api.entityService.Get(id, map[string]string{}) + if err != nil { + return nil, err + } + return parseZone(resp), nil +} + +func (api *ZoneApi) List() ([]Zone, error) { + return api.ListWithOptions(map[string]string{}) +} + +func (api *ZoneApi) ListWithOptions(options map[string]string) ([]Zone, error) { + resp, err := api.entityService.List(options) + if err != nil { + return nil, err + } + return parseZoneList(resp), nil +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/services/entity.go b/vendor/github.com/cloud-ca/go-cloudca/services/entity.go new file mode 100644 index 0000000..f0e5398 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/services/entity.go @@ -0,0 +1,148 @@ +package services + +import ( + "github.com/cloud-ca/go-cloudca/api" +) + +//A generic service to access any entity +type EntityService interface { + Get(id string, options map[string]string) ([]byte, error) + List(options map[string]string) ([]byte, error) + Execute(id string, operation string, body []byte, options map[string]string) ([]byte, error) + Create(body []byte, options map[string]string) ([]byte, error) + Update(id string, body []byte, options map[string]string) ([]byte, error) + Delete(id string, body []byte, options map[string]string) ([]byte, error) +} + +//Implementation of the EntityService +type EntityApi struct { + apiClient api.ApiClient + taskService TaskService + serviceCode string + environmentName string + entityType string +} + +func NewEntityService(apiClient api.ApiClient, serviceCode string, environmentName string, entityType string) EntityService { + return &EntityApi{ + apiClient: apiClient, + taskService: NewTaskService(apiClient), + serviceCode: serviceCode, + environmentName: environmentName, + entityType: entityType, + } +} + +func (entityApi *EntityApi) buildEndpoint() string { + return "/services/" + entityApi.serviceCode + "/" + entityApi.environmentName + "/" + entityApi.entityType +} + +//Get an entity. Returns a []byte (of a json object) that should be unmarshalled to a specific entity +func (entityApi *EntityApi) Get(id string, options map[string]string) ([]byte, error) { + request := api.CcaRequest{ + Method: api.GET, + Endpoint: entityApi.buildEndpoint() + "/" + id, + Options: options, + } + response, err := entityApi.apiClient.Do(request) + if err != nil { + return nil, err + } else if response.IsError() { + return nil, api.CcaErrorResponse(*response) + } + return response.Data, nil +} + +//Get an entity list. Returns a []byte (of a json object) that should be unmarshalled to a specific entity +func (entityApi *EntityApi) List(options map[string]string) ([]byte, error) { + request := api.CcaRequest{ + Method: api.GET, + Endpoint: entityApi.buildEndpoint(), + Options: options, + } + response, err := entityApi.apiClient.Do(request) + if err != nil { + return nil, err + } else if response.IsError() { + return nil, api.CcaErrorResponse(*response) + } + return response.Data, nil +} + +//Execute a specific operation on an entity. Returns a []byte (of a json object) that should be unmarshalled to a specific entity +func (entityApi *EntityApi) Execute(id string, operation string, body []byte, options map[string]string) ([]byte, error) { + optionsCopy := map[string]string{} + for k, v := range options { + optionsCopy[k] = v + } + optionsCopy["operation"] = operation + endpoint := entityApi.buildEndpoint() + if id != "" { + endpoint = endpoint + "/" + id + } + request := api.CcaRequest{ + Method: api.POST, + Body: body, + Endpoint: endpoint, + Options: optionsCopy, + } + response, err := entityApi.apiClient.Do(request) + if err != nil { + return nil, err + } else if response.IsError() { + return nil, api.CcaErrorResponse(*response) + } + + return entityApi.taskService.PollResponse(response, DEFAULT_POLLING_INTERVAL) +} + +//Create a new entity described in the body parameter (json object). Returns a []byte (of a json object) that should be unmarshalled to a specific entity +func (entityApi *EntityApi) Create(body []byte, options map[string]string) ([]byte, error) { + request := api.CcaRequest{ + Method: api.POST, + Body: body, + Endpoint: entityApi.buildEndpoint(), + Options: options, + } + response, err := entityApi.apiClient.Do(request) + if err != nil { + return nil, err + } else if response.IsError() { + return nil, api.CcaErrorResponse(*response) + } + return entityApi.taskService.PollResponse(response, DEFAULT_POLLING_INTERVAL) +} + +//Update entity with specified id described in the body parameter (json object). Returns a []byte (of a json object) that should be unmarshalled to a specific entity +func (entityApi *EntityApi) Update(id string, body []byte, options map[string]string) ([]byte, error) { + request := api.CcaRequest{ + Method: api.PUT, + Body: body, + Endpoint: entityApi.buildEndpoint() + "/" + id, + Options: options, + } + response, err := entityApi.apiClient.Do(request) + if err != nil { + return nil, err + } else if response.IsError() { + return nil, api.CcaErrorResponse(*response) + } + return entityApi.taskService.PollResponse(response, DEFAULT_POLLING_INTERVAL) +} + +//Delete specified id described. A body (json object) can be provided if some fields must be sent to server. Returns a []byte (of a json object) that should be unmarshalled to a specific entity +func (entityApi EntityApi) Delete(id string, body []byte, options map[string]string) ([]byte, error) { + request := api.CcaRequest{ + Method: api.DELETE, + Body: body, + Endpoint: entityApi.buildEndpoint() + "/" + id, + Options: options, + } + response, err := entityApi.apiClient.Do(request) + if err != nil { + return nil, err + } else if response.IsError() { + return nil, api.CcaErrorResponse(*response) + } + return entityApi.taskService.PollResponse(response, DEFAULT_POLLING_INTERVAL) +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/services/service.go b/vendor/github.com/cloud-ca/go-cloudca/services/service.go new file mode 100644 index 0000000..76abf79 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/services/service.go @@ -0,0 +1,6 @@ +package services + +//Holds all the resources available for a particular service +type ServiceResources interface { + GetServiceType() string +} diff --git a/vendor/github.com/cloud-ca/go-cloudca/services/task.go b/vendor/github.com/cloud-ca/go-cloudca/services/task.go new file mode 100644 index 0000000..966bd76 --- /dev/null +++ b/vendor/github.com/cloud-ca/go-cloudca/services/task.go @@ -0,0 +1,127 @@ +package services + +import ( + "encoding/json" + "github.com/cloud-ca/go-cloudca/api" + "strings" + "time" +) + +//Task status +const ( + PENDING = "PENDING" + SUCCESS = "SUCCESS" + FAILED = "FAILED" +) + +const DEFAULT_POLLING_INTERVAL = 1000 + +//A Task object. This object can be used to poll asynchronous operations. +type Task struct { + Id string + Status string + Created string + Result []byte +} + +type FailedTask Task + +func (ft FailedTask) Error() string { + return "Task id=" + ft.Id + " failed" //should add reason +} + +type TaskService interface { + Get(id string) (*Task, error) + Poll(id string, milliseconds time.Duration) ([]byte, error) + PollResponse(response *api.CcaResponse, milliseconds time.Duration) ([]byte, error) +} + +type TaskApi struct { + apiClient api.ApiClient +} + +//Create a new TaskService +func NewTaskService(apiClient api.ApiClient) TaskService { + return &TaskApi{ + apiClient: apiClient, + } +} + +//Retrieve a Task with sepecified id +func (taskApi *TaskApi) Get(id string) (*Task, error) { + request := api.CcaRequest{ + Method: api.GET, + Endpoint: "tasks/" + id, + } + response, err := taskApi.apiClient.Do(request) + if err != nil { + return nil, err + } else if len(response.Errors) > 0 { + return nil, api.CcaErrorResponse(*response) + } + data := response.Data + taskMap := map[string]*json.RawMessage{} + json.Unmarshal(data, &taskMap) + + task := Task{} + json.Unmarshal(*taskMap["id"], &task.Id) + json.Unmarshal(*taskMap["status"], &task.Status) + json.Unmarshal(*taskMap["created"], &task.Created) + if val, ok := taskMap["result"]; ok { + task.Result = []byte(*val) + } + return &task, nil +} + +//Poll an the Task API. Blocks until success or failure. +//Returns result on success, an error otherwise +func (taskApi *TaskApi) Poll(id string, milliseconds time.Duration) ([]byte, error) { + ticker := time.NewTicker(time.Millisecond * milliseconds) + task, err := taskApi.Get(id) + if err != nil { + return nil, err + } + done := task.Completed() + for !done { + <-ticker.C + task, err = taskApi.Get(id) + if err != nil { + return nil, err + } + done = task.Completed() + } + if task.Failed() { + return nil, FailedTask(*task) + } + return task.Result, nil +} + +//Poll an the Task API. Blocks until success or failure +func (taskApi *TaskApi) PollResponse(response *api.CcaResponse, milliseconds time.Duration) ([]byte, error) { + if strings.EqualFold(response.TaskStatus, SUCCESS) { + return response.Data, nil + } else if strings.EqualFold(response.TaskStatus, FAILED) { + return nil, api.CcaErrorResponse(*response) + } + return taskApi.Poll(response.TaskId, milliseconds) +} + +//Returns true if task has failed +func (task Task) Failed() bool { + return strings.EqualFold(task.Status, FAILED) +} + +//Returns true if task was successful +func (task Task) Success() bool { + return strings.EqualFold(task.Status, SUCCESS) +} + +//Returns true if task is still executing +func (task Task) Pending() bool { + return strings.EqualFold(task.Status, PENDING) +} + +//Returns true if task has completed its execution +func (task Task) Completed() bool { + return !task.Pending() +} diff --git a/vendor/github.com/tidwall/pretty/.travis.yml b/vendor/github.com/tidwall/pretty/.travis.yml new file mode 100644 index 0000000..4f2ee4d --- /dev/null +++ b/vendor/github.com/tidwall/pretty/.travis.yml @@ -0,0 +1 @@ +language: go diff --git a/vendor/github.com/tidwall/pretty/LICENSE b/vendor/github.com/tidwall/pretty/LICENSE new file mode 100644 index 0000000..993b83f --- /dev/null +++ b/vendor/github.com/tidwall/pretty/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2017 Josh Baker + +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. diff --git a/vendor/github.com/tidwall/pretty/README.md b/vendor/github.com/tidwall/pretty/README.md new file mode 100644 index 0000000..d2b8864 --- /dev/null +++ b/vendor/github.com/tidwall/pretty/README.md @@ -0,0 +1,124 @@ +# Pretty +[![Build Status](https://img.shields.io/travis/tidwall/pretty.svg?style=flat-square)](https://travis-ci.org/tidwall/prettty) +[![Coverage Status](https://img.shields.io/badge/coverage-100%25-brightgreen.svg?style=flat-square)](http://gocover.io/github.com/tidwall/pretty) +[![GoDoc](https://img.shields.io/badge/api-reference-blue.svg?style=flat-square)](https://godoc.org/github.com/tidwall/pretty) + + +Pretty is a Go package that provides [fast](#performance) methods for formatting JSON for human readability, or to compact JSON for smaller payloads. + +Getting Started +=============== + +## Installing + +To start using Pretty, install Go and run `go get`: + +```sh +$ go get -u github.com/tidwall/pretty +``` + +This will retrieve the library. + +## Pretty + +Using this example: + +```json +{"name": {"first":"Tom","last":"Anderson"}, "age":37, +"children": ["Sara","Alex","Jack"], +"fav.movie": "Deer Hunter", "friends": [ + {"first": "Janet", "last": "Murphy", "age": 44} + ]} +``` + +The following code: +```go +result = pretty.Pretty(example) +``` + +Will format the json to: + +```json +{ + "name": { + "first": "Tom", + "last": "Anderson" + }, + "age": 37, + "children": ["Sara", "Alex", "Jack"], + "fav.movie": "Deer Hunter", + "friends": [ + { + "first": "Janet", + "last": "Murphy", + "age": 44 + } + ] +} +``` + +## Color + +Color will colorize the json for outputing to the screen. + +```json +result = pretty.Color(json, nil) +``` + +Will add color to the result for printing to the terminal. +The second param is used for a customizing the style, and passing nil will use the default `pretty.TerminalStyle`. + +## Ugly + +The following code: +```go +result = pretty.Ugly(example) +``` + +Will format the json to: + +```json +{"name":{"first":"Tom","last":"Anderson"},"age":37,"children":["Sara","Alex","Jack"],"fav.movie":"Deer Hunter","friends":[{"first":"Janet","last":"Murphy","age":44}]}``` +``` + + +## Customized output + +There's a `PrettyOptions(json, opts)` function which allows for customizing the output with the following options: + +```go +type Options struct { + // Width is an max column width for single line arrays + // Default is 80 + Width int + // Prefix is a prefix for all lines + // Default is an empty string + Prefix string + // Indent is the nested indentation + // Default is two spaces + Indent string + // SortKeys will sort the keys alphabetically + // Default is false + SortKeys bool +} +``` +## Performance + +Benchmarks of Pretty alongside the builtin `encoding/json` Indent/Compact methods. +``` +BenchmarkPretty-8 1000000 1283 ns/op 720 B/op 2 allocs/op +BenchmarkUgly-8 3000000 426 ns/op 240 B/op 1 allocs/op +BenchmarkUglyInPlace-8 5000000 340 ns/op 0 B/op 0 allocs/op +BenchmarkJSONIndent-8 300000 4628 ns/op 1069 B/op 4 allocs/op +BenchmarkJSONCompact-8 1000000 2469 ns/op 758 B/op 4 allocs/op +``` + +*These benchmarks were run on a MacBook Pro 15" 2.8 GHz Intel Core i7 using Go 1.7.* + +## Contact +Josh Baker [@tidwall](http://twitter.com/tidwall) + +## License + +Pretty source code is available under the MIT [License](/LICENSE). + diff --git a/vendor/github.com/tidwall/pretty/pretty.go b/vendor/github.com/tidwall/pretty/pretty.go new file mode 100644 index 0000000..0a922d0 --- /dev/null +++ b/vendor/github.com/tidwall/pretty/pretty.go @@ -0,0 +1,432 @@ +package pretty + +import ( + "sort" +) + +// Options is Pretty options +type Options struct { + // Width is an max column width for single line arrays + // Default is 80 + Width int + // Prefix is a prefix for all lines + // Default is an empty string + Prefix string + // Indent is the nested indentation + // Default is two spaces + Indent string + // SortKeys will sort the keys alphabetically + // Default is false + SortKeys bool +} + +// DefaultOptions is the default options for pretty formats. +var DefaultOptions = &Options{Width: 80, Prefix: "", Indent: " ", SortKeys: false} + +// Pretty converts the input json into a more human readable format where each +// element is on it's own line with clear indentation. +func Pretty(json []byte) []byte { return PrettyOptions(json, nil) } + +// PrettyOptions is like Pretty but with customized options. +func PrettyOptions(json []byte, opts *Options) []byte { + if opts == nil { + opts = DefaultOptions + } + buf := make([]byte, 0, len(json)) + if len(opts.Prefix) != 0 { + buf = append(buf, opts.Prefix...) + } + buf, _, _, _ = appendPrettyAny(buf, json, 0, true, + opts.Width, opts.Prefix, opts.Indent, opts.SortKeys, + 0, 0, -1) + if len(buf) > 0 { + buf = append(buf, '\n') + } + return buf +} + +// Ugly removes insignificant space characters from the input json byte slice +// and returns the compacted result. +func Ugly(json []byte) []byte { + buf := make([]byte, 0, len(json)) + return ugly(buf, json) +} + +// UglyInPlace removes insignificant space characters from the input json +// byte slice and returns the compacted result. This method reuses the +// input json buffer to avoid allocations. Do not use the original bytes +// slice upon return. +func UglyInPlace(json []byte) []byte { return ugly(json, json) } + +func ugly(dst, src []byte) []byte { + dst = dst[:0] + for i := 0; i < len(src); i++ { + if src[i] > ' ' { + dst = append(dst, src[i]) + if src[i] == '"' { + for i = i + 1; i < len(src); i++ { + dst = append(dst, src[i]) + if src[i] == '"' { + j := i - 1 + for ; ; j-- { + if src[j] != '\\' { + break + } + } + if (j-i)%2 != 0 { + break + } + } + } + } + } + } + return dst +} + +func appendPrettyAny(buf, json []byte, i int, pretty bool, width int, prefix, indent string, sortkeys bool, tabs, nl, max int) ([]byte, int, int, bool) { + for ; i < len(json); i++ { + if json[i] <= ' ' { + continue + } + if json[i] == '"' { + return appendPrettyString(buf, json, i, nl) + } + if (json[i] >= '0' && json[i] <= '9') || json[i] == '-' { + return appendPrettyNumber(buf, json, i, nl) + } + if json[i] == '{' { + return appendPrettyObject(buf, json, i, '{', '}', pretty, width, prefix, indent, sortkeys, tabs, nl, max) + } + if json[i] == '[' { + return appendPrettyObject(buf, json, i, '[', ']', pretty, width, prefix, indent, sortkeys, tabs, nl, max) + } + switch json[i] { + case 't': + return append(buf, 't', 'r', 'u', 'e'), i + 4, nl, true + case 'f': + return append(buf, 'f', 'a', 'l', 's', 'e'), i + 5, nl, true + case 'n': + return append(buf, 'n', 'u', 'l', 'l'), i + 4, nl, true + } + } + return buf, i, nl, true +} + +type pair struct { + kstart, kend int + vstart, vend int +} + +type byKey struct { + sorted bool + json []byte + pairs []pair +} + +func (arr *byKey) Len() int { + return len(arr.pairs) +} +func (arr *byKey) Less(i, j int) bool { + key1 := arr.json[arr.pairs[i].kstart+1 : arr.pairs[i].kend-1] + key2 := arr.json[arr.pairs[j].kstart+1 : arr.pairs[j].kend-1] + return string(key1) < string(key2) +} +func (arr *byKey) Swap(i, j int) { + arr.pairs[i], arr.pairs[j] = arr.pairs[j], arr.pairs[i] + arr.sorted = true +} + +func appendPrettyObject(buf, json []byte, i int, open, close byte, pretty bool, width int, prefix, indent string, sortkeys bool, tabs, nl, max int) ([]byte, int, int, bool) { + var ok bool + if width > 0 { + if pretty && open == '[' && max == -1 { + // here we try to create a single line array + max := width - (len(buf) - nl) + if max > 3 { + s1, s2 := len(buf), i + buf, i, _, ok = appendPrettyObject(buf, json, i, '[', ']', false, width, prefix, "", sortkeys, 0, 0, max) + if ok && len(buf)-s1 <= max { + return buf, i, nl, true + } + buf = buf[:s1] + i = s2 + } + } else if max != -1 && open == '{' { + return buf, i, nl, false + } + } + buf = append(buf, open) + i++ + var pairs []pair + if open == '{' && sortkeys { + pairs = make([]pair, 0, 8) + } + var n int + for ; i < len(json); i++ { + if json[i] <= ' ' { + continue + } + if json[i] == close { + if pretty { + if open == '{' && sortkeys { + buf = sortPairs(json, buf, pairs) + } + if n > 0 { + nl = len(buf) + buf = append(buf, '\n') + } + if buf[len(buf)-1] != open { + buf = appendTabs(buf, prefix, indent, tabs) + } + } + buf = append(buf, close) + return buf, i + 1, nl, open != '{' + } + if open == '[' || json[i] == '"' { + if n > 0 { + buf = append(buf, ',') + if width != -1 && open == '[' { + buf = append(buf, ' ') + } + } + var p pair + if pretty { + nl = len(buf) + buf = append(buf, '\n') + if open == '{' && sortkeys { + p.kstart = i + p.vstart = len(buf) + } + buf = appendTabs(buf, prefix, indent, tabs+1) + } + if open == '{' { + buf, i, nl, _ = appendPrettyString(buf, json, i, nl) + if sortkeys { + p.kend = i + } + buf = append(buf, ':') + if pretty { + buf = append(buf, ' ') + } + } + buf, i, nl, ok = appendPrettyAny(buf, json, i, pretty, width, prefix, indent, sortkeys, tabs+1, nl, max) + if max != -1 && !ok { + return buf, i, nl, false + } + if pretty && open == '{' && sortkeys { + p.vend = len(buf) + if p.kstart > p.kend || p.vstart > p.vend { + // bad data. disable sorting + sortkeys = false + } else { + pairs = append(pairs, p) + } + } + i-- + n++ + } + } + return buf, i, nl, open != '{' +} +func sortPairs(json, buf []byte, pairs []pair) []byte { + if len(pairs) == 0 { + return buf + } + vstart := pairs[0].vstart + vend := pairs[len(pairs)-1].vend + arr := byKey{false, json, pairs} + sort.Sort(&arr) + if !arr.sorted { + return buf + } + nbuf := make([]byte, 0, vend-vstart) + for i, p := range pairs { + nbuf = append(nbuf, buf[p.vstart:p.vend]...) + if i < len(pairs)-1 { + nbuf = append(nbuf, ',') + nbuf = append(nbuf, '\n') + } + } + return append(buf[:vstart], nbuf...) +} + +func appendPrettyString(buf, json []byte, i, nl int) ([]byte, int, int, bool) { + s := i + i++ + for ; i < len(json); i++ { + if json[i] == '"' { + var sc int + for j := i - 1; j > s; j-- { + if json[j] == '\\' { + sc++ + } else { + break + } + } + if sc%2 == 1 { + continue + } + i++ + break + } + } + return append(buf, json[s:i]...), i, nl, true +} + +func appendPrettyNumber(buf, json []byte, i, nl int) ([]byte, int, int, bool) { + s := i + i++ + for ; i < len(json); i++ { + if json[i] <= ' ' || json[i] == ',' || json[i] == ':' || json[i] == ']' || json[i] == '}' { + break + } + } + return append(buf, json[s:i]...), i, nl, true +} + +func appendTabs(buf []byte, prefix, indent string, tabs int) []byte { + if len(prefix) != 0 { + buf = append(buf, prefix...) + } + if len(indent) == 2 && indent[0] == ' ' && indent[1] == ' ' { + for i := 0; i < tabs; i++ { + buf = append(buf, ' ', ' ') + } + } else { + for i := 0; i < tabs; i++ { + buf = append(buf, indent...) + } + } + return buf +} + +// Style is the color style +type Style struct { + Key, String, Number [2]string + True, False, Null [2]string + Append func(dst []byte, c byte) []byte +} + +func hexp(p byte) byte { + switch { + case p < 10: + return p + '0' + default: + return (p - 10) + 'a' + } +} + +// TerminalStyle is for terminals +var TerminalStyle = &Style{ + Key: [2]string{"\x1B[94m", "\x1B[0m"}, + String: [2]string{"\x1B[92m", "\x1B[0m"}, + Number: [2]string{"\x1B[93m", "\x1B[0m"}, + True: [2]string{"\x1B[96m", "\x1B[0m"}, + False: [2]string{"\x1B[96m", "\x1B[0m"}, + Null: [2]string{"\x1B[91m", "\x1B[0m"}, + Append: func(dst []byte, c byte) []byte { + if c < ' ' && (c != '\r' && c != '\n' && c != '\t' && c != '\v') { + dst = append(dst, "\\u00"...) + dst = append(dst, hexp((c>>4)&0xF)) + return append(dst, hexp((c)&0xF)) + } + return append(dst, c) + }, +} + +// Color will colorize the json. The style parma is used for customizing +// the colors. Passing nil to the style param will use the default +// TerminalStyle. +func Color(src []byte, style *Style) []byte { + if style == nil { + style = TerminalStyle + } + apnd := style.Append + if apnd == nil { + apnd = func(dst []byte, c byte) []byte { + return append(dst, c) + } + } + type stackt struct { + kind byte + key bool + } + var dst []byte + var stack []stackt + for i := 0; i < len(src); i++ { + if src[i] == '"' { + key := len(stack) > 0 && stack[len(stack)-1].key + if key { + dst = append(dst, style.Key[0]...) + } else { + dst = append(dst, style.String[0]...) + } + dst = apnd(dst, '"') + for i = i + 1; i < len(src); i++ { + dst = apnd(dst, src[i]) + if src[i] == '"' { + j := i - 1 + for ; ; j-- { + if src[j] != '\\' { + break + } + } + if (j-i)%2 != 0 { + break + } + } + } + if key { + dst = append(dst, style.Key[1]...) + } else { + dst = append(dst, style.String[1]...) + } + } else if src[i] == '{' || src[i] == '[' { + stack = append(stack, stackt{src[i], src[i] == '{'}) + dst = apnd(dst, src[i]) + } else if (src[i] == '}' || src[i] == ']') && len(stack) > 0 { + stack = stack[:len(stack)-1] + dst = apnd(dst, src[i]) + } else if (src[i] == ':' || src[i] == ',') && len(stack) > 0 && stack[len(stack)-1].kind == '{' { + stack[len(stack)-1].key = !stack[len(stack)-1].key + dst = apnd(dst, src[i]) + } else { + var kind byte + if (src[i] >= '0' && src[i] <= '9') || src[i] == '-' { + kind = '0' + dst = append(dst, style.Number[0]...) + } else if src[i] == 't' { + kind = 't' + dst = append(dst, style.True[0]...) + } else if src[i] == 'f' { + kind = 'f' + dst = append(dst, style.False[0]...) + } else if src[i] == 'n' { + kind = 'n' + dst = append(dst, style.Null[0]...) + } else { + dst = apnd(dst, src[i]) + } + if kind != 0 { + for ; i < len(src); i++ { + if src[i] <= ' ' || src[i] == ',' || src[i] == ':' || src[i] == ']' || src[i] == '}' { + i-- + break + } + dst = apnd(dst, src[i]) + } + if kind == '0' { + dst = append(dst, style.Number[1]...) + } else if kind == 't' { + dst = append(dst, style.True[1]...) + } else if kind == 'f' { + dst = append(dst, style.False[1]...) + } else if kind == 'n' { + dst = append(dst, style.Null[1]...) + } + } + } + } + return dst +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 46da506..192552a 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,3 +1,9 @@ +# github.com/cloud-ca/go-cloudca v1.4.0 +github.com/cloud-ca/go-cloudca +github.com/cloud-ca/go-cloudca/api +github.com/cloud-ca/go-cloudca/configuration +github.com/cloud-ca/go-cloudca/services +github.com/cloud-ca/go-cloudca/services/cloudca # github.com/fsnotify/fsnotify v1.4.7 github.com/fsnotify/fsnotify # github.com/hashicorp/hcl v1.0.0 @@ -38,6 +44,8 @@ github.com/spf13/jwalterweatherman github.com/spf13/pflag # github.com/spf13/viper v1.4.0 github.com/spf13/viper +# github.com/tidwall/pretty v1.0.0 +github.com/tidwall/pretty # golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 golang.org/x/crypto/ssh/terminal # golang.org/x/sys v0.0.0-20190422165155-953cdadca894