mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-02 19:47:54 +00:00
add PCF auth method, agent, and cli handler
This commit is contained in:
@@ -25,6 +25,7 @@ import (
|
|||||||
"github.com/hashicorp/vault/command/agent/auth/gcp"
|
"github.com/hashicorp/vault/command/agent/auth/gcp"
|
||||||
"github.com/hashicorp/vault/command/agent/auth/jwt"
|
"github.com/hashicorp/vault/command/agent/auth/jwt"
|
||||||
"github.com/hashicorp/vault/command/agent/auth/kubernetes"
|
"github.com/hashicorp/vault/command/agent/auth/kubernetes"
|
||||||
|
"github.com/hashicorp/vault/command/agent/auth/pcf"
|
||||||
"github.com/hashicorp/vault/command/agent/cache"
|
"github.com/hashicorp/vault/command/agent/cache"
|
||||||
"github.com/hashicorp/vault/command/agent/config"
|
"github.com/hashicorp/vault/command/agent/config"
|
||||||
"github.com/hashicorp/vault/command/agent/sink"
|
"github.com/hashicorp/vault/command/agent/sink"
|
||||||
@@ -342,6 +343,8 @@ func (c *AgentCommand) Run(args []string) int {
|
|||||||
method, err = kubernetes.NewKubernetesAuthMethod(authConfig)
|
method, err = kubernetes.NewKubernetesAuthMethod(authConfig)
|
||||||
case "approle":
|
case "approle":
|
||||||
method, err = approle.NewApproleAuthMethod(authConfig)
|
method, err = approle.NewApproleAuthMethod(authConfig)
|
||||||
|
case "pcf":
|
||||||
|
method, err = pcf.NewPCFAuthMethod(authConfig)
|
||||||
default:
|
default:
|
||||||
c.UI.Error(fmt.Sprintf("Unknown auth method %q", config.AutoAuth.Method.Type))
|
c.UI.Error(fmt.Sprintf("Unknown auth method %q", config.AutoAuth.Method.Type))
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
82
command/agent/auth/pcf/pcf.go
Normal file
82
command/agent/auth/pcf/pcf.go
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package pcf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
pcf "github.com/hashicorp/vault-plugin-auth-pcf"
|
||||||
|
"github.com/hashicorp/vault-plugin-auth-pcf/signatures"
|
||||||
|
"github.com/hashicorp/vault/api"
|
||||||
|
"github.com/hashicorp/vault/command/agent/auth"
|
||||||
|
)
|
||||||
|
|
||||||
|
type pcfMethod struct {
|
||||||
|
mountPath string
|
||||||
|
roleName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPCFAuthMethod(conf *auth.AuthConfig) (auth.AuthMethod, error) {
|
||||||
|
if conf == nil {
|
||||||
|
return nil, errors.New("empty config")
|
||||||
|
}
|
||||||
|
if conf.Config == nil {
|
||||||
|
return nil, errors.New("empty config data")
|
||||||
|
}
|
||||||
|
a := &pcfMethod{
|
||||||
|
mountPath: conf.MountPath,
|
||||||
|
}
|
||||||
|
if raw, ok := conf.Config["role"]; ok {
|
||||||
|
if roleName, ok := raw.(string); ok {
|
||||||
|
a.roleName = roleName
|
||||||
|
} else {
|
||||||
|
return nil, errors.New("could not convert 'role' config value to string")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, errors.New("missing 'role' value")
|
||||||
|
}
|
||||||
|
return a, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pcfMethod) Authenticate(ctx context.Context, client *api.Client) (string, map[string]interface{}, error) {
|
||||||
|
pathToClientCert := os.Getenv(pcf.EnvVarInstanceCertificate)
|
||||||
|
if pathToClientCert == "" {
|
||||||
|
return "", nil, fmt.Errorf("missing %q value", pcf.EnvVarInstanceCertificate)
|
||||||
|
}
|
||||||
|
certBytes, err := ioutil.ReadFile(pathToClientCert)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
pathToClientKey := os.Getenv(pcf.EnvVarInstanceKey)
|
||||||
|
if pathToClientKey == "" {
|
||||||
|
return "", nil, fmt.Errorf("missing %q value", pcf.EnvVarInstanceKey)
|
||||||
|
}
|
||||||
|
signingTime := time.Now().UTC()
|
||||||
|
signatureData := &signatures.SignatureData{
|
||||||
|
SigningTime: signingTime,
|
||||||
|
Role: p.roleName,
|
||||||
|
Certificate: string(certBytes),
|
||||||
|
}
|
||||||
|
signature, err := signatures.Sign(pathToClientKey, signatureData)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
data := map[string]interface{}{
|
||||||
|
"role": p.roleName,
|
||||||
|
"certificate": string(certBytes),
|
||||||
|
"signing_time": signingTime.Format(signatures.TimeFormat),
|
||||||
|
"signature": signature,
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s/login", p.mountPath), data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pcfMethod) NewCreds() chan struct{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pcfMethod) CredSuccess() {}
|
||||||
|
|
||||||
|
func (p *pcfMethod) Shutdown() {}
|
||||||
170
command/agent/pcf_end_to_end_test.go
Normal file
170
command/agent/pcf_end_to_end_test.go
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
package agent
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
hclog "github.com/hashicorp/go-hclog"
|
||||||
|
log "github.com/hashicorp/go-hclog"
|
||||||
|
credPCF "github.com/hashicorp/vault-plugin-auth-pcf"
|
||||||
|
"github.com/hashicorp/vault-plugin-auth-pcf/testing/certificates"
|
||||||
|
pcfAPI "github.com/hashicorp/vault-plugin-auth-pcf/testing/pcf"
|
||||||
|
"github.com/hashicorp/vault/api"
|
||||||
|
"github.com/hashicorp/vault/command/agent/auth"
|
||||||
|
agentpcf "github.com/hashicorp/vault/command/agent/auth/pcf"
|
||||||
|
"github.com/hashicorp/vault/command/agent/sink"
|
||||||
|
"github.com/hashicorp/vault/command/agent/sink/file"
|
||||||
|
vaulthttp "github.com/hashicorp/vault/http"
|
||||||
|
"github.com/hashicorp/vault/sdk/helper/logging"
|
||||||
|
"github.com/hashicorp/vault/sdk/logical"
|
||||||
|
"github.com/hashicorp/vault/vault"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPCFEndToEnd(t *testing.T) {
|
||||||
|
logger := logging.NewVaultLogger(hclog.Trace)
|
||||||
|
|
||||||
|
coreConfig := &vault.CoreConfig{
|
||||||
|
DisableMlock: true,
|
||||||
|
DisableCache: true,
|
||||||
|
Logger: log.NewNullLogger(),
|
||||||
|
CredentialBackends: map[string]logical.Factory{
|
||||||
|
"pcf": credPCF.Factory,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
cluster := vault.NewTestCluster(t, coreConfig, &vault.TestClusterOptions{
|
||||||
|
HandlerFunc: vaulthttp.Handler,
|
||||||
|
})
|
||||||
|
|
||||||
|
cluster.Start()
|
||||||
|
defer cluster.Cleanup()
|
||||||
|
|
||||||
|
cores := cluster.Cores
|
||||||
|
vault.TestWaitActive(t, cores[0].Core)
|
||||||
|
client := cores[0].Client
|
||||||
|
if err := client.Sys().EnableAuthWithOptions("pcf", &api.EnableAuthOptions{
|
||||||
|
Type: "pcf",
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
testIPAddress := "127.0.0.1"
|
||||||
|
|
||||||
|
// Generate some valid certs that look like the ones we get from PCF.
|
||||||
|
testPCFCerts, err := certificates.Generate(pcfAPI.FoundServiceGUID, pcfAPI.FoundOrgGUID, pcfAPI.FoundSpaceGUID, pcfAPI.FoundAppGUID, testIPAddress)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := testPCFCerts.Close(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Start a mock server representing their API.
|
||||||
|
mockPCFAPI := pcfAPI.MockServer(false)
|
||||||
|
defer mockPCFAPI.Close()
|
||||||
|
|
||||||
|
// Configure a CA certificate like a Vault operator would in setting up PCF.
|
||||||
|
if _, err := client.Logical().Write("auth/pcf/config", map[string]interface{}{
|
||||||
|
"certificates": testPCFCerts.CACertificate,
|
||||||
|
"pcf_api_addr": mockPCFAPI.URL,
|
||||||
|
"pcf_username": pcfAPI.AuthUsername,
|
||||||
|
"pcf_password": pcfAPI.AuthPassword,
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure a role to be used for logging in, another thing a Vault operator would do.
|
||||||
|
if _, err := client.Logical().Write("auth/pcf/roles/test-role", map[string]interface{}{
|
||||||
|
"bound_instance_ids": pcfAPI.FoundServiceGUID,
|
||||||
|
"bound_organization_ids": pcfAPI.FoundOrgGUID,
|
||||||
|
"bound_space_ids": pcfAPI.FoundSpaceGUID,
|
||||||
|
"bound_application_ids": pcfAPI.FoundAppGUID,
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Setenv(credPCF.EnvVarInstanceCertificate, testPCFCerts.PathToInstanceCertificate)
|
||||||
|
os.Setenv(credPCF.EnvVarInstanceKey, testPCFCerts.PathToInstanceKey)
|
||||||
|
|
||||||
|
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||||
|
timer := time.AfterFunc(30*time.Second, func() {
|
||||||
|
cancelFunc()
|
||||||
|
})
|
||||||
|
defer timer.Stop()
|
||||||
|
|
||||||
|
am, err := agentpcf.NewPCFAuthMethod(&auth.AuthConfig{
|
||||||
|
MountPath: "auth/pcf",
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"role": "test-role",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ahConfig := &auth.AuthHandlerConfig{
|
||||||
|
Logger: logger.Named("auth.handler"),
|
||||||
|
Client: client,
|
||||||
|
}
|
||||||
|
|
||||||
|
ah := auth.NewAuthHandler(ahConfig)
|
||||||
|
go ah.Run(ctx, am)
|
||||||
|
defer func() {
|
||||||
|
<-ah.DoneCh
|
||||||
|
}()
|
||||||
|
|
||||||
|
tmpFile, err := ioutil.TempFile("", "auth.tokensink.test.")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
tokenSinkFileName := tmpFile.Name()
|
||||||
|
tmpFile.Close()
|
||||||
|
os.Remove(tokenSinkFileName)
|
||||||
|
t.Logf("output: %s", tokenSinkFileName)
|
||||||
|
|
||||||
|
config := &sink.SinkConfig{
|
||||||
|
Logger: logger.Named("sink.file"),
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"path": tokenSinkFileName,
|
||||||
|
},
|
||||||
|
WrapTTL: 10 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
fs, err := file.NewFileSink(config)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
config.Sink = fs
|
||||||
|
|
||||||
|
ss := sink.NewSinkServer(&sink.SinkServerConfig{
|
||||||
|
Logger: logger.Named("sink.server"),
|
||||||
|
Client: client,
|
||||||
|
})
|
||||||
|
go ss.Run(ctx, ah.OutputCh, []*sink.SinkConfig{config})
|
||||||
|
defer func() {
|
||||||
|
<-ss.DoneCh
|
||||||
|
}()
|
||||||
|
|
||||||
|
if stat, err := os.Lstat(tokenSinkFileName); err == nil {
|
||||||
|
t.Fatalf("expected err but got %s", stat)
|
||||||
|
} else if !os.IsNotExist(err) {
|
||||||
|
t.Fatal("expected notexist err")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait 2 seconds for the env variables to be detected and an auth to be generated.
|
||||||
|
time.Sleep(time.Second * 2)
|
||||||
|
|
||||||
|
token, err := readToken(tokenSinkFileName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if token.Token == "" {
|
||||||
|
t.Fatal("expected token but didn't receive it")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,6 +27,7 @@ import (
|
|||||||
credCentrify "github.com/hashicorp/vault-plugin-auth-centrify"
|
credCentrify "github.com/hashicorp/vault-plugin-auth-centrify"
|
||||||
credGcp "github.com/hashicorp/vault-plugin-auth-gcp/plugin"
|
credGcp "github.com/hashicorp/vault-plugin-auth-gcp/plugin"
|
||||||
credOIDC "github.com/hashicorp/vault-plugin-auth-jwt"
|
credOIDC "github.com/hashicorp/vault-plugin-auth-jwt"
|
||||||
|
credPCF "github.com/hashicorp/vault-plugin-auth-pcf"
|
||||||
credAws "github.com/hashicorp/vault/builtin/credential/aws"
|
credAws "github.com/hashicorp/vault/builtin/credential/aws"
|
||||||
credCert "github.com/hashicorp/vault/builtin/credential/cert"
|
credCert "github.com/hashicorp/vault/builtin/credential/cert"
|
||||||
credGitHub "github.com/hashicorp/vault/builtin/credential/github"
|
credGitHub "github.com/hashicorp/vault/builtin/credential/github"
|
||||||
@@ -162,6 +163,7 @@ func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) {
|
|||||||
"ldap": &credLdap.CLIHandler{},
|
"ldap": &credLdap.CLIHandler{},
|
||||||
"oidc": &credOIDC.CLIHandler{},
|
"oidc": &credOIDC.CLIHandler{},
|
||||||
"okta": &credOkta.CLIHandler{},
|
"okta": &credOkta.CLIHandler{},
|
||||||
|
"pcf": &credPCF.CLIHandler{},
|
||||||
"radius": &credUserpass.CLIHandler{
|
"radius": &credUserpass.CLIHandler{
|
||||||
DefaultMount: "radius",
|
DefaultMount: "radius",
|
||||||
},
|
},
|
||||||
|
|||||||
5
go.mod
5
go.mod
@@ -58,7 +58,7 @@ require (
|
|||||||
github.com/hashicorp/errwrap v1.0.0
|
github.com/hashicorp/errwrap v1.0.0
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.1
|
github.com/hashicorp/go-cleanhttp v0.5.1
|
||||||
github.com/hashicorp/go-gcp-common v0.5.0
|
github.com/hashicorp/go-gcp-common v0.5.0
|
||||||
github.com/hashicorp/go-hclog v0.8.0
|
github.com/hashicorp/go-hclog v0.9.2
|
||||||
github.com/hashicorp/go-memdb v1.0.0
|
github.com/hashicorp/go-memdb v1.0.0
|
||||||
github.com/hashicorp/go-multierror v1.0.0
|
github.com/hashicorp/go-multierror v1.0.0
|
||||||
github.com/hashicorp/go-rootcerts v1.0.0
|
github.com/hashicorp/go-rootcerts v1.0.0
|
||||||
@@ -74,13 +74,14 @@ require (
|
|||||||
github.com/hashicorp/vault-plugin-auth-gcp v0.5.1
|
github.com/hashicorp/vault-plugin-auth-gcp v0.5.1
|
||||||
github.com/hashicorp/vault-plugin-auth-jwt v0.5.1
|
github.com/hashicorp/vault-plugin-auth-jwt v0.5.1
|
||||||
github.com/hashicorp/vault-plugin-auth-kubernetes v0.5.1
|
github.com/hashicorp/vault-plugin-auth-kubernetes v0.5.1
|
||||||
|
github.com/hashicorp/vault-plugin-auth-pcf v0.0.0-20190605234735-619218abcd26
|
||||||
github.com/hashicorp/vault-plugin-secrets-ad v0.5.1
|
github.com/hashicorp/vault-plugin-secrets-ad v0.5.1
|
||||||
github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.1
|
github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.1
|
||||||
github.com/hashicorp/vault-plugin-secrets-azure v0.5.1
|
github.com/hashicorp/vault-plugin-secrets-azure v0.5.1
|
||||||
github.com/hashicorp/vault-plugin-secrets-gcp v0.5.2
|
github.com/hashicorp/vault-plugin-secrets-gcp v0.5.2
|
||||||
github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.1
|
github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.1
|
||||||
github.com/hashicorp/vault-plugin-secrets-kv v0.5.2-0.20190416155133-fd495225dea0
|
github.com/hashicorp/vault-plugin-secrets-kv v0.5.2-0.20190416155133-fd495225dea0
|
||||||
github.com/hashicorp/vault/api v1.0.1
|
github.com/hashicorp/vault/api v1.0.2
|
||||||
github.com/hashicorp/vault/sdk v0.1.11
|
github.com/hashicorp/vault/sdk v0.1.11
|
||||||
github.com/influxdata/influxdb v0.0.0-20190411212539-d24b7ba8c4c4
|
github.com/influxdata/influxdb v0.0.0-20190411212539-d24b7ba8c4c4
|
||||||
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect
|
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect
|
||||||
|
|||||||
21
go.sum
21
go.sum
@@ -2,6 +2,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
|
|||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU=
|
cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU=
|
||||||
cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
|
cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
|
||||||
|
code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f h1:UrKzEwTgeiff9vxdrfdqxibzpWjxLnuXDI5m6z3GJAk=
|
||||||
|
code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f/go.mod h1:sk5LnIjB/nIEU7yP5sDQExVm62wu0pBh3yrElngUisI=
|
||||||
contrib.go.opencensus.io/exporter/ocagent v0.4.12 h1:jGFvw3l57ViIVEPKKEUXPcLYIXJmQxLUh6ey1eJhwyc=
|
contrib.go.opencensus.io/exporter/ocagent v0.4.12 h1:jGFvw3l57ViIVEPKKEUXPcLYIXJmQxLUh6ey1eJhwyc=
|
||||||
contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA=
|
contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA=
|
||||||
git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
||||||
@@ -16,6 +18,8 @@ github.com/DataDog/datadog-go v2.2.0+incompatible h1:V5BKkxACZLjzHjSgBbr2gvLA2Ae
|
|||||||
github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||||
github.com/Jeffail/gabs v1.1.1 h1:V0uzR08Hj22EX8+8QMhyI9sX2hwRu+/RJhJUmnwda/E=
|
github.com/Jeffail/gabs v1.1.1 h1:V0uzR08Hj22EX8+8QMhyI9sX2hwRu+/RJhJUmnwda/E=
|
||||||
github.com/Jeffail/gabs v1.1.1/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc=
|
github.com/Jeffail/gabs v1.1.1/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc=
|
||||||
|
github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc=
|
||||||
|
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||||
github.com/Microsoft/go-winio v0.4.12 h1:xAfWHN1IrQ0NJ9TBC0KBZoqLjzDTr1ML+4MywiUOryc=
|
github.com/Microsoft/go-winio v0.4.12 h1:xAfWHN1IrQ0NJ9TBC0KBZoqLjzDTr1ML+4MywiUOryc=
|
||||||
github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
||||||
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
|
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
|
||||||
@@ -76,10 +80,13 @@ github.com/circonus-labs/circonus-gometrics v2.2.7+incompatible/go.mod h1:nmEj6D
|
|||||||
github.com/circonus-labs/circonusllhist v0.1.3 h1:TJH+oke8D16535+jHExHj4nQvzlZrj7ug5D7I/orNUA=
|
github.com/circonus-labs/circonusllhist v0.1.3 h1:TJH+oke8D16535+jHExHj4nQvzlZrj7ug5D7I/orNUA=
|
||||||
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381 h1:rdRS5BT13Iae9ssvcslol66gfOOXjaLYwqerEn/cl9s=
|
||||||
|
github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381/go.mod h1:e5+USP2j8Le2M0Jo3qKPFnNhuo1wueU4nWHCXBOfQ14=
|
||||||
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
|
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
|
||||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||||
github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c h1:2zRrJWIt/f9c9HhNHAgrRgq0San5gRRUJTBXLkchal0=
|
github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c h1:2zRrJWIt/f9c9HhNHAgrRgq0San5gRRUJTBXLkchal0=
|
||||||
github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
|
github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
|
||||||
|
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
|
||||||
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808 h1:4BX8f882bXEDKfWIf0wa8HRvpnBoPszJJXL+TVbBw4M=
|
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808 h1:4BX8f882bXEDKfWIf0wa8HRvpnBoPszJJXL+TVbBw4M=
|
||||||
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||||
github.com/coreos/go-oidc v2.0.0+incompatible h1:+RStIopZ8wooMx+Vs5Bt8zMXxV1ABl5LbakNExNmZIg=
|
github.com/coreos/go-oidc v2.0.0+incompatible h1:+RStIopZ8wooMx+Vs5Bt8zMXxV1ABl5LbakNExNmZIg=
|
||||||
@@ -139,6 +146,7 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
|
|||||||
github.com/go-ldap/ldap v3.0.2+incompatible h1:kD5HQcAzlQ7yrhfn+h+MSABeAy/jAJhvIJ/QDllP44g=
|
github.com/go-ldap/ldap v3.0.2+incompatible h1:kD5HQcAzlQ7yrhfn+h+MSABeAy/jAJhvIJ/QDllP44g=
|
||||||
github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
|
github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
|
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
|
||||||
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
|
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
|
||||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
@@ -190,6 +198,7 @@ github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
|
|||||||
github.com/googleapis/gax-go/v2 v2.0.4 h1:hU4mGcQI4DaAYW+IbTun+2qEZVFxK0ySjQLTbS0VQKc=
|
github.com/googleapis/gax-go/v2 v2.0.4 h1:hU4mGcQI4DaAYW+IbTun+2qEZVFxK0ySjQLTbS0VQKc=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75 h1:f0n1xnMSmBLzVfsMMvriDyA75NB/oBgILX2GcHXIQzY=
|
github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75 h1:f0n1xnMSmBLzVfsMMvriDyA75NB/oBgILX2GcHXIQzY=
|
||||||
@@ -225,6 +234,8 @@ github.com/hashicorp/go-gcp-common v0.5.0/go.mod h1:IDGUI2N/OS3PiU4qZcXJeWKPI6O/
|
|||||||
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
|
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
|
||||||
github.com/hashicorp/go-hclog v0.8.0 h1:z3ollgGRg8RjfJH6UVBaG54R70GFd++QOkvnJH3VSBY=
|
github.com/hashicorp/go-hclog v0.8.0 h1:z3ollgGRg8RjfJH6UVBaG54R70GFd++QOkvnJH3VSBY=
|
||||||
github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||||
|
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
|
||||||
|
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||||
github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0=
|
github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0=
|
||||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||||
github.com/hashicorp/go-memdb v1.0.0 h1:K1O4N2VPndZiTrdH3lmmf5bemr9Xw81KjVwhReIUjTQ=
|
github.com/hashicorp/go-memdb v1.0.0 h1:K1O4N2VPndZiTrdH3lmmf5bemr9Xw81KjVwhReIUjTQ=
|
||||||
@@ -275,6 +286,10 @@ github.com/hashicorp/vault-plugin-auth-jwt v0.5.1 h1:d9WLI7oF6VMtwBZwS5bbChc4kW+
|
|||||||
github.com/hashicorp/vault-plugin-auth-jwt v0.5.1/go.mod h1:5VU7gc6/BEEFQW/viqMs3LBxI1D1cxJmKqKQEP3JUP4=
|
github.com/hashicorp/vault-plugin-auth-jwt v0.5.1/go.mod h1:5VU7gc6/BEEFQW/viqMs3LBxI1D1cxJmKqKQEP3JUP4=
|
||||||
github.com/hashicorp/vault-plugin-auth-kubernetes v0.5.1 h1:q6DGb12Vw/CpZ9xDWAmpzxVRKeClFqRFgbIZ3fZcvuY=
|
github.com/hashicorp/vault-plugin-auth-kubernetes v0.5.1 h1:q6DGb12Vw/CpZ9xDWAmpzxVRKeClFqRFgbIZ3fZcvuY=
|
||||||
github.com/hashicorp/vault-plugin-auth-kubernetes v0.5.1/go.mod h1:qCDsm0njdfUrnN5sFKMLjxGjZKjQf2qB6dReQ4gr4YI=
|
github.com/hashicorp/vault-plugin-auth-kubernetes v0.5.1/go.mod h1:qCDsm0njdfUrnN5sFKMLjxGjZKjQf2qB6dReQ4gr4YI=
|
||||||
|
github.com/hashicorp/vault-plugin-auth-pcf v0.0.0-20190524170107-2d769dfedad4 h1:dSp8yiXmbfqKfS0j7//fTA+uw3G4OPt7COKDf7oYmMQ=
|
||||||
|
github.com/hashicorp/vault-plugin-auth-pcf v0.0.0-20190524170107-2d769dfedad4/go.mod h1:9866PkjxPBXclbEJBKzVGY60pgVIY9b7qZJ5Fa+p6VY=
|
||||||
|
github.com/hashicorp/vault-plugin-auth-pcf v0.0.0-20190605234735-619218abcd26 h1:mz5YaAFveImGMooFLAW14kdSBH4jVdRnKTQYAz0fEHw=
|
||||||
|
github.com/hashicorp/vault-plugin-auth-pcf v0.0.0-20190605234735-619218abcd26/go.mod h1:9866PkjxPBXclbEJBKzVGY60pgVIY9b7qZJ5Fa+p6VY=
|
||||||
github.com/hashicorp/vault-plugin-secrets-ad v0.5.1 h1:BdiASUZLOvOUs317EnaUNjGxTSw0PYGQA7zJZhDKLC4=
|
github.com/hashicorp/vault-plugin-secrets-ad v0.5.1 h1:BdiASUZLOvOUs317EnaUNjGxTSw0PYGQA7zJZhDKLC4=
|
||||||
github.com/hashicorp/vault-plugin-secrets-ad v0.5.1/go.mod h1:EH9CI8+0aWRBz8eIgGth0QjttmHWlGvn+8ZmX/ZUetE=
|
github.com/hashicorp/vault-plugin-secrets-ad v0.5.1/go.mod h1:EH9CI8+0aWRBz8eIgGth0QjttmHWlGvn+8ZmX/ZUetE=
|
||||||
github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.1 h1:72K91p4uLhT/jgtBq2zV5Wn8ocvny4sAN56XOcTxK1w=
|
github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.1 h1:72K91p4uLhT/jgtBq2zV5Wn8ocvny4sAN56XOcTxK1w=
|
||||||
@@ -316,6 +331,7 @@ github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBv
|
|||||||
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
|
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
|
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
@@ -337,6 +353,7 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
|||||||
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||||
github.com/marstr/guid v1.1.0 h1:/M4H/1G4avsieL6BbUwCOBzulmoeKVP5ux/3mQNnbyI=
|
github.com/marstr/guid v1.1.0 h1:/M4H/1G4avsieL6BbUwCOBzulmoeKVP5ux/3mQNnbyI=
|
||||||
github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
|
github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
|
||||||
|
github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11/go.mod h1:Ah2dBMoxZEqk118as2T4u4fjfXarE0pPnMJaArZQZsI=
|
||||||
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
|
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
@@ -399,6 +416,7 @@ github.com/openzipkin/zipkin-go v0.1.3/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTm
|
|||||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||||
github.com/ory/dockertest v3.3.4+incompatible h1:VrpM6Gqg7CrPm3bL4Wm1skO+zFWLbh7/Xb5kGEbJRh8=
|
github.com/ory/dockertest v3.3.4+incompatible h1:VrpM6Gqg7CrPm3bL4Wm1skO+zFWLbh7/Xb5kGEbJRh8=
|
||||||
github.com/ory/dockertest v3.3.4+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs=
|
github.com/ory/dockertest v3.3.4+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs=
|
||||||
|
github.com/oxtoacart/bpool v0.0.0-20150712133111-4e1c5567d7c2/go.mod h1:L3UMQOThbttwfYRNFOWLLVXMhk5Lkio4GGOtw5UrxS0=
|
||||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs=
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs=
|
||||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
|
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
|
||||||
@@ -458,8 +476,10 @@ github.com/sirupsen/logrus v1.0.5 h1:8c8b5uO0zS4X6RPl/sd1ENwSkIc0/H2PaHxE3udaE8I
|
|||||||
github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
||||||
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
|
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180725160413-e900ae048470/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
|
github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
|
||||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs=
|
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs=
|
||||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
|
github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
|
||||||
@@ -534,6 +554,7 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2eP
|
|||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190130055435-99b60b757ec1/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190319182350-c85d3e98c914/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190319182350-c85d3e98c914/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA=
|
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA=
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
credGcp "github.com/hashicorp/vault-plugin-auth-gcp/plugin"
|
credGcp "github.com/hashicorp/vault-plugin-auth-gcp/plugin"
|
||||||
credJWT "github.com/hashicorp/vault-plugin-auth-jwt"
|
credJWT "github.com/hashicorp/vault-plugin-auth-jwt"
|
||||||
credKube "github.com/hashicorp/vault-plugin-auth-kubernetes"
|
credKube "github.com/hashicorp/vault-plugin-auth-kubernetes"
|
||||||
|
credPCF "github.com/hashicorp/vault-plugin-auth-pcf"
|
||||||
credAppId "github.com/hashicorp/vault/builtin/credential/app-id"
|
credAppId "github.com/hashicorp/vault/builtin/credential/app-id"
|
||||||
credAppRole "github.com/hashicorp/vault/builtin/credential/approle"
|
credAppRole "github.com/hashicorp/vault/builtin/credential/approle"
|
||||||
credAws "github.com/hashicorp/vault/builtin/credential/aws"
|
credAws "github.com/hashicorp/vault/builtin/credential/aws"
|
||||||
@@ -75,6 +76,7 @@ func newRegistry() *registry {
|
|||||||
"ldap": credLdap.Factory,
|
"ldap": credLdap.Factory,
|
||||||
"oidc": credJWT.Factory,
|
"oidc": credJWT.Factory,
|
||||||
"okta": credOkta.Factory,
|
"okta": credOkta.Factory,
|
||||||
|
"pcf": credPCF.Factory,
|
||||||
"radius": credRadius.Factory,
|
"radius": credRadius.Factory,
|
||||||
"userpass": credUserpass.Factory,
|
"userpass": credUserpass.Factory,
|
||||||
},
|
},
|
||||||
|
|||||||
202
vendor/code.cloudfoundry.org/gofileutils/LICENSE
generated
vendored
Normal file
202
vendor/code.cloudfoundry.org/gofileutils/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
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.
|
||||||
11
vendor/code.cloudfoundry.org/gofileutils/NOTICE
generated
vendored
Normal file
11
vendor/code.cloudfoundry.org/gofileutils/NOTICE
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
Copyright (c) 2015-Present CloudFoundry.org Foundation, Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
This project contains software that is Copyright (c) 2014-2015 Pivotal Software, Inc.
|
||||||
|
|
||||||
|
This project is licensed to you under the Apache License, Version 2.0 (the "License").
|
||||||
|
|
||||||
|
You may not use this project except in compliance with the License.
|
||||||
|
|
||||||
|
This project may include a number of subcomponents with separate copyright notices
|
||||||
|
and license terms. Your use of these subcomponents is subject to the terms and
|
||||||
|
conditions of the subcomponent's license, as noted in the LICENSE file.
|
||||||
20
vendor/code.cloudfoundry.org/gofileutils/fileutils/dir_utils.go
generated
vendored
Normal file
20
vendor/code.cloudfoundry.org/gofileutils/fileutils/dir_utils.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package fileutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func IsDirEmpty(dir string) (isEmpty bool, err error) {
|
||||||
|
dirFile, err := os.Open(dir)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, readErr := dirFile.Readdirnames(1)
|
||||||
|
if readErr != nil {
|
||||||
|
isEmpty = true
|
||||||
|
} else {
|
||||||
|
isEmpty = false
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
74
vendor/code.cloudfoundry.org/gofileutils/fileutils/file_utils.go
generated
vendored
Normal file
74
vendor/code.cloudfoundry.org/gofileutils/fileutils/file_utils.go
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
package fileutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Open(path string) (file *os.File, err error) {
|
||||||
|
err = os.MkdirAll(filepath.Dir(path), os.ModeDir|os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Create(path string) (file *os.File, err error) {
|
||||||
|
err = os.MkdirAll(filepath.Dir(path), os.ModeDir|os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return os.Create(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CopyPathToPath(fromPath, toPath string) (err error) {
|
||||||
|
srcFileInfo, err := os.Stat(fromPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if srcFileInfo.IsDir() {
|
||||||
|
err = os.MkdirAll(toPath, srcFileInfo.Mode())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
files, err := ioutil.ReadDir(fromPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, file := range files {
|
||||||
|
err = CopyPathToPath(path.Join(fromPath, file.Name()), path.Join(toPath, file.Name()))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var dst *os.File
|
||||||
|
dst, err = Create(toPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer dst.Close()
|
||||||
|
|
||||||
|
dst.Chmod(srcFileInfo.Mode())
|
||||||
|
|
||||||
|
src, err := os.Open(fromPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer src.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(dst, src)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
27
vendor/code.cloudfoundry.org/gofileutils/fileutils/temp_utils.go
generated
vendored
Normal file
27
vendor/code.cloudfoundry.org/gofileutils/fileutils/temp_utils.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package fileutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TempDir(namePrefix string, cb func(tmpDir string, err error)) {
|
||||||
|
tmpDir, err := ioutil.TempDir("", namePrefix)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
os.RemoveAll(tmpDir)
|
||||||
|
}()
|
||||||
|
|
||||||
|
cb(tmpDir, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TempFile(namePrefix string, cb func(tmpFile *os.File, err error)) {
|
||||||
|
tmpFile, err := ioutil.TempFile("", namePrefix)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
tmpFile.Close()
|
||||||
|
os.Remove(tmpFile.Name())
|
||||||
|
}()
|
||||||
|
|
||||||
|
cb(tmpFile, err)
|
||||||
|
}
|
||||||
27
vendor/github.com/Masterminds/semver/.travis.yml
generated
vendored
Normal file
27
vendor/github.com/Masterminds/semver/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
language: go
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.6.x
|
||||||
|
- 1.7.x
|
||||||
|
- 1.8.x
|
||||||
|
- 1.9.x
|
||||||
|
- 1.10.x
|
||||||
|
- tip
|
||||||
|
|
||||||
|
# Setting sudo access to false will let Travis CI use containers rather than
|
||||||
|
# VMs to run the tests. For more details see:
|
||||||
|
# - http://docs.travis-ci.com/user/workers/container-based-infrastructure/
|
||||||
|
# - http://docs.travis-ci.com/user/workers/standard-infrastructure/
|
||||||
|
sudo: false
|
||||||
|
|
||||||
|
script:
|
||||||
|
- make setup
|
||||||
|
- make test
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
webhooks:
|
||||||
|
urls:
|
||||||
|
- https://webhooks.gitter.im/e/06e3328629952dabe3e0
|
||||||
|
on_success: change # options: [always|never|change] default: always
|
||||||
|
on_failure: always # options: [always|never|change] default: always
|
||||||
|
on_start: never # options: [always|never|change] default: always
|
||||||
86
vendor/github.com/Masterminds/semver/CHANGELOG.md
generated
vendored
Normal file
86
vendor/github.com/Masterminds/semver/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
# 1.4.2 (2018-04-10)
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
- #72: Updated the docs to point to vert for a console appliaction
|
||||||
|
- #71: Update the docs on pre-release comparator handling
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
- #70: Fix the handling of pre-releases and the 0.0.0 release edge case
|
||||||
|
|
||||||
|
# 1.4.1 (2018-04-02)
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
- Fixed #64: Fix pre-release precedence issue (thanks @uudashr)
|
||||||
|
|
||||||
|
# 1.4.0 (2017-10-04)
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
- #61: Update NewVersion to parse ints with a 64bit int size (thanks @zknill)
|
||||||
|
|
||||||
|
# 1.3.1 (2017-07-10)
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
- Fixed #57: number comparisons in prerelease sometimes inaccurate
|
||||||
|
|
||||||
|
# 1.3.0 (2017-05-02)
|
||||||
|
|
||||||
|
## Added
|
||||||
|
- #45: Added json (un)marshaling support (thanks @mh-cbon)
|
||||||
|
- Stability marker. See https://masterminds.github.io/stability/
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
- #51: Fix handling of single digit tilde constraint (thanks @dgodd)
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
- #55: The godoc icon moved from png to svg
|
||||||
|
|
||||||
|
# 1.2.3 (2017-04-03)
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
- #46: Fixed 0.x.x and 0.0.x in constraints being treated as *
|
||||||
|
|
||||||
|
# Release 1.2.2 (2016-12-13)
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
- #34: Fixed issue where hyphen range was not working with pre-release parsing.
|
||||||
|
|
||||||
|
# Release 1.2.1 (2016-11-28)
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
- #24: Fixed edge case issue where constraint "> 0" does not handle "0.0.1-alpha"
|
||||||
|
properly.
|
||||||
|
|
||||||
|
# Release 1.2.0 (2016-11-04)
|
||||||
|
|
||||||
|
## Added
|
||||||
|
- #20: Added MustParse function for versions (thanks @adamreese)
|
||||||
|
- #15: Added increment methods on versions (thanks @mh-cbon)
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
- Issue #21: Per the SemVer spec (section 9) a pre-release is unstable and
|
||||||
|
might not satisfy the intended compatibility. The change here ignores pre-releases
|
||||||
|
on constraint checks (e.g., ~ or ^) when a pre-release is not part of the
|
||||||
|
constraint. For example, `^1.2.3` will ignore pre-releases while
|
||||||
|
`^1.2.3-alpha` will include them.
|
||||||
|
|
||||||
|
# Release 1.1.1 (2016-06-30)
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
- Issue #9: Speed up version comparison performance (thanks @sdboyer)
|
||||||
|
- Issue #8: Added benchmarks (thanks @sdboyer)
|
||||||
|
- Updated Go Report Card URL to new location
|
||||||
|
- Updated Readme to add code snippet formatting (thanks @mh-cbon)
|
||||||
|
- Updating tagging to v[SemVer] structure for compatibility with other tools.
|
||||||
|
|
||||||
|
# Release 1.1.0 (2016-03-11)
|
||||||
|
|
||||||
|
- Issue #2: Implemented validation to provide reasons a versions failed a
|
||||||
|
constraint.
|
||||||
|
|
||||||
|
# Release 1.0.1 (2015-12-31)
|
||||||
|
|
||||||
|
- Fixed #1: * constraint failing on valid versions.
|
||||||
|
|
||||||
|
# Release 1.0.0 (2015-10-20)
|
||||||
|
|
||||||
|
- Initial release
|
||||||
20
vendor/github.com/Masterminds/semver/LICENSE.txt
generated
vendored
Normal file
20
vendor/github.com/Masterminds/semver/LICENSE.txt
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
The Masterminds
|
||||||
|
Copyright (C) 2014-2015, Matt Butcher and Matt Farina
|
||||||
|
|
||||||
|
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.
|
||||||
36
vendor/github.com/Masterminds/semver/Makefile
generated
vendored
Normal file
36
vendor/github.com/Masterminds/semver/Makefile
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
.PHONY: setup
|
||||||
|
setup:
|
||||||
|
go get -u gopkg.in/alecthomas/gometalinter.v1
|
||||||
|
gometalinter.v1 --install
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test: validate lint
|
||||||
|
@echo "==> Running tests"
|
||||||
|
go test -v
|
||||||
|
|
||||||
|
.PHONY: validate
|
||||||
|
validate:
|
||||||
|
@echo "==> Running static validations"
|
||||||
|
@gometalinter.v1 \
|
||||||
|
--disable-all \
|
||||||
|
--enable deadcode \
|
||||||
|
--severity deadcode:error \
|
||||||
|
--enable gofmt \
|
||||||
|
--enable gosimple \
|
||||||
|
--enable ineffassign \
|
||||||
|
--enable misspell \
|
||||||
|
--enable vet \
|
||||||
|
--tests \
|
||||||
|
--vendor \
|
||||||
|
--deadline 60s \
|
||||||
|
./... || exit_code=1
|
||||||
|
|
||||||
|
.PHONY: lint
|
||||||
|
lint:
|
||||||
|
@echo "==> Running linters"
|
||||||
|
@gometalinter.v1 \
|
||||||
|
--disable-all \
|
||||||
|
--enable golint \
|
||||||
|
--vendor \
|
||||||
|
--deadline 60s \
|
||||||
|
./... || :
|
||||||
165
vendor/github.com/Masterminds/semver/README.md
generated
vendored
Normal file
165
vendor/github.com/Masterminds/semver/README.md
generated
vendored
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
# SemVer
|
||||||
|
|
||||||
|
The `semver` package provides the ability to work with [Semantic Versions](http://semver.org) in Go. Specifically it provides the ability to:
|
||||||
|
|
||||||
|
* Parse semantic versions
|
||||||
|
* Sort semantic versions
|
||||||
|
* Check if a semantic version fits within a set of constraints
|
||||||
|
* Optionally work with a `v` prefix
|
||||||
|
|
||||||
|
[](https://masterminds.github.io/stability/active.html)
|
||||||
|
[](https://travis-ci.org/Masterminds/semver) [](https://ci.appveyor.com/project/mattfarina/semver/branch/master) [](https://godoc.org/github.com/Masterminds/semver) [](https://goreportcard.com/report/github.com/Masterminds/semver)
|
||||||
|
|
||||||
|
## Parsing Semantic Versions
|
||||||
|
|
||||||
|
To parse a semantic version use the `NewVersion` function. For example,
|
||||||
|
|
||||||
|
```go
|
||||||
|
v, err := semver.NewVersion("1.2.3-beta.1+build345")
|
||||||
|
```
|
||||||
|
|
||||||
|
If there is an error the version wasn't parseable. The version object has methods
|
||||||
|
to get the parts of the version, compare it to other versions, convert the
|
||||||
|
version back into a string, and get the original string. For more details
|
||||||
|
please see the [documentation](https://godoc.org/github.com/Masterminds/semver).
|
||||||
|
|
||||||
|
## Sorting Semantic Versions
|
||||||
|
|
||||||
|
A set of versions can be sorted using the [`sort`](https://golang.org/pkg/sort/)
|
||||||
|
package from the standard library. For example,
|
||||||
|
|
||||||
|
```go
|
||||||
|
raw := []string{"1.2.3", "1.0", "1.3", "2", "0.4.2",}
|
||||||
|
vs := make([]*semver.Version, len(raw))
|
||||||
|
for i, r := range raw {
|
||||||
|
v, err := semver.NewVersion(r)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error parsing version: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
vs[i] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(semver.Collection(vs))
|
||||||
|
```
|
||||||
|
|
||||||
|
## Checking Version Constraints
|
||||||
|
|
||||||
|
Checking a version against version constraints is one of the most featureful
|
||||||
|
parts of the package.
|
||||||
|
|
||||||
|
```go
|
||||||
|
c, err := semver.NewConstraint(">= 1.2.3")
|
||||||
|
if err != nil {
|
||||||
|
// Handle constraint not being parseable.
|
||||||
|
}
|
||||||
|
|
||||||
|
v, _ := semver.NewVersion("1.3")
|
||||||
|
if err != nil {
|
||||||
|
// Handle version not being parseable.
|
||||||
|
}
|
||||||
|
// Check if the version meets the constraints. The a variable will be true.
|
||||||
|
a := c.Check(v)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Basic Comparisons
|
||||||
|
|
||||||
|
There are two elements to the comparisons. First, a comparison string is a list
|
||||||
|
of comma separated and comparisons. These are then separated by || separated or
|
||||||
|
comparisons. For example, `">= 1.2, < 3.0.0 || >= 4.2.3"` is looking for a
|
||||||
|
comparison that's greater than or equal to 1.2 and less than 3.0.0 or is
|
||||||
|
greater than or equal to 4.2.3.
|
||||||
|
|
||||||
|
The basic comparisons are:
|
||||||
|
|
||||||
|
* `=`: equal (aliased to no operator)
|
||||||
|
* `!=`: not equal
|
||||||
|
* `>`: greater than
|
||||||
|
* `<`: less than
|
||||||
|
* `>=`: greater than or equal to
|
||||||
|
* `<=`: less than or equal to
|
||||||
|
|
||||||
|
_Note, according to the Semantic Version specification pre-releases may not be
|
||||||
|
API compliant with their release counterpart. It says,_
|
||||||
|
|
||||||
|
> _A pre-release version indicates that the version is unstable and might not satisfy the intended compatibility requirements as denoted by its associated normal version._
|
||||||
|
|
||||||
|
_SemVer comparisons without a pre-release value will skip pre-release versions.
|
||||||
|
For example, `>1.2.3` will skip pre-releases when looking at a list of values
|
||||||
|
while `>1.2.3-alpha.1` will evaluate pre-releases._
|
||||||
|
|
||||||
|
## Hyphen Range Comparisons
|
||||||
|
|
||||||
|
There are multiple methods to handle ranges and the first is hyphens ranges.
|
||||||
|
These look like:
|
||||||
|
|
||||||
|
* `1.2 - 1.4.5` which is equivalent to `>= 1.2, <= 1.4.5`
|
||||||
|
* `2.3.4 - 4.5` which is equivalent to `>= 2.3.4, <= 4.5`
|
||||||
|
|
||||||
|
## Wildcards In Comparisons
|
||||||
|
|
||||||
|
The `x`, `X`, and `*` characters can be used as a wildcard character. This works
|
||||||
|
for all comparison operators. When used on the `=` operator it falls
|
||||||
|
back to the pack level comparison (see tilde below). For example,
|
||||||
|
|
||||||
|
* `1.2.x` is equivalent to `>= 1.2.0, < 1.3.0`
|
||||||
|
* `>= 1.2.x` is equivalent to `>= 1.2.0`
|
||||||
|
* `<= 2.x` is equivalent to `<= 3`
|
||||||
|
* `*` is equivalent to `>= 0.0.0`
|
||||||
|
|
||||||
|
## Tilde Range Comparisons (Patch)
|
||||||
|
|
||||||
|
The tilde (`~`) comparison operator is for patch level ranges when a minor
|
||||||
|
version is specified and major level changes when the minor number is missing.
|
||||||
|
For example,
|
||||||
|
|
||||||
|
* `~1.2.3` is equivalent to `>= 1.2.3, < 1.3.0`
|
||||||
|
* `~1` is equivalent to `>= 1, < 2`
|
||||||
|
* `~2.3` is equivalent to `>= 2.3, < 2.4`
|
||||||
|
* `~1.2.x` is equivalent to `>= 1.2.0, < 1.3.0`
|
||||||
|
* `~1.x` is equivalent to `>= 1, < 2`
|
||||||
|
|
||||||
|
## Caret Range Comparisons (Major)
|
||||||
|
|
||||||
|
The caret (`^`) comparison operator is for major level changes. This is useful
|
||||||
|
when comparisons of API versions as a major change is API breaking. For example,
|
||||||
|
|
||||||
|
* `^1.2.3` is equivalent to `>= 1.2.3, < 2.0.0`
|
||||||
|
* `^1.2.x` is equivalent to `>= 1.2.0, < 2.0.0`
|
||||||
|
* `^2.3` is equivalent to `>= 2.3, < 3`
|
||||||
|
* `^2.x` is equivalent to `>= 2.0.0, < 3`
|
||||||
|
|
||||||
|
# Validation
|
||||||
|
|
||||||
|
In addition to testing a version against a constraint, a version can be validated
|
||||||
|
against a constraint. When validation fails a slice of errors containing why a
|
||||||
|
version didn't meet the constraint is returned. For example,
|
||||||
|
|
||||||
|
```go
|
||||||
|
c, err := semver.NewConstraint("<= 1.2.3, >= 1.4")
|
||||||
|
if err != nil {
|
||||||
|
// Handle constraint not being parseable.
|
||||||
|
}
|
||||||
|
|
||||||
|
v, _ := semver.NewVersion("1.3")
|
||||||
|
if err != nil {
|
||||||
|
// Handle version not being parseable.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate a version against a constraint.
|
||||||
|
a, msgs := c.Validate(v)
|
||||||
|
// a is false
|
||||||
|
for _, m := range msgs {
|
||||||
|
fmt.Println(m)
|
||||||
|
|
||||||
|
// Loops over the errors which would read
|
||||||
|
// "1.3 is greater than 1.2.3"
|
||||||
|
// "1.3 is less than 1.4"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Contribute
|
||||||
|
|
||||||
|
If you find an issue or want to contribute please file an [issue](https://github.com/Masterminds/semver/issues)
|
||||||
|
or [create a pull request](https://github.com/Masterminds/semver/pulls).
|
||||||
44
vendor/github.com/Masterminds/semver/appveyor.yml
generated
vendored
Normal file
44
vendor/github.com/Masterminds/semver/appveyor.yml
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
version: build-{build}.{branch}
|
||||||
|
|
||||||
|
clone_folder: C:\gopath\src\github.com\Masterminds\semver
|
||||||
|
shallow_clone: true
|
||||||
|
|
||||||
|
environment:
|
||||||
|
GOPATH: C:\gopath
|
||||||
|
|
||||||
|
platform:
|
||||||
|
- x64
|
||||||
|
|
||||||
|
install:
|
||||||
|
- go version
|
||||||
|
- go env
|
||||||
|
- go get -u gopkg.in/alecthomas/gometalinter.v1
|
||||||
|
- set PATH=%PATH%;%GOPATH%\bin
|
||||||
|
- gometalinter.v1.exe --install
|
||||||
|
|
||||||
|
build_script:
|
||||||
|
- go install -v ./...
|
||||||
|
|
||||||
|
test_script:
|
||||||
|
- "gometalinter.v1 \
|
||||||
|
--disable-all \
|
||||||
|
--enable deadcode \
|
||||||
|
--severity deadcode:error \
|
||||||
|
--enable gofmt \
|
||||||
|
--enable gosimple \
|
||||||
|
--enable ineffassign \
|
||||||
|
--enable misspell \
|
||||||
|
--enable vet \
|
||||||
|
--tests \
|
||||||
|
--vendor \
|
||||||
|
--deadline 60s \
|
||||||
|
./... || exit_code=1"
|
||||||
|
- "gometalinter.v1 \
|
||||||
|
--disable-all \
|
||||||
|
--enable golint \
|
||||||
|
--vendor \
|
||||||
|
--deadline 60s \
|
||||||
|
./... || :"
|
||||||
|
- go test -v
|
||||||
|
|
||||||
|
deploy: off
|
||||||
24
vendor/github.com/Masterminds/semver/collection.go
generated
vendored
Normal file
24
vendor/github.com/Masterminds/semver/collection.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package semver
|
||||||
|
|
||||||
|
// Collection is a collection of Version instances and implements the sort
|
||||||
|
// interface. See the sort package for more details.
|
||||||
|
// https://golang.org/pkg/sort/
|
||||||
|
type Collection []*Version
|
||||||
|
|
||||||
|
// Len returns the length of a collection. The number of Version instances
|
||||||
|
// on the slice.
|
||||||
|
func (c Collection) Len() int {
|
||||||
|
return len(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Less is needed for the sort interface to compare two Version objects on the
|
||||||
|
// slice. If checks if one is less than the other.
|
||||||
|
func (c Collection) Less(i, j int) bool {
|
||||||
|
return c[i].LessThan(c[j])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap is needed for the sort interface to replace the Version objects
|
||||||
|
// at two different positions in the slice.
|
||||||
|
func (c Collection) Swap(i, j int) {
|
||||||
|
c[i], c[j] = c[j], c[i]
|
||||||
|
}
|
||||||
426
vendor/github.com/Masterminds/semver/constraints.go
generated
vendored
Normal file
426
vendor/github.com/Masterminds/semver/constraints.go
generated
vendored
Normal file
@@ -0,0 +1,426 @@
|
|||||||
|
package semver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Constraints is one or more constraint that a semantic version can be
|
||||||
|
// checked against.
|
||||||
|
type Constraints struct {
|
||||||
|
constraints [][]*constraint
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewConstraint returns a Constraints instance that a Version instance can
|
||||||
|
// be checked against. If there is a parse error it will be returned.
|
||||||
|
func NewConstraint(c string) (*Constraints, error) {
|
||||||
|
|
||||||
|
// Rewrite - ranges into a comparison operation.
|
||||||
|
c = rewriteRange(c)
|
||||||
|
|
||||||
|
ors := strings.Split(c, "||")
|
||||||
|
or := make([][]*constraint, len(ors))
|
||||||
|
for k, v := range ors {
|
||||||
|
cs := strings.Split(v, ",")
|
||||||
|
result := make([]*constraint, len(cs))
|
||||||
|
for i, s := range cs {
|
||||||
|
pc, err := parseConstraint(s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result[i] = pc
|
||||||
|
}
|
||||||
|
or[k] = result
|
||||||
|
}
|
||||||
|
|
||||||
|
o := &Constraints{constraints: or}
|
||||||
|
return o, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check tests if a version satisfies the constraints.
|
||||||
|
func (cs Constraints) Check(v *Version) bool {
|
||||||
|
// loop over the ORs and check the inner ANDs
|
||||||
|
for _, o := range cs.constraints {
|
||||||
|
joy := true
|
||||||
|
for _, c := range o {
|
||||||
|
if !c.check(v) {
|
||||||
|
joy = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if joy {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate checks if a version satisfies a constraint. If not a slice of
|
||||||
|
// reasons for the failure are returned in addition to a bool.
|
||||||
|
func (cs Constraints) Validate(v *Version) (bool, []error) {
|
||||||
|
// loop over the ORs and check the inner ANDs
|
||||||
|
var e []error
|
||||||
|
for _, o := range cs.constraints {
|
||||||
|
joy := true
|
||||||
|
for _, c := range o {
|
||||||
|
if !c.check(v) {
|
||||||
|
em := fmt.Errorf(c.msg, v, c.orig)
|
||||||
|
e = append(e, em)
|
||||||
|
joy = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if joy {
|
||||||
|
return true, []error{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, e
|
||||||
|
}
|
||||||
|
|
||||||
|
var constraintOps map[string]cfunc
|
||||||
|
var constraintMsg map[string]string
|
||||||
|
var constraintRegex *regexp.Regexp
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
constraintOps = map[string]cfunc{
|
||||||
|
"": constraintTildeOrEqual,
|
||||||
|
"=": constraintTildeOrEqual,
|
||||||
|
"!=": constraintNotEqual,
|
||||||
|
">": constraintGreaterThan,
|
||||||
|
"<": constraintLessThan,
|
||||||
|
">=": constraintGreaterThanEqual,
|
||||||
|
"=>": constraintGreaterThanEqual,
|
||||||
|
"<=": constraintLessThanEqual,
|
||||||
|
"=<": constraintLessThanEqual,
|
||||||
|
"~": constraintTilde,
|
||||||
|
"~>": constraintTilde,
|
||||||
|
"^": constraintCaret,
|
||||||
|
}
|
||||||
|
|
||||||
|
constraintMsg = map[string]string{
|
||||||
|
"": "%s is not equal to %s",
|
||||||
|
"=": "%s is not equal to %s",
|
||||||
|
"!=": "%s is equal to %s",
|
||||||
|
">": "%s is less than or equal to %s",
|
||||||
|
"<": "%s is greater than or equal to %s",
|
||||||
|
">=": "%s is less than %s",
|
||||||
|
"=>": "%s is less than %s",
|
||||||
|
"<=": "%s is greater than %s",
|
||||||
|
"=<": "%s is greater than %s",
|
||||||
|
"~": "%s does not have same major and minor version as %s",
|
||||||
|
"~>": "%s does not have same major and minor version as %s",
|
||||||
|
"^": "%s does not have same major version as %s",
|
||||||
|
}
|
||||||
|
|
||||||
|
ops := make([]string, 0, len(constraintOps))
|
||||||
|
for k := range constraintOps {
|
||||||
|
ops = append(ops, regexp.QuoteMeta(k))
|
||||||
|
}
|
||||||
|
|
||||||
|
constraintRegex = regexp.MustCompile(fmt.Sprintf(
|
||||||
|
`^\s*(%s)\s*(%s)\s*$`,
|
||||||
|
strings.Join(ops, "|"),
|
||||||
|
cvRegex))
|
||||||
|
|
||||||
|
constraintRangeRegex = regexp.MustCompile(fmt.Sprintf(
|
||||||
|
`\s*(%s)\s+-\s+(%s)\s*`,
|
||||||
|
cvRegex, cvRegex))
|
||||||
|
}
|
||||||
|
|
||||||
|
// An individual constraint
|
||||||
|
type constraint struct {
|
||||||
|
// The callback function for the restraint. It performs the logic for
|
||||||
|
// the constraint.
|
||||||
|
function cfunc
|
||||||
|
|
||||||
|
msg string
|
||||||
|
|
||||||
|
// The version used in the constraint check. For example, if a constraint
|
||||||
|
// is '<= 2.0.0' the con a version instance representing 2.0.0.
|
||||||
|
con *Version
|
||||||
|
|
||||||
|
// The original parsed version (e.g., 4.x from != 4.x)
|
||||||
|
orig string
|
||||||
|
|
||||||
|
// When an x is used as part of the version (e.g., 1.x)
|
||||||
|
minorDirty bool
|
||||||
|
dirty bool
|
||||||
|
patchDirty bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if a version meets the constraint
|
||||||
|
func (c *constraint) check(v *Version) bool {
|
||||||
|
return c.function(v, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
type cfunc func(v *Version, c *constraint) bool
|
||||||
|
|
||||||
|
func parseConstraint(c string) (*constraint, error) {
|
||||||
|
m := constraintRegex.FindStringSubmatch(c)
|
||||||
|
if m == nil {
|
||||||
|
return nil, fmt.Errorf("improper constraint: %s", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
ver := m[2]
|
||||||
|
orig := ver
|
||||||
|
minorDirty := false
|
||||||
|
patchDirty := false
|
||||||
|
dirty := false
|
||||||
|
if isX(m[3]) {
|
||||||
|
ver = "0.0.0"
|
||||||
|
dirty = true
|
||||||
|
} else if isX(strings.TrimPrefix(m[4], ".")) || m[4] == "" {
|
||||||
|
minorDirty = true
|
||||||
|
dirty = true
|
||||||
|
ver = fmt.Sprintf("%s.0.0%s", m[3], m[6])
|
||||||
|
} else if isX(strings.TrimPrefix(m[5], ".")) {
|
||||||
|
dirty = true
|
||||||
|
patchDirty = true
|
||||||
|
ver = fmt.Sprintf("%s%s.0%s", m[3], m[4], m[6])
|
||||||
|
}
|
||||||
|
|
||||||
|
con, err := NewVersion(ver)
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
// The constraintRegex should catch any regex parsing errors. So,
|
||||||
|
// we should never get here.
|
||||||
|
return nil, errors.New("constraint Parser Error")
|
||||||
|
}
|
||||||
|
|
||||||
|
cs := &constraint{
|
||||||
|
function: constraintOps[m[1]],
|
||||||
|
msg: constraintMsg[m[1]],
|
||||||
|
con: con,
|
||||||
|
orig: orig,
|
||||||
|
minorDirty: minorDirty,
|
||||||
|
patchDirty: patchDirty,
|
||||||
|
dirty: dirty,
|
||||||
|
}
|
||||||
|
return cs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constraint functions
|
||||||
|
func constraintNotEqual(v *Version, c *constraint) bool {
|
||||||
|
if c.dirty {
|
||||||
|
|
||||||
|
// If there is a pre-release on the version but the constraint isn't looking
|
||||||
|
// for them assume that pre-releases are not compatible. See issue 21 for
|
||||||
|
// more details.
|
||||||
|
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.con.Major() != v.Major() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if c.con.Minor() != v.Minor() && !c.minorDirty {
|
||||||
|
return true
|
||||||
|
} else if c.minorDirty {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return !v.Equal(c.con)
|
||||||
|
}
|
||||||
|
|
||||||
|
func constraintGreaterThan(v *Version, c *constraint) bool {
|
||||||
|
|
||||||
|
// An edge case the constraint is 0.0.0 and the version is 0.0.0-someprerelease
|
||||||
|
// exists. This that case.
|
||||||
|
if !isNonZero(c.con) && isNonZero(v) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is a pre-release on the version but the constraint isn't looking
|
||||||
|
// for them assume that pre-releases are not compatible. See issue 21 for
|
||||||
|
// more details.
|
||||||
|
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return v.Compare(c.con) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func constraintLessThan(v *Version, c *constraint) bool {
|
||||||
|
// If there is a pre-release on the version but the constraint isn't looking
|
||||||
|
// for them assume that pre-releases are not compatible. See issue 21 for
|
||||||
|
// more details.
|
||||||
|
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.dirty {
|
||||||
|
return v.Compare(c.con) < 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Major() > c.con.Major() {
|
||||||
|
return false
|
||||||
|
} else if v.Minor() > c.con.Minor() && !c.minorDirty {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func constraintGreaterThanEqual(v *Version, c *constraint) bool {
|
||||||
|
// An edge case the constraint is 0.0.0 and the version is 0.0.0-someprerelease
|
||||||
|
// exists. This that case.
|
||||||
|
if !isNonZero(c.con) && isNonZero(v) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is a pre-release on the version but the constraint isn't looking
|
||||||
|
// for them assume that pre-releases are not compatible. See issue 21 for
|
||||||
|
// more details.
|
||||||
|
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return v.Compare(c.con) >= 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func constraintLessThanEqual(v *Version, c *constraint) bool {
|
||||||
|
// If there is a pre-release on the version but the constraint isn't looking
|
||||||
|
// for them assume that pre-releases are not compatible. See issue 21 for
|
||||||
|
// more details.
|
||||||
|
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.dirty {
|
||||||
|
return v.Compare(c.con) <= 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Major() > c.con.Major() {
|
||||||
|
return false
|
||||||
|
} else if v.Minor() > c.con.Minor() && !c.minorDirty {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ~*, ~>* --> >= 0.0.0 (any)
|
||||||
|
// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0, <3.0.0
|
||||||
|
// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0, <2.1.0
|
||||||
|
// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0, <1.3.0
|
||||||
|
// ~1.2.3, ~>1.2.3 --> >=1.2.3, <1.3.0
|
||||||
|
// ~1.2.0, ~>1.2.0 --> >=1.2.0, <1.3.0
|
||||||
|
func constraintTilde(v *Version, c *constraint) bool {
|
||||||
|
// If there is a pre-release on the version but the constraint isn't looking
|
||||||
|
// for them assume that pre-releases are not compatible. See issue 21 for
|
||||||
|
// more details.
|
||||||
|
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.LessThan(c.con) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// ~0.0.0 is a special case where all constraints are accepted. It's
|
||||||
|
// equivalent to >= 0.0.0.
|
||||||
|
if c.con.Major() == 0 && c.con.Minor() == 0 && c.con.Patch() == 0 &&
|
||||||
|
!c.minorDirty && !c.patchDirty {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Major() != c.con.Major() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Minor() != c.con.Minor() && !c.minorDirty {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// When there is a .x (dirty) status it automatically opts in to ~. Otherwise
|
||||||
|
// it's a straight =
|
||||||
|
func constraintTildeOrEqual(v *Version, c *constraint) bool {
|
||||||
|
// If there is a pre-release on the version but the constraint isn't looking
|
||||||
|
// for them assume that pre-releases are not compatible. See issue 21 for
|
||||||
|
// more details.
|
||||||
|
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.dirty {
|
||||||
|
c.msg = constraintMsg["~"]
|
||||||
|
return constraintTilde(v, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
return v.Equal(c.con)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ^* --> (any)
|
||||||
|
// ^2, ^2.x, ^2.x.x --> >=2.0.0, <3.0.0
|
||||||
|
// ^2.0, ^2.0.x --> >=2.0.0, <3.0.0
|
||||||
|
// ^1.2, ^1.2.x --> >=1.2.0, <2.0.0
|
||||||
|
// ^1.2.3 --> >=1.2.3, <2.0.0
|
||||||
|
// ^1.2.0 --> >=1.2.0, <2.0.0
|
||||||
|
func constraintCaret(v *Version, c *constraint) bool {
|
||||||
|
// If there is a pre-release on the version but the constraint isn't looking
|
||||||
|
// for them assume that pre-releases are not compatible. See issue 21 for
|
||||||
|
// more details.
|
||||||
|
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.LessThan(c.con) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Major() != c.con.Major() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
var constraintRangeRegex *regexp.Regexp
|
||||||
|
|
||||||
|
const cvRegex string = `v?([0-9|x|X|\*]+)(\.[0-9|x|X|\*]+)?(\.[0-9|x|X|\*]+)?` +
|
||||||
|
`(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` +
|
||||||
|
`(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?`
|
||||||
|
|
||||||
|
func isX(x string) bool {
|
||||||
|
switch x {
|
||||||
|
case "x", "*", "X":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func rewriteRange(i string) string {
|
||||||
|
m := constraintRangeRegex.FindAllStringSubmatch(i, -1)
|
||||||
|
if m == nil {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
o := i
|
||||||
|
for _, v := range m {
|
||||||
|
t := fmt.Sprintf(">= %s, <= %s", v[1], v[11])
|
||||||
|
o = strings.Replace(o, v[0], t, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect if a version is not zero (0.0.0)
|
||||||
|
func isNonZero(v *Version) bool {
|
||||||
|
if v.Major() != 0 || v.Minor() != 0 || v.Patch() != 0 || v.Prerelease() != "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
115
vendor/github.com/Masterminds/semver/doc.go
generated
vendored
Normal file
115
vendor/github.com/Masterminds/semver/doc.go
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
Package semver provides the ability to work with Semantic Versions (http://semver.org) in Go.
|
||||||
|
|
||||||
|
Specifically it provides the ability to:
|
||||||
|
|
||||||
|
* Parse semantic versions
|
||||||
|
* Sort semantic versions
|
||||||
|
* Check if a semantic version fits within a set of constraints
|
||||||
|
* Optionally work with a `v` prefix
|
||||||
|
|
||||||
|
Parsing Semantic Versions
|
||||||
|
|
||||||
|
To parse a semantic version use the `NewVersion` function. For example,
|
||||||
|
|
||||||
|
v, err := semver.NewVersion("1.2.3-beta.1+build345")
|
||||||
|
|
||||||
|
If there is an error the version wasn't parseable. The version object has methods
|
||||||
|
to get the parts of the version, compare it to other versions, convert the
|
||||||
|
version back into a string, and get the original string. For more details
|
||||||
|
please see the documentation at https://godoc.org/github.com/Masterminds/semver.
|
||||||
|
|
||||||
|
Sorting Semantic Versions
|
||||||
|
|
||||||
|
A set of versions can be sorted using the `sort` package from the standard library.
|
||||||
|
For example,
|
||||||
|
|
||||||
|
raw := []string{"1.2.3", "1.0", "1.3", "2", "0.4.2",}
|
||||||
|
vs := make([]*semver.Version, len(raw))
|
||||||
|
for i, r := range raw {
|
||||||
|
v, err := semver.NewVersion(r)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error parsing version: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
vs[i] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(semver.Collection(vs))
|
||||||
|
|
||||||
|
Checking Version Constraints
|
||||||
|
|
||||||
|
Checking a version against version constraints is one of the most featureful
|
||||||
|
parts of the package.
|
||||||
|
|
||||||
|
c, err := semver.NewConstraint(">= 1.2.3")
|
||||||
|
if err != nil {
|
||||||
|
// Handle constraint not being parseable.
|
||||||
|
}
|
||||||
|
|
||||||
|
v, _ := semver.NewVersion("1.3")
|
||||||
|
if err != nil {
|
||||||
|
// Handle version not being parseable.
|
||||||
|
}
|
||||||
|
// Check if the version meets the constraints. The a variable will be true.
|
||||||
|
a := c.Check(v)
|
||||||
|
|
||||||
|
Basic Comparisons
|
||||||
|
|
||||||
|
There are two elements to the comparisons. First, a comparison string is a list
|
||||||
|
of comma separated and comparisons. These are then separated by || separated or
|
||||||
|
comparisons. For example, `">= 1.2, < 3.0.0 || >= 4.2.3"` is looking for a
|
||||||
|
comparison that's greater than or equal to 1.2 and less than 3.0.0 or is
|
||||||
|
greater than or equal to 4.2.3.
|
||||||
|
|
||||||
|
The basic comparisons are:
|
||||||
|
|
||||||
|
* `=`: equal (aliased to no operator)
|
||||||
|
* `!=`: not equal
|
||||||
|
* `>`: greater than
|
||||||
|
* `<`: less than
|
||||||
|
* `>=`: greater than or equal to
|
||||||
|
* `<=`: less than or equal to
|
||||||
|
|
||||||
|
Hyphen Range Comparisons
|
||||||
|
|
||||||
|
There are multiple methods to handle ranges and the first is hyphens ranges.
|
||||||
|
These look like:
|
||||||
|
|
||||||
|
* `1.2 - 1.4.5` which is equivalent to `>= 1.2, <= 1.4.5`
|
||||||
|
* `2.3.4 - 4.5` which is equivalent to `>= 2.3.4, <= 4.5`
|
||||||
|
|
||||||
|
Wildcards In Comparisons
|
||||||
|
|
||||||
|
The `x`, `X`, and `*` characters can be used as a wildcard character. This works
|
||||||
|
for all comparison operators. When used on the `=` operator it falls
|
||||||
|
back to the pack level comparison (see tilde below). For example,
|
||||||
|
|
||||||
|
* `1.2.x` is equivalent to `>= 1.2.0, < 1.3.0`
|
||||||
|
* `>= 1.2.x` is equivalent to `>= 1.2.0`
|
||||||
|
* `<= 2.x` is equivalent to `<= 3`
|
||||||
|
* `*` is equivalent to `>= 0.0.0`
|
||||||
|
|
||||||
|
Tilde Range Comparisons (Patch)
|
||||||
|
|
||||||
|
The tilde (`~`) comparison operator is for patch level ranges when a minor
|
||||||
|
version is specified and major level changes when the minor number is missing.
|
||||||
|
For example,
|
||||||
|
|
||||||
|
* `~1.2.3` is equivalent to `>= 1.2.3, < 1.3.0`
|
||||||
|
* `~1` is equivalent to `>= 1, < 2`
|
||||||
|
* `~2.3` is equivalent to `>= 2.3, < 2.4`
|
||||||
|
* `~1.2.x` is equivalent to `>= 1.2.0, < 1.3.0`
|
||||||
|
* `~1.x` is equivalent to `>= 1, < 2`
|
||||||
|
|
||||||
|
Caret Range Comparisons (Major)
|
||||||
|
|
||||||
|
The caret (`^`) comparison operator is for major level changes. This is useful
|
||||||
|
when comparisons of API versions as a major change is API breaking. For example,
|
||||||
|
|
||||||
|
* `^1.2.3` is equivalent to `>= 1.2.3, < 2.0.0`
|
||||||
|
* `^1.2.x` is equivalent to `>= 1.2.0, < 2.0.0`
|
||||||
|
* `^2.3` is equivalent to `>= 2.3, < 3`
|
||||||
|
* `^2.x` is equivalent to `>= 2.0.0, < 3`
|
||||||
|
*/
|
||||||
|
package semver
|
||||||
421
vendor/github.com/Masterminds/semver/version.go
generated
vendored
Normal file
421
vendor/github.com/Masterminds/semver/version.go
generated
vendored
Normal file
@@ -0,0 +1,421 @@
|
|||||||
|
package semver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The compiled version of the regex created at init() is cached here so it
|
||||||
|
// only needs to be created once.
|
||||||
|
var versionRegex *regexp.Regexp
|
||||||
|
var validPrereleaseRegex *regexp.Regexp
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrInvalidSemVer is returned a version is found to be invalid when
|
||||||
|
// being parsed.
|
||||||
|
ErrInvalidSemVer = errors.New("Invalid Semantic Version")
|
||||||
|
|
||||||
|
// ErrInvalidMetadata is returned when the metadata is an invalid format
|
||||||
|
ErrInvalidMetadata = errors.New("Invalid Metadata string")
|
||||||
|
|
||||||
|
// ErrInvalidPrerelease is returned when the pre-release is an invalid format
|
||||||
|
ErrInvalidPrerelease = errors.New("Invalid Prerelease string")
|
||||||
|
)
|
||||||
|
|
||||||
|
// SemVerRegex is the regular expression used to parse a semantic version.
|
||||||
|
const SemVerRegex string = `v?([0-9]+)(\.[0-9]+)?(\.[0-9]+)?` +
|
||||||
|
`(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` +
|
||||||
|
`(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?`
|
||||||
|
|
||||||
|
// ValidPrerelease is the regular expression which validates
|
||||||
|
// both prerelease and metadata values.
|
||||||
|
const ValidPrerelease string = `^([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*)`
|
||||||
|
|
||||||
|
// Version represents a single semantic version.
|
||||||
|
type Version struct {
|
||||||
|
major, minor, patch int64
|
||||||
|
pre string
|
||||||
|
metadata string
|
||||||
|
original string
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
versionRegex = regexp.MustCompile("^" + SemVerRegex + "$")
|
||||||
|
validPrereleaseRegex = regexp.MustCompile(ValidPrerelease)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewVersion parses a given version and returns an instance of Version or
|
||||||
|
// an error if unable to parse the version.
|
||||||
|
func NewVersion(v string) (*Version, error) {
|
||||||
|
m := versionRegex.FindStringSubmatch(v)
|
||||||
|
if m == nil {
|
||||||
|
return nil, ErrInvalidSemVer
|
||||||
|
}
|
||||||
|
|
||||||
|
sv := &Version{
|
||||||
|
metadata: m[8],
|
||||||
|
pre: m[5],
|
||||||
|
original: v,
|
||||||
|
}
|
||||||
|
|
||||||
|
var temp int64
|
||||||
|
temp, err := strconv.ParseInt(m[1], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error parsing version segment: %s", err)
|
||||||
|
}
|
||||||
|
sv.major = temp
|
||||||
|
|
||||||
|
if m[2] != "" {
|
||||||
|
temp, err = strconv.ParseInt(strings.TrimPrefix(m[2], "."), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error parsing version segment: %s", err)
|
||||||
|
}
|
||||||
|
sv.minor = temp
|
||||||
|
} else {
|
||||||
|
sv.minor = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if m[3] != "" {
|
||||||
|
temp, err = strconv.ParseInt(strings.TrimPrefix(m[3], "."), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error parsing version segment: %s", err)
|
||||||
|
}
|
||||||
|
sv.patch = temp
|
||||||
|
} else {
|
||||||
|
sv.patch = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return sv, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustParse parses a given version and panics on error.
|
||||||
|
func MustParse(v string) *Version {
|
||||||
|
sv, err := NewVersion(v)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return sv
|
||||||
|
}
|
||||||
|
|
||||||
|
// String converts a Version object to a string.
|
||||||
|
// Note, if the original version contained a leading v this version will not.
|
||||||
|
// See the Original() method to retrieve the original value. Semantic Versions
|
||||||
|
// don't contain a leading v per the spec. Instead it's optional on
|
||||||
|
// impelementation.
|
||||||
|
func (v *Version) String() string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
|
||||||
|
fmt.Fprintf(&buf, "%d.%d.%d", v.major, v.minor, v.patch)
|
||||||
|
if v.pre != "" {
|
||||||
|
fmt.Fprintf(&buf, "-%s", v.pre)
|
||||||
|
}
|
||||||
|
if v.metadata != "" {
|
||||||
|
fmt.Fprintf(&buf, "+%s", v.metadata)
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Original returns the original value passed in to be parsed.
|
||||||
|
func (v *Version) Original() string {
|
||||||
|
return v.original
|
||||||
|
}
|
||||||
|
|
||||||
|
// Major returns the major version.
|
||||||
|
func (v *Version) Major() int64 {
|
||||||
|
return v.major
|
||||||
|
}
|
||||||
|
|
||||||
|
// Minor returns the minor version.
|
||||||
|
func (v *Version) Minor() int64 {
|
||||||
|
return v.minor
|
||||||
|
}
|
||||||
|
|
||||||
|
// Patch returns the patch version.
|
||||||
|
func (v *Version) Patch() int64 {
|
||||||
|
return v.patch
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prerelease returns the pre-release version.
|
||||||
|
func (v *Version) Prerelease() string {
|
||||||
|
return v.pre
|
||||||
|
}
|
||||||
|
|
||||||
|
// Metadata returns the metadata on the version.
|
||||||
|
func (v *Version) Metadata() string {
|
||||||
|
return v.metadata
|
||||||
|
}
|
||||||
|
|
||||||
|
// originalVPrefix returns the original 'v' prefix if any.
|
||||||
|
func (v *Version) originalVPrefix() string {
|
||||||
|
|
||||||
|
// Note, only lowercase v is supported as a prefix by the parser.
|
||||||
|
if v.original != "" && v.original[:1] == "v" {
|
||||||
|
return v.original[:1]
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// IncPatch produces the next patch version.
|
||||||
|
// If the current version does not have prerelease/metadata information,
|
||||||
|
// it unsets metadata and prerelease values, increments patch number.
|
||||||
|
// If the current version has any of prerelease or metadata information,
|
||||||
|
// it unsets both values and keeps curent patch value
|
||||||
|
func (v Version) IncPatch() Version {
|
||||||
|
vNext := v
|
||||||
|
// according to http://semver.org/#spec-item-9
|
||||||
|
// Pre-release versions have a lower precedence than the associated normal version.
|
||||||
|
// according to http://semver.org/#spec-item-10
|
||||||
|
// Build metadata SHOULD be ignored when determining version precedence.
|
||||||
|
if v.pre != "" {
|
||||||
|
vNext.metadata = ""
|
||||||
|
vNext.pre = ""
|
||||||
|
} else {
|
||||||
|
vNext.metadata = ""
|
||||||
|
vNext.pre = ""
|
||||||
|
vNext.patch = v.patch + 1
|
||||||
|
}
|
||||||
|
vNext.original = v.originalVPrefix() + "" + vNext.String()
|
||||||
|
return vNext
|
||||||
|
}
|
||||||
|
|
||||||
|
// IncMinor produces the next minor version.
|
||||||
|
// Sets patch to 0.
|
||||||
|
// Increments minor number.
|
||||||
|
// Unsets metadata.
|
||||||
|
// Unsets prerelease status.
|
||||||
|
func (v Version) IncMinor() Version {
|
||||||
|
vNext := v
|
||||||
|
vNext.metadata = ""
|
||||||
|
vNext.pre = ""
|
||||||
|
vNext.patch = 0
|
||||||
|
vNext.minor = v.minor + 1
|
||||||
|
vNext.original = v.originalVPrefix() + "" + vNext.String()
|
||||||
|
return vNext
|
||||||
|
}
|
||||||
|
|
||||||
|
// IncMajor produces the next major version.
|
||||||
|
// Sets patch to 0.
|
||||||
|
// Sets minor to 0.
|
||||||
|
// Increments major number.
|
||||||
|
// Unsets metadata.
|
||||||
|
// Unsets prerelease status.
|
||||||
|
func (v Version) IncMajor() Version {
|
||||||
|
vNext := v
|
||||||
|
vNext.metadata = ""
|
||||||
|
vNext.pre = ""
|
||||||
|
vNext.patch = 0
|
||||||
|
vNext.minor = 0
|
||||||
|
vNext.major = v.major + 1
|
||||||
|
vNext.original = v.originalVPrefix() + "" + vNext.String()
|
||||||
|
return vNext
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPrerelease defines the prerelease value.
|
||||||
|
// Value must not include the required 'hypen' prefix.
|
||||||
|
func (v Version) SetPrerelease(prerelease string) (Version, error) {
|
||||||
|
vNext := v
|
||||||
|
if len(prerelease) > 0 && !validPrereleaseRegex.MatchString(prerelease) {
|
||||||
|
return vNext, ErrInvalidPrerelease
|
||||||
|
}
|
||||||
|
vNext.pre = prerelease
|
||||||
|
vNext.original = v.originalVPrefix() + "" + vNext.String()
|
||||||
|
return vNext, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMetadata defines metadata value.
|
||||||
|
// Value must not include the required 'plus' prefix.
|
||||||
|
func (v Version) SetMetadata(metadata string) (Version, error) {
|
||||||
|
vNext := v
|
||||||
|
if len(metadata) > 0 && !validPrereleaseRegex.MatchString(metadata) {
|
||||||
|
return vNext, ErrInvalidMetadata
|
||||||
|
}
|
||||||
|
vNext.metadata = metadata
|
||||||
|
vNext.original = v.originalVPrefix() + "" + vNext.String()
|
||||||
|
return vNext, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LessThan tests if one version is less than another one.
|
||||||
|
func (v *Version) LessThan(o *Version) bool {
|
||||||
|
return v.Compare(o) < 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// GreaterThan tests if one version is greater than another one.
|
||||||
|
func (v *Version) GreaterThan(o *Version) bool {
|
||||||
|
return v.Compare(o) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equal tests if two versions are equal to each other.
|
||||||
|
// Note, versions can be equal with different metadata since metadata
|
||||||
|
// is not considered part of the comparable version.
|
||||||
|
func (v *Version) Equal(o *Version) bool {
|
||||||
|
return v.Compare(o) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare compares this version to another one. It returns -1, 0, or 1 if
|
||||||
|
// the version smaller, equal, or larger than the other version.
|
||||||
|
//
|
||||||
|
// Versions are compared by X.Y.Z. Build metadata is ignored. Prerelease is
|
||||||
|
// lower than the version without a prerelease.
|
||||||
|
func (v *Version) Compare(o *Version) int {
|
||||||
|
// Compare the major, minor, and patch version for differences. If a
|
||||||
|
// difference is found return the comparison.
|
||||||
|
if d := compareSegment(v.Major(), o.Major()); d != 0 {
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
if d := compareSegment(v.Minor(), o.Minor()); d != 0 {
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
if d := compareSegment(v.Patch(), o.Patch()); d != 0 {
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point the major, minor, and patch versions are the same.
|
||||||
|
ps := v.pre
|
||||||
|
po := o.Prerelease()
|
||||||
|
|
||||||
|
if ps == "" && po == "" {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if ps == "" {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if po == "" {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
return comparePrerelease(ps, po)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements JSON.Unmarshaler interface.
|
||||||
|
func (v *Version) UnmarshalJSON(b []byte) error {
|
||||||
|
var s string
|
||||||
|
if err := json.Unmarshal(b, &s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
temp, err := NewVersion(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.major = temp.major
|
||||||
|
v.minor = temp.minor
|
||||||
|
v.patch = temp.patch
|
||||||
|
v.pre = temp.pre
|
||||||
|
v.metadata = temp.metadata
|
||||||
|
v.original = temp.original
|
||||||
|
temp = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements JSON.Marshaler interface.
|
||||||
|
func (v *Version) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(v.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareSegment(v, o int64) int {
|
||||||
|
if v < o {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if v > o {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func comparePrerelease(v, o string) int {
|
||||||
|
|
||||||
|
// split the prelease versions by their part. The separator, per the spec,
|
||||||
|
// is a .
|
||||||
|
sparts := strings.Split(v, ".")
|
||||||
|
oparts := strings.Split(o, ".")
|
||||||
|
|
||||||
|
// Find the longer length of the parts to know how many loop iterations to
|
||||||
|
// go through.
|
||||||
|
slen := len(sparts)
|
||||||
|
olen := len(oparts)
|
||||||
|
|
||||||
|
l := slen
|
||||||
|
if olen > slen {
|
||||||
|
l = olen
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over each part of the prereleases to compare the differences.
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
// Since the lentgh of the parts can be different we need to create
|
||||||
|
// a placeholder. This is to avoid out of bounds issues.
|
||||||
|
stemp := ""
|
||||||
|
if i < slen {
|
||||||
|
stemp = sparts[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
otemp := ""
|
||||||
|
if i < olen {
|
||||||
|
otemp = oparts[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
d := comparePrePart(stemp, otemp)
|
||||||
|
if d != 0 {
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reaching here means two versions are of equal value but have different
|
||||||
|
// metadata (the part following a +). They are not identical in string form
|
||||||
|
// but the version comparison finds them to be equal.
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func comparePrePart(s, o string) int {
|
||||||
|
// Fastpath if they are equal
|
||||||
|
if s == o {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// When s or o are empty we can use the other in an attempt to determine
|
||||||
|
// the response.
|
||||||
|
if s == "" {
|
||||||
|
if o != "" {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if o == "" {
|
||||||
|
if s != "" {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// When comparing strings "99" is greater than "103". To handle
|
||||||
|
// cases like this we need to detect numbers and compare them.
|
||||||
|
|
||||||
|
oi, n1 := strconv.ParseInt(o, 10, 64)
|
||||||
|
si, n2 := strconv.ParseInt(s, 10, 64)
|
||||||
|
|
||||||
|
// The case where both are strings compare the strings
|
||||||
|
if n1 != nil && n2 != nil {
|
||||||
|
if s > o {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
} else if n1 != nil {
|
||||||
|
// o is a string and s is a number
|
||||||
|
return -1
|
||||||
|
} else if n2 != nil {
|
||||||
|
// s is a string and o is a number
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
// Both are numbers
|
||||||
|
if si > oi {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
|
||||||
|
}
|
||||||
30
vendor/github.com/cloudfoundry-community/go-cfclient/.gitignore
generated
vendored
Normal file
30
vendor/github.com/cloudfoundry-community/go-cfclient/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Folders
|
||||||
|
_obj
|
||||||
|
_test
|
||||||
|
_workspace
|
||||||
|
|
||||||
|
# Architecture specific extensions/prefixes
|
||||||
|
*.[568vq]
|
||||||
|
[568vq].out
|
||||||
|
|
||||||
|
*.cgo1.go
|
||||||
|
*.cgo2.c
|
||||||
|
_cgo_defun.c
|
||||||
|
_cgo_gotypes.go
|
||||||
|
_cgo_export.*
|
||||||
|
|
||||||
|
_testmain.go
|
||||||
|
|
||||||
|
*.exe
|
||||||
|
*.test
|
||||||
|
*.prof
|
||||||
|
|
||||||
|
vendor
|
||||||
|
|
||||||
|
# GoLand
|
||||||
|
.idea
|
||||||
14
vendor/github.com/cloudfoundry-community/go-cfclient/.travis.yml
generated
vendored
Normal file
14
vendor/github.com/cloudfoundry-community/go-cfclient/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
language: go
|
||||||
|
sudo: false
|
||||||
|
go:
|
||||||
|
- "1.10"
|
||||||
|
- "1.11"
|
||||||
|
|
||||||
|
script:
|
||||||
|
- FILES=`find . -iname '*.go' -type f -not -path "./vendor/*"`
|
||||||
|
# linting
|
||||||
|
- gofmt -d $FILES
|
||||||
|
- env GO111MODULE=on go tool vet $FILES
|
||||||
|
# testing
|
||||||
|
- go generate
|
||||||
|
- env GO111MODULE=on go test -v -race
|
||||||
174
vendor/github.com/cloudfoundry-community/go-cfclient/Gopkg.lock
generated
vendored
Normal file
174
vendor/github.com/cloudfoundry-community/go-cfclient/Gopkg.lock
generated
vendored
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||||
|
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/Masterminds/semver"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "c7af12943936e8c39859482e61f0574c2fd7fc75"
|
||||||
|
version = "v1.4.2"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/cloudfoundry/gofileutils"
|
||||||
|
packages = ["fileutils"]
|
||||||
|
revision = "4d0c80011a0f37da1711c184028bc40137cd45af"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/codegangsta/inject"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "37d7f8432a3e684eef9b2edece76bdfa6ac85b39"
|
||||||
|
version = "v1.0-rc1"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/go-martini/martini"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "49411a5b646861ad29a6ddd5351717a0a9c49b94"
|
||||||
|
version = "v1.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/golang/protobuf"
|
||||||
|
packages = ["proto"]
|
||||||
|
revision = "1e59b77b52bf8e4b449a57e6f79f21226d571845"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/gopherjs/gopherjs"
|
||||||
|
packages = ["js"]
|
||||||
|
revision = "444abdf920945de5d4a977b572bcc6c674d1e4eb"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/jtolds/gls"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "77f18212c9c7edc9bd6a33d383a7b545ce62f064"
|
||||||
|
version = "v4.2.1"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/martini-contrib/render"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "ec18f8345a1181146728238980606fb1d6f40e8c"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/onsi/gomega"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"format",
|
||||||
|
"internal/assertion",
|
||||||
|
"internal/asyncassertion",
|
||||||
|
"internal/oraclematcher",
|
||||||
|
"internal/testingtsupport",
|
||||||
|
"matchers",
|
||||||
|
"matchers/support/goraph/bipartitegraph",
|
||||||
|
"matchers/support/goraph/edge",
|
||||||
|
"matchers/support/goraph/node",
|
||||||
|
"matchers/support/goraph/util",
|
||||||
|
"types"
|
||||||
|
]
|
||||||
|
revision = "c893efa28eb45626cdaa76c9f653b62488858837"
|
||||||
|
version = "v1.2.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/oxtoacart/bpool"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "4e1c5567d7c2dd59fa4c7c83d34c2f3528b025d6"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/pkg/errors"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
|
||||||
|
version = "v0.8.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/smartystreets/assertions"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"internal/go-render/render",
|
||||||
|
"internal/oglematchers"
|
||||||
|
]
|
||||||
|
revision = "ff1918e1e5a13a74014644ae7c1e0ba2f791364d"
|
||||||
|
version = "1.8.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/smartystreets/goconvey"
|
||||||
|
packages = [
|
||||||
|
"convey",
|
||||||
|
"convey/gotest",
|
||||||
|
"convey/reporting"
|
||||||
|
]
|
||||||
|
revision = "9e8dc3f972df6c8fcc0375ef492c24d0bb204857"
|
||||||
|
version = "1.6.3"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "golang.org/x/net"
|
||||||
|
packages = [
|
||||||
|
"context",
|
||||||
|
"context/ctxhttp",
|
||||||
|
"html",
|
||||||
|
"html/atom",
|
||||||
|
"html/charset"
|
||||||
|
]
|
||||||
|
revision = "9dfe39835686865bff950a07b394c12a98ddc811"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "golang.org/x/oauth2"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"clientcredentials",
|
||||||
|
"internal"
|
||||||
|
]
|
||||||
|
revision = "f95fa95eaa936d9d87489b15d1d18b97c1ba9c28"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "golang.org/x/text"
|
||||||
|
packages = [
|
||||||
|
"encoding",
|
||||||
|
"encoding/charmap",
|
||||||
|
"encoding/htmlindex",
|
||||||
|
"encoding/internal",
|
||||||
|
"encoding/internal/identifier",
|
||||||
|
"encoding/japanese",
|
||||||
|
"encoding/korean",
|
||||||
|
"encoding/simplifiedchinese",
|
||||||
|
"encoding/traditionalchinese",
|
||||||
|
"encoding/unicode",
|
||||||
|
"internal/gen",
|
||||||
|
"internal/tag",
|
||||||
|
"internal/utf8internal",
|
||||||
|
"language",
|
||||||
|
"runes",
|
||||||
|
"transform",
|
||||||
|
"unicode/cldr"
|
||||||
|
]
|
||||||
|
revision = "88f656faf3f37f690df1a32515b479415e1a6769"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "google.golang.org/appengine"
|
||||||
|
packages = [
|
||||||
|
"internal",
|
||||||
|
"internal/base",
|
||||||
|
"internal/datastore",
|
||||||
|
"internal/log",
|
||||||
|
"internal/remote_api",
|
||||||
|
"internal/urlfetch",
|
||||||
|
"urlfetch"
|
||||||
|
]
|
||||||
|
revision = "150dc57a1b433e64154302bdc40b6bb8aefa313a"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "v2"
|
||||||
|
name = "gopkg.in/yaml.v2"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "287cf08546ab5e7e37d55a84f7ed3fd1db036de5"
|
||||||
|
|
||||||
|
[solve-meta]
|
||||||
|
analyzer-name = "dep"
|
||||||
|
analyzer-version = 1
|
||||||
|
inputs-digest = "2e35689146470eb531e3645c63fb933ad86066e63f57021c20e592e25299a02b"
|
||||||
|
solver-name = "gps-cdcl"
|
||||||
|
solver-version = 1
|
||||||
58
vendor/github.com/cloudfoundry-community/go-cfclient/Gopkg.toml
generated
vendored
Normal file
58
vendor/github.com/cloudfoundry-community/go-cfclient/Gopkg.toml
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
|
||||||
|
# Gopkg.toml example
|
||||||
|
#
|
||||||
|
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||||
|
# for detailed Gopkg.toml documentation.
|
||||||
|
#
|
||||||
|
# required = ["github.com/user/thing/cmd/thing"]
|
||||||
|
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||||
|
#
|
||||||
|
# [[constraint]]
|
||||||
|
# name = "github.com/user/project"
|
||||||
|
# version = "1.0.0"
|
||||||
|
#
|
||||||
|
# [[constraint]]
|
||||||
|
# name = "github.com/user/project2"
|
||||||
|
# branch = "dev"
|
||||||
|
# source = "github.com/myfork/project2"
|
||||||
|
#
|
||||||
|
# [[override]]
|
||||||
|
# name = "github.com/x/y"
|
||||||
|
# version = "2.4.0"
|
||||||
|
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/go-martini/martini"
|
||||||
|
version = "1.0.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/martini-contrib/render"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/onsi/gomega"
|
||||||
|
version = "1.2.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/pkg/errors"
|
||||||
|
version = "0.8.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/smartystreets/goconvey"
|
||||||
|
version = "1.6.3"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "golang.org/x/net"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "golang.org/x/oauth2"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "v2"
|
||||||
|
name = "gopkg.in/yaml.v2"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/Masterminds/semver"
|
||||||
|
version = "1.4.2"
|
||||||
21
vendor/github.com/cloudfoundry-community/go-cfclient/LICENSE
generated
vendored
Normal file
21
vendor/github.com/cloudfoundry-community/go-cfclient/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
The MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 Long Nguyen
|
||||||
|
|
||||||
|
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.
|
||||||
59
vendor/github.com/cloudfoundry-community/go-cfclient/README.md
generated
vendored
Normal file
59
vendor/github.com/cloudfoundry-community/go-cfclient/README.md
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
# go-cfclient
|
||||||
|
[](https://travis-ci.org/cloudfoundry-community/go-cfclient)
|
||||||
|
[](http://godoc.org/github.com/cloudfoundry-community/go-cfclient)
|
||||||
|
[](https://goreportcard.com/report/github.com/cloudfoundry-community/go-cfclient)
|
||||||
|
|
||||||
|
### Overview
|
||||||
|
|
||||||
|
`cfclient` is a package to assist you in writing apps that need to interact with [Cloud Foundry](http://cloudfoundry.org).
|
||||||
|
It provides functions and structures to retrieve and update
|
||||||
|
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
go get github.com/cloudfoundry-community/go-cfclient
|
||||||
|
```
|
||||||
|
|
||||||
|
NOTE: Currently this project is not versioning its releases and so breaking changes might be introduced.
|
||||||
|
Whilst hopefully notifications of breaking changes are made via commit messages, ideally your project will use a local
|
||||||
|
vendoring system to lock in a version of `go-cfclient` that is known to work for you.
|
||||||
|
This will allow you to control the timing and maintenance of upgrades to newer versions of this library.
|
||||||
|
|
||||||
|
Some example code:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/cloudfoundry-community/go-cfclient"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
c := &cfclient.Config{
|
||||||
|
ApiAddress: "https://api.10.244.0.34.xip.io",
|
||||||
|
Username: "admin",
|
||||||
|
Password: "admin",
|
||||||
|
}
|
||||||
|
client, _ := cfclient.NewClient(c)
|
||||||
|
apps, _ := client.ListApps()
|
||||||
|
fmt.Println(apps)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Development
|
||||||
|
|
||||||
|
#### Errors
|
||||||
|
|
||||||
|
If the Cloud Foundry error definitions change at <https://github.com/cloudfoundry/cloud_controller_ng/blob/master/vendor/errors/v2.yml>
|
||||||
|
then the error predicate functions in this package need to be regenerated.
|
||||||
|
|
||||||
|
To do this, simply use Go to regenerate the code:
|
||||||
|
|
||||||
|
```
|
||||||
|
go generate
|
||||||
|
```
|
||||||
|
|
||||||
|
### Contributing
|
||||||
|
|
||||||
|
Pull requests welcome.
|
||||||
107
vendor/github.com/cloudfoundry-community/go-cfclient/app_update.go
generated
vendored
Normal file
107
vendor/github.com/cloudfoundry-community/go-cfclient/app_update.go
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdateResponse struct {
|
||||||
|
Metadata Meta `json:"metadata"`
|
||||||
|
Entity UpdateResponseEntity `json:"entity"`
|
||||||
|
}
|
||||||
|
type AppUpdateResource struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Memory int `json:"memory,omitempty"`
|
||||||
|
Instances int `json:"instances,omitempty"`
|
||||||
|
DiskQuota int `json:"disk_quota,omitempty"`
|
||||||
|
SpaceGuid string `json:"space_guid,omitempty"`
|
||||||
|
StackGuid string `json:"stack_guid,omitempty"`
|
||||||
|
State AppState `json:"state,omitempty"`
|
||||||
|
Command string `json:"command,omitempty"`
|
||||||
|
Buildpack string `json:"buildpack,omitempty"`
|
||||||
|
HealthCheckHttpEndpoint string `json:"health_check_http_endpoint,omitempty"`
|
||||||
|
HealthCheckType string `json:"health_check_type,omitempty"`
|
||||||
|
HealthCheckTimeout int `json:"health_check_timeout,omitempty"`
|
||||||
|
Diego bool `json:"diego,omitempty"`
|
||||||
|
EnableSSH bool `json:"enable_ssh,omitempty"`
|
||||||
|
DockerImage string `json:"docker_image,omitempty"`
|
||||||
|
DockerCredentials map[string]interface{} `json:"docker_credentials_json,omitempty"`
|
||||||
|
Environment map[string]interface{} `json:"environment_json,omitempty"`
|
||||||
|
StagingFailedReason string `json:"staging_failed_reason,omitempty"`
|
||||||
|
StagingFailedDescription string `json:"staging_failed_description,omitempty"`
|
||||||
|
Ports []int `json:"ports,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateResponseEntity struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Production bool `json:"production"`
|
||||||
|
SpaceGuid string `json:"space_guid"`
|
||||||
|
StackGuid string `json:"stack_guid"`
|
||||||
|
Buildpack string `json:"buildpack"`
|
||||||
|
DetectedBuildpack string `json:"detected_buildpack"`
|
||||||
|
DetectedBuildpackGuid string `json:"detected_buildpack_guid"`
|
||||||
|
Environment map[string]interface{} `json:"environment_json"`
|
||||||
|
Memory int `json:"memory"`
|
||||||
|
Instances int `json:"instances"`
|
||||||
|
DiskQuota int `json:"disk_quota"`
|
||||||
|
State string `json:"state"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
Command string `json:"command"`
|
||||||
|
Console bool `json:"console"`
|
||||||
|
Debug string `json:"debug"`
|
||||||
|
StagingTaskId string `json:"staging_task_id"`
|
||||||
|
PackageState string `json:"package_state"`
|
||||||
|
HealthCheckHttpEndpoint string `json:"health_check_http_endpoint"`
|
||||||
|
HealthCheckType string `json:"health_check_type"`
|
||||||
|
HealthCheckTimeout int `json:"health_check_timeout"`
|
||||||
|
StagingFailedReason string `json:"staging_failed_reason"`
|
||||||
|
StagingFailedDescription string `json:"staging_failed_description"`
|
||||||
|
Diego bool `json:"diego,omitempty"`
|
||||||
|
DockerImage string `json:"docker_image"`
|
||||||
|
DockerCredentials struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
} `json:"docker_credentials"`
|
||||||
|
PackageUpdatedAt string `json:"package_updated_at"`
|
||||||
|
DetectedStartCommand string `json:"detected_start_command"`
|
||||||
|
EnableSSH bool `json:"enable_ssh"`
|
||||||
|
Ports []int `json:"ports"`
|
||||||
|
SpaceURL string `json:"space_url"`
|
||||||
|
StackURL string `json:"stack_url"`
|
||||||
|
RoutesURL string `json:"routes_url"`
|
||||||
|
EventsURL string `json:"events_url"`
|
||||||
|
ServiceBindingsUrl string `json:"service_bindings_url"`
|
||||||
|
RouteMappingsUrl string `json:"route_mappings_url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) UpdateApp(guid string, aur AppUpdateResource) (UpdateResponse, error) {
|
||||||
|
var updateResponse UpdateResponse
|
||||||
|
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
err := json.NewEncoder(buf).Encode(aur)
|
||||||
|
if err != nil {
|
||||||
|
return UpdateResponse{}, err
|
||||||
|
}
|
||||||
|
req := c.NewRequestWithBody("PUT", fmt.Sprintf("/v2/apps/%s", guid), buf)
|
||||||
|
resp, err := c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return UpdateResponse{}, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return UpdateResponse{}, fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return UpdateResponse{}, err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(body, &updateResponse)
|
||||||
|
if err != nil {
|
||||||
|
return UpdateResponse{}, err
|
||||||
|
}
|
||||||
|
return updateResponse, nil
|
||||||
|
}
|
||||||
80
vendor/github.com/cloudfoundry-community/go-cfclient/app_usage_events.go
generated
vendored
Normal file
80
vendor/github.com/cloudfoundry-community/go-cfclient/app_usage_events.go
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AppUsageEvent struct {
|
||||||
|
GUID string `json:"guid"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
State string `json:"state"`
|
||||||
|
PreviousState string `json:"previous_state"`
|
||||||
|
MemoryInMbPerInstance int `json:"memory_in_mb_per_instance"`
|
||||||
|
PreviousMemoryInMbPerInstance int `json:"previous_memory_in_mb_per_instance"`
|
||||||
|
InstanceCount int `json:"instance_count"`
|
||||||
|
PreviousInstanceCount int `json:"previous_instance_count"`
|
||||||
|
AppGUID string `json:"app_guid"`
|
||||||
|
SpaceGUID string `json:"space_guid"`
|
||||||
|
SpaceName string `json:"space_name"`
|
||||||
|
OrgGUID string `json:"org_guid"`
|
||||||
|
BuildpackGUID string `json:"buildpack_guid"`
|
||||||
|
BuildpackName string `json:"buildpack_name"`
|
||||||
|
PackageState string `json:"package_state"`
|
||||||
|
PreviousPackageState string `json:"previous_package_state"`
|
||||||
|
ParentAppGUID string `json:"parent_app_guid"`
|
||||||
|
ParentAppName string `json:"parent_app_name"`
|
||||||
|
ProcessType string `json:"process_type"`
|
||||||
|
TaskName string `json:"task_name"`
|
||||||
|
TaskGUID string `json:"task_guid"`
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type AppUsageEventsResponse struct {
|
||||||
|
TotalResults int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
NextURL string `json:"next_url"`
|
||||||
|
Resources []AppUsageEventResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AppUsageEventResource struct {
|
||||||
|
Meta Meta `json:"metadata"`
|
||||||
|
Entity AppUsageEvent `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAppUsageEventsByQuery lists all events matching the provided query.
|
||||||
|
func (c *Client) ListAppUsageEventsByQuery(query url.Values) ([]AppUsageEvent, error) {
|
||||||
|
var appUsageEvents []AppUsageEvent
|
||||||
|
requestURL := fmt.Sprintf("/v2/app_usage_events?%s", query.Encode())
|
||||||
|
for {
|
||||||
|
var appUsageEventsResponse AppUsageEventsResponse
|
||||||
|
r := c.NewRequest("GET", requestURL)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "error requesting events")
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&appUsageEventsResponse); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "error unmarshaling events")
|
||||||
|
}
|
||||||
|
for _, e := range appUsageEventsResponse.Resources {
|
||||||
|
e.Entity.GUID = e.Meta.Guid
|
||||||
|
e.Entity.CreatedAt = e.Meta.CreatedAt
|
||||||
|
e.Entity.c = c
|
||||||
|
appUsageEvents = append(appUsageEvents, e.Entity)
|
||||||
|
}
|
||||||
|
requestURL = appUsageEventsResponse.NextURL
|
||||||
|
if requestURL == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return appUsageEvents, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAppUsageEvents lists all unfiltered events.
|
||||||
|
func (c *Client) ListAppUsageEvents() ([]AppUsageEvent, error) {
|
||||||
|
return c.ListAppUsageEventsByQuery(nil)
|
||||||
|
}
|
||||||
182
vendor/github.com/cloudfoundry-community/go-cfclient/appevents.go
generated
vendored
Normal file
182
vendor/github.com/cloudfoundry-community/go-cfclient/appevents.go
generated
vendored
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
//AppCrash app.crash event const
|
||||||
|
AppCrash = "app.crash"
|
||||||
|
//AppStart audit.app.start event const
|
||||||
|
AppStart = "audit.app.start"
|
||||||
|
//AppStop audit.app.stop event const
|
||||||
|
AppStop = "audit.app.stop"
|
||||||
|
//AppUpdate audit.app.update event const
|
||||||
|
AppUpdate = "audit.app.update"
|
||||||
|
//AppCreate audit.app.create event const
|
||||||
|
AppCreate = "audit.app.create"
|
||||||
|
//AppDelete audit.app.delete-request event const
|
||||||
|
AppDelete = "audit.app.delete-request"
|
||||||
|
//AppSSHAuth audit.app.ssh-authorized event const
|
||||||
|
AppSSHAuth = "audit.app.ssh-authorized"
|
||||||
|
//AppSSHUnauth audit.app.ssh-unauthorized event const
|
||||||
|
AppSSHUnauth = "audit.app.ssh-unauthorized"
|
||||||
|
//AppRestage audit.app.restage event const
|
||||||
|
AppRestage = "audit.app.restage"
|
||||||
|
//AppMapRoute audit.app.map-route event const
|
||||||
|
AppMapRoute = "audit.app.map-route"
|
||||||
|
//AppUnmapRoute audit.app.unmap-route event const
|
||||||
|
AppUnmapRoute = "audit.app.unmap-route"
|
||||||
|
//FilterTimestamp const for query filter timestamp
|
||||||
|
FilterTimestamp = "timestamp"
|
||||||
|
//FilterActee const for query filter actee
|
||||||
|
FilterActee = "actee"
|
||||||
|
)
|
||||||
|
|
||||||
|
//ValidOperators const for all valid operators in a query
|
||||||
|
var ValidOperators = []string{":", ">=", "<=", "<", ">", "IN"}
|
||||||
|
|
||||||
|
// AppEventResponse the entire response
|
||||||
|
type AppEventResponse struct {
|
||||||
|
Results int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
PrevURL string `json:"prev_url"`
|
||||||
|
NextURL string `json:"next_url"`
|
||||||
|
Resources []AppEventResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppEventResource the event resources
|
||||||
|
type AppEventResource struct {
|
||||||
|
Meta Meta `json:"metadata"`
|
||||||
|
Entity AppEventEntity `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//AppEventQuery a struct for defining queries like 'q=filter>value' or 'q=filter IN a,b,c'
|
||||||
|
type AppEventQuery struct {
|
||||||
|
Filter string
|
||||||
|
Operator string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
// The AppEventEntity the actual app event body
|
||||||
|
type AppEventEntity struct {
|
||||||
|
//EventTypes are app.crash, audit.app.start, audit.app.stop, audit.app.update, audit.app.create, audit.app.delete-request
|
||||||
|
EventType string `json:"type"`
|
||||||
|
//The GUID of the actor.
|
||||||
|
Actor string `json:"actor"`
|
||||||
|
//The actor type, user or app
|
||||||
|
ActorType string `json:"actor_type"`
|
||||||
|
//The name of the actor.
|
||||||
|
ActorName string `json:"actor_name"`
|
||||||
|
//The GUID of the actee.
|
||||||
|
Actee string `json:"actee"`
|
||||||
|
//The actee type, space, app or v3-app
|
||||||
|
ActeeType string `json:"actee_type"`
|
||||||
|
//The name of the actee.
|
||||||
|
ActeeName string `json:"actee_name"`
|
||||||
|
//Timestamp format "2016-02-26T13:29:44Z". The event creation time.
|
||||||
|
Timestamp time.Time `json:"timestamp"`
|
||||||
|
MetaData struct {
|
||||||
|
//app.crash event fields
|
||||||
|
ExitDescription string `json:"exit_description,omitempty"`
|
||||||
|
ExitReason string `json:"reason,omitempty"`
|
||||||
|
ExitStatus string `json:"exit_status,omitempty"`
|
||||||
|
|
||||||
|
Request struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Instances float64 `json:"instances,omitempty"`
|
||||||
|
State string `json:"state,omitempty"`
|
||||||
|
Memory float64 `json:"memory,omitempty"`
|
||||||
|
EnvironmentVars string `json:"environment_json,omitempty"`
|
||||||
|
DockerCredentials string `json:"docker_credentials_json,omitempty"`
|
||||||
|
//audit.app.create event fields
|
||||||
|
Console bool `json:"console,omitempty"`
|
||||||
|
Buildpack string `json:"buildpack,omitempty"`
|
||||||
|
Space string `json:"space_guid,omitempty"`
|
||||||
|
HealthcheckType string `json:"health_check_type,omitempty"`
|
||||||
|
HealthcheckTimeout float64 `json:"health_check_timeout,omitempty"`
|
||||||
|
Production bool `json:"production,omitempty"`
|
||||||
|
//app.crash event fields
|
||||||
|
Index float64 `json:"index,omitempty"`
|
||||||
|
} `json:"request"`
|
||||||
|
} `json:"metadata"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAppEvents returns all app events based on eventType
|
||||||
|
func (c *Client) ListAppEvents(eventType string) ([]AppEventEntity, error) {
|
||||||
|
return c.ListAppEventsByQuery(eventType, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAppEventsByQuery returns all app events based on eventType and queries
|
||||||
|
func (c *Client) ListAppEventsByQuery(eventType string, queries []AppEventQuery) ([]AppEventEntity, error) {
|
||||||
|
var events []AppEventEntity
|
||||||
|
|
||||||
|
if eventType != AppCrash && eventType != AppStart && eventType != AppStop && eventType != AppUpdate && eventType != AppCreate &&
|
||||||
|
eventType != AppDelete && eventType != AppSSHAuth && eventType != AppSSHUnauth && eventType != AppRestage &&
|
||||||
|
eventType != AppMapRoute && eventType != AppUnmapRoute {
|
||||||
|
return nil, errors.New("Unsupported app event type " + eventType)
|
||||||
|
}
|
||||||
|
|
||||||
|
var query = "/v2/events?q=type:" + eventType
|
||||||
|
//adding the additional queries
|
||||||
|
if queries != nil && len(queries) > 0 {
|
||||||
|
for _, eventQuery := range queries {
|
||||||
|
if eventQuery.Filter != FilterTimestamp && eventQuery.Filter != FilterActee {
|
||||||
|
return nil, errors.New("Unsupported query filter type " + eventQuery.Filter)
|
||||||
|
}
|
||||||
|
if !stringInSlice(eventQuery.Operator, ValidOperators) {
|
||||||
|
return nil, errors.New("Unsupported query operator type " + eventQuery.Operator)
|
||||||
|
}
|
||||||
|
query += "&q=" + eventQuery.Filter + eventQuery.Operator + eventQuery.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
eventResponse, err := c.getAppEventsResponse(query)
|
||||||
|
if err != nil {
|
||||||
|
return []AppEventEntity{}, err
|
||||||
|
}
|
||||||
|
for _, event := range eventResponse.Resources {
|
||||||
|
events = append(events, event.Entity)
|
||||||
|
}
|
||||||
|
query = eventResponse.NextURL
|
||||||
|
if query == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return events, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) getAppEventsResponse(query string) (AppEventResponse, error) {
|
||||||
|
var eventResponse AppEventResponse
|
||||||
|
r := c.NewRequest("GET", query)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return AppEventResponse{}, errors.Wrap(err, "Error requesting appevents")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return AppEventResponse{}, errors.Wrap(err, "Error reading appevents response body")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(resBody, &eventResponse)
|
||||||
|
if err != nil {
|
||||||
|
return AppEventResponse{}, errors.Wrap(err, "Error unmarshalling appevent")
|
||||||
|
}
|
||||||
|
return eventResponse, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func stringInSlice(str string, list []string) bool {
|
||||||
|
for _, v := range list {
|
||||||
|
if v == str {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
659
vendor/github.com/cloudfoundry-community/go-cfclient/apps.go
generated
vendored
Normal file
659
vendor/github.com/cloudfoundry-community/go-cfclient/apps.go
generated
vendored
Normal file
@@ -0,0 +1,659 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/tls"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"mime/multipart"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AppResponse struct {
|
||||||
|
Count int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
NextUrl string `json:"next_url"`
|
||||||
|
Resources []AppResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AppResource struct {
|
||||||
|
Meta Meta `json:"metadata"`
|
||||||
|
Entity App `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AppState string
|
||||||
|
|
||||||
|
const (
|
||||||
|
APP_STOPPED AppState = "STOPPED"
|
||||||
|
APP_STARTED AppState = "STARTED"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HealthCheckType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
HEALTH_HTTP HealthCheckType = "http"
|
||||||
|
HEALTH_PORT HealthCheckType = "port"
|
||||||
|
HEALTH_PROCESS HealthCheckType = "process"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DockerCredentials struct {
|
||||||
|
Username string `json:"username,omitempty"`
|
||||||
|
Password string `json:"password,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AppCreateRequest struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
SpaceGuid string `json:"space_guid"`
|
||||||
|
// Memory for the app, in MB
|
||||||
|
Memory int `json:"memory,omitempty"`
|
||||||
|
// Instances to startup
|
||||||
|
Instances int `json:"instances,omitempty"`
|
||||||
|
// Disk quota in MB
|
||||||
|
DiskQuota int `json:"disk_quota,omitempty"`
|
||||||
|
StackGuid string `json:"stack_guid,omitempty"`
|
||||||
|
// Desired state of the app. Either "STOPPED" or "STARTED"
|
||||||
|
State AppState `json:"state,omitempty"`
|
||||||
|
// Command to start an app
|
||||||
|
Command string `json:"command,omitempty"`
|
||||||
|
// Buildpack to build the app. Three options:
|
||||||
|
// 1. Blank for autodetection
|
||||||
|
// 2. GIT url
|
||||||
|
// 3. Name of an installed buildpack
|
||||||
|
Buildpack string `json:"buildpack,omitempty"`
|
||||||
|
// Endpoint to check if an app is healthy
|
||||||
|
HealthCheckHttpEndpoint string `json:"health_check_http_endpoint,omitempty"`
|
||||||
|
// How to check if an app is healthy. Defaults to HEALTH_PORT if not specified
|
||||||
|
HealthCheckType HealthCheckType `json:"health_check_type,omitempty"`
|
||||||
|
Diego bool `json:"diego,omitempty"`
|
||||||
|
EnableSSH bool `json:"enable_ssh,omitempty"`
|
||||||
|
DockerImage string `json:"docker_image,omitempty"`
|
||||||
|
DockerCredentials DockerCredentials `json:"docker_credentials,omitempty"`
|
||||||
|
Environment map[string]interface{} `json:"environment_json,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type App struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Memory int `json:"memory"`
|
||||||
|
Instances int `json:"instances"`
|
||||||
|
DiskQuota int `json:"disk_quota"`
|
||||||
|
SpaceGuid string `json:"space_guid"`
|
||||||
|
StackGuid string `json:"stack_guid"`
|
||||||
|
State string `json:"state"`
|
||||||
|
PackageState string `json:"package_state"`
|
||||||
|
Command string `json:"command"`
|
||||||
|
Buildpack string `json:"buildpack"`
|
||||||
|
DetectedBuildpack string `json:"detected_buildpack"`
|
||||||
|
DetectedBuildpackGuid string `json:"detected_buildpack_guid"`
|
||||||
|
HealthCheckHttpEndpoint string `json:"health_check_http_endpoint"`
|
||||||
|
HealthCheckType string `json:"health_check_type"`
|
||||||
|
HealthCheckTimeout int `json:"health_check_timeout"`
|
||||||
|
Diego bool `json:"diego"`
|
||||||
|
EnableSSH bool `json:"enable_ssh"`
|
||||||
|
DetectedStartCommand string `json:"detected_start_command"`
|
||||||
|
DockerImage string `json:"docker_image"`
|
||||||
|
DockerCredentials map[string]interface{} `json:"docker_credentials_json"`
|
||||||
|
Environment map[string]interface{} `json:"environment_json"`
|
||||||
|
StagingFailedReason string `json:"staging_failed_reason"`
|
||||||
|
StagingFailedDescription string `json:"staging_failed_description"`
|
||||||
|
Ports []int `json:"ports"`
|
||||||
|
SpaceURL string `json:"space_url"`
|
||||||
|
SpaceData SpaceResource `json:"space"`
|
||||||
|
PackageUpdatedAt string `json:"package_updated_at"`
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type AppInstance struct {
|
||||||
|
State string `json:"state"`
|
||||||
|
Since sinceTime `json:"since"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AppStats struct {
|
||||||
|
State string `json:"state"`
|
||||||
|
Stats struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Uris []string `json:"uris"`
|
||||||
|
Host string `json:"host"`
|
||||||
|
Port int `json:"port"`
|
||||||
|
Uptime int `json:"uptime"`
|
||||||
|
MemQuota int `json:"mem_quota"`
|
||||||
|
DiskQuota int `json:"disk_quota"`
|
||||||
|
FdsQuota int `json:"fds_quota"`
|
||||||
|
Usage struct {
|
||||||
|
Time statTime `json:"time"`
|
||||||
|
CPU float64 `json:"cpu"`
|
||||||
|
Mem int `json:"mem"`
|
||||||
|
Disk int `json:"disk"`
|
||||||
|
} `json:"usage"`
|
||||||
|
} `json:"stats"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AppSummary struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
ServiceCount int `json:"service_count"`
|
||||||
|
RunningInstances int `json:"running_instances"`
|
||||||
|
SpaceGuid string `json:"space_guid"`
|
||||||
|
StackGuid string `json:"stack_guid"`
|
||||||
|
Buildpack string `json:"buildpack"`
|
||||||
|
DetectedBuildpack string `json:"detected_buildpack"`
|
||||||
|
Environment map[string]interface{} `json:"environment_json"`
|
||||||
|
Memory int `json:"memory"`
|
||||||
|
Instances int `json:"instances"`
|
||||||
|
DiskQuota int `json:"disk_quota"`
|
||||||
|
State string `json:"state"`
|
||||||
|
Command string `json:"command"`
|
||||||
|
PackageState string `json:"package_state"`
|
||||||
|
HealthCheckType string `json:"health_check_type"`
|
||||||
|
HealthCheckTimeout int `json:"health_check_timeout"`
|
||||||
|
StagingFailedReason string `json:"staging_failed_reason"`
|
||||||
|
StagingFailedDescription string `json:"staging_failed_description"`
|
||||||
|
Diego bool `json:"diego"`
|
||||||
|
DockerImage string `json:"docker_image"`
|
||||||
|
DetectedStartCommand string `json:"detected_start_command"`
|
||||||
|
EnableSSH bool `json:"enable_ssh"`
|
||||||
|
DockerCredentials map[string]interface{} `json:"docker_credentials_json"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AppEnv struct {
|
||||||
|
// These can have arbitrary JSON so need to map to interface{}
|
||||||
|
Environment map[string]interface{} `json:"environment_json"`
|
||||||
|
StagingEnv map[string]interface{} `json:"staging_env_json"`
|
||||||
|
RunningEnv map[string]interface{} `json:"running_env_json"`
|
||||||
|
SystemEnv map[string]interface{} `json:"system_env_json"`
|
||||||
|
ApplicationEnv map[string]interface{} `json:"application_env_json"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom time types to handle non-RFC3339 formatting in API JSON
|
||||||
|
|
||||||
|
type sinceTime struct {
|
||||||
|
time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *sinceTime) UnmarshalJSON(b []byte) (err error) {
|
||||||
|
timeFlt, err := strconv.ParseFloat(string(b), 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
time := time.Unix(int64(timeFlt), 0)
|
||||||
|
*s = sinceTime{time}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s sinceTime) ToTime() time.Time {
|
||||||
|
t, _ := time.Parse(time.UnixDate, s.Format(time.UnixDate))
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
type statTime struct {
|
||||||
|
time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *statTime) UnmarshalJSON(b []byte) (err error) {
|
||||||
|
timeString, err := strconv.Unquote(string(b))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
possibleFormats := [...]string{time.RFC3339, time.RFC3339Nano, "2006-01-02 15:04:05 -0700", "2006-01-02 15:04:05 MST"}
|
||||||
|
|
||||||
|
var value time.Time
|
||||||
|
for _, possibleFormat := range possibleFormats {
|
||||||
|
if value, err = time.Parse(possibleFormat, timeString); err == nil {
|
||||||
|
*s = statTime{value}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("%s was not in any of the expected Date Formats %v", timeString, possibleFormats)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s statTime) ToTime() time.Time {
|
||||||
|
t, _ := time.Parse(time.UnixDate, s.Format(time.UnixDate))
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) Space() (Space, error) {
|
||||||
|
var spaceResource SpaceResource
|
||||||
|
r := a.c.NewRequest("GET", a.SpaceURL)
|
||||||
|
resp, err := a.c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return Space{}, errors.Wrap(err, "Error requesting space")
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return Space{}, errors.Wrap(err, "Error reading space response")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(resBody, &spaceResource)
|
||||||
|
if err != nil {
|
||||||
|
return Space{}, errors.Wrap(err, "Error unmarshalling body")
|
||||||
|
}
|
||||||
|
return a.c.mergeSpaceResource(spaceResource), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) Summary() (AppSummary, error) {
|
||||||
|
var appSummary AppSummary
|
||||||
|
requestUrl := fmt.Sprintf("/v2/apps/%s/summary", a.Guid)
|
||||||
|
r := a.c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := a.c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return AppSummary{}, errors.Wrap(err, "Error requesting app summary")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return AppSummary{}, errors.Wrap(err, "Error reading app summary body")
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(resBody, &appSummary)
|
||||||
|
if err != nil {
|
||||||
|
return AppSummary{}, errors.Wrap(err, "Error unmarshalling app summary")
|
||||||
|
}
|
||||||
|
return appSummary, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAppsByQueryWithLimits queries totalPages app info. When totalPages is
|
||||||
|
// less and equal than 0, it queries all app info
|
||||||
|
// When there are no more than totalPages apps on server side, all apps info will be returned
|
||||||
|
func (c *Client) ListAppsByQueryWithLimits(query url.Values, totalPages int) ([]App, error) {
|
||||||
|
return c.listApps("/v2/apps?"+query.Encode(), totalPages)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListAppsByQuery(query url.Values) ([]App, error) {
|
||||||
|
return c.listApps("/v2/apps?"+query.Encode(), -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAppByGuidNoInlineCall will fetch app info including space and orgs information
|
||||||
|
// Without using inline-relations-depth=2 call
|
||||||
|
func (c *Client) GetAppByGuidNoInlineCall(guid string) (App, error) {
|
||||||
|
var appResource AppResource
|
||||||
|
r := c.NewRequest("GET", "/v2/apps/"+guid)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return App{}, errors.Wrap(err, "Error requesting apps")
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return App{}, errors.Wrap(err, "Error reading app response body")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(resBody, &appResource)
|
||||||
|
if err != nil {
|
||||||
|
return App{}, errors.Wrap(err, "Error unmarshalling app")
|
||||||
|
}
|
||||||
|
app := c.mergeAppResource(appResource)
|
||||||
|
|
||||||
|
// If no Space Information no need to check org.
|
||||||
|
if app.SpaceGuid != "" {
|
||||||
|
//Getting Spaces Resource
|
||||||
|
space, err := app.Space()
|
||||||
|
if err != nil {
|
||||||
|
errors.Wrap(err, "Unable to get the Space for the apps "+app.Name)
|
||||||
|
} else {
|
||||||
|
app.SpaceData.Entity = space
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Getting orgResource
|
||||||
|
org, err := app.SpaceData.Entity.Org()
|
||||||
|
if err != nil {
|
||||||
|
errors.Wrap(err, "Unable to get the Org for the apps "+app.Name)
|
||||||
|
} else {
|
||||||
|
app.SpaceData.Entity.OrgData.Entity = org
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return app, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListApps() ([]App, error) {
|
||||||
|
q := url.Values{}
|
||||||
|
q.Set("inline-relations-depth", "2")
|
||||||
|
return c.ListAppsByQuery(q)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListAppsByRoute(routeGuid string) ([]App, error) {
|
||||||
|
return c.listApps(fmt.Sprintf("/v2/routes/%s/apps", routeGuid), -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) listApps(requestUrl string, totalPages int) ([]App, error) {
|
||||||
|
pages := 0
|
||||||
|
apps := []App{}
|
||||||
|
for {
|
||||||
|
var appResp AppResponse
|
||||||
|
r := c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error requesting apps")
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error reading app request")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(resBody, &appResp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error unmarshalling app")
|
||||||
|
}
|
||||||
|
for _, app := range appResp.Resources {
|
||||||
|
apps = append(apps, c.mergeAppResource(app))
|
||||||
|
}
|
||||||
|
|
||||||
|
requestUrl = appResp.NextUrl
|
||||||
|
if requestUrl == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
pages += 1
|
||||||
|
if totalPages > 0 && pages >= totalPages {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return apps, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetAppInstances(guid string) (map[string]AppInstance, error) {
|
||||||
|
var appInstances map[string]AppInstance
|
||||||
|
|
||||||
|
requestURL := fmt.Sprintf("/v2/apps/%s/instances", guid)
|
||||||
|
r := c.NewRequest("GET", requestURL)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error requesting app instances")
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error reading app instances")
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(resBody, &appInstances)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error unmarshalling app instances")
|
||||||
|
}
|
||||||
|
return appInstances, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetAppEnv(guid string) (AppEnv, error) {
|
||||||
|
var appEnv AppEnv
|
||||||
|
|
||||||
|
requestURL := fmt.Sprintf("/v2/apps/%s/env", guid)
|
||||||
|
r := c.NewRequest("GET", requestURL)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return appEnv, errors.Wrap(err, "Error requesting app env")
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return appEnv, errors.Wrap(err, "Error reading app env")
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(resBody, &appEnv)
|
||||||
|
if err != nil {
|
||||||
|
return appEnv, errors.Wrap(err, "Error unmarshalling app env")
|
||||||
|
}
|
||||||
|
return appEnv, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetAppRoutes(guid string) ([]Route, error) {
|
||||||
|
return c.fetchRoutes(fmt.Sprintf("/v2/apps/%s/routes", guid))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetAppStats(guid string) (map[string]AppStats, error) {
|
||||||
|
var appStats map[string]AppStats
|
||||||
|
|
||||||
|
requestURL := fmt.Sprintf("/v2/apps/%s/stats", guid)
|
||||||
|
r := c.NewRequest("GET", requestURL)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error requesting app stats")
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error reading app stats")
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(resBody, &appStats)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error unmarshalling app stats")
|
||||||
|
}
|
||||||
|
return appStats, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) KillAppInstance(guid string, index string) error {
|
||||||
|
requestURL := fmt.Sprintf("/v2/apps/%s/instances/%s", guid, index)
|
||||||
|
r := c.NewRequest("DELETE", requestURL)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "Error stopping app %s at index %s", guid, index)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if resp.StatusCode != 204 {
|
||||||
|
return errors.Wrapf(err, "Error stopping app %s at index %s", guid, index)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetAppByGuid(guid string) (App, error) {
|
||||||
|
var appResource AppResource
|
||||||
|
r := c.NewRequest("GET", "/v2/apps/"+guid+"?inline-relations-depth=2")
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return App{}, errors.Wrap(err, "Error requesting apps")
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return App{}, errors.Wrap(err, "Error reading app response body")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(resBody, &appResource)
|
||||||
|
if err != nil {
|
||||||
|
return App{}, errors.Wrap(err, "Error unmarshalling app")
|
||||||
|
}
|
||||||
|
return c.mergeAppResource(appResource), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AppByGuid(guid string) (App, error) {
|
||||||
|
return c.GetAppByGuid(guid)
|
||||||
|
}
|
||||||
|
|
||||||
|
//AppByName takes an appName, and GUIDs for a space and org, and performs
|
||||||
|
// the API lookup with those query parameters set to return you the desired
|
||||||
|
// App object.
|
||||||
|
func (c *Client) AppByName(appName, spaceGuid, orgGuid string) (app App, err error) {
|
||||||
|
query := url.Values{}
|
||||||
|
query.Add("q", fmt.Sprintf("organization_guid:%s", orgGuid))
|
||||||
|
query.Add("q", fmt.Sprintf("space_guid:%s", spaceGuid))
|
||||||
|
query.Add("q", fmt.Sprintf("name:%s", appName))
|
||||||
|
apps, err := c.ListAppsByQuery(query)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(apps) == 0 {
|
||||||
|
err = fmt.Errorf("No app found with name: `%s` in space with GUID `%s` and org with GUID `%s`", appName, spaceGuid, orgGuid)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
app = apps[0]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UploadAppBits uploads the application's contents
|
||||||
|
func (c *Client) UploadAppBits(file io.Reader, appGUID string) error {
|
||||||
|
requestFile, err := ioutil.TempFile("", "requests")
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
requestFile.Close()
|
||||||
|
os.Remove(requestFile.Name())
|
||||||
|
}()
|
||||||
|
|
||||||
|
writer := multipart.NewWriter(requestFile)
|
||||||
|
err = writer.WriteField("resources", "[]")
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "Error uploading app %s bits", appGUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
part, err := writer.CreateFormFile("application", "application.zip")
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "Error uploading app %s bits", appGUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.Copy(part, file)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "Error uploading app %s bits, failed to copy all bytes", appGUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = writer.Close()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "Error uploading app %s bits, failed to close multipart writer", appGUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
requestFile.Seek(0, 0)
|
||||||
|
fileStats, err := requestFile.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "Error uploading app %s bits, failed to get temp file stats", appGUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
requestURL := fmt.Sprintf("/v2/apps/%s/bits", appGUID)
|
||||||
|
r := c.NewRequestWithBody("PUT", requestURL, requestFile)
|
||||||
|
req, err := r.toHTTP()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "Error uploading app %s bits", appGUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
req.ContentLength = fileStats.Size()
|
||||||
|
contentType := fmt.Sprintf("multipart/form-data; boundary=%s", writer.Boundary())
|
||||||
|
req.Header.Set("Content-Type", contentType)
|
||||||
|
|
||||||
|
resp, err := c.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "Error uploading app %s bits", appGUID)
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return errors.Wrapf(err, "Error uploading app %s bits, response code: %d", appGUID, resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAppBits downloads the application's bits as a tar file
|
||||||
|
func (c *Client) GetAppBits(guid string) (io.ReadCloser, error) {
|
||||||
|
requestURL := fmt.Sprintf("/v2/apps/%s/download", guid)
|
||||||
|
req := c.NewRequest("GET", requestURL)
|
||||||
|
resp, err := c.DoRequestWithoutRedirects(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Error downloading app %s bits, API request failed", guid)
|
||||||
|
}
|
||||||
|
if isResponseRedirect(resp) {
|
||||||
|
// directly download the bits from blobstore using a non cloud controller transport
|
||||||
|
// some blobstores will return a 400 if an Authorization header is sent
|
||||||
|
blobStoreLocation := resp.Header.Get("Location")
|
||||||
|
tr := &http.Transport{
|
||||||
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: c.Config.SkipSslValidation},
|
||||||
|
}
|
||||||
|
client := &http.Client{Transport: tr}
|
||||||
|
resp, err = client.Get(blobStoreLocation)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Error downloading app %s bits from blobstore", guid)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, errors.Wrapf(err, "Error downloading app %s bits, expected redirect to blobstore", guid)
|
||||||
|
}
|
||||||
|
return resp.Body, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateApp creates a new empty application that still needs it's
|
||||||
|
// app bit uploaded and to be started
|
||||||
|
func (c *Client) CreateApp(req AppCreateRequest) (App, error) {
|
||||||
|
var appResp AppResource
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
err := json.NewEncoder(buf).Encode(req)
|
||||||
|
if err != nil {
|
||||||
|
return App{}, err
|
||||||
|
}
|
||||||
|
r := c.NewRequestWithBody("POST", "/v2/apps", buf)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return App{}, errors.Wrapf(err, "Error creating app %s", req.Name)
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return App{}, errors.Wrapf(err, "Error creating app %s, response code: %d", req.Name, resp.StatusCode)
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return App{}, errors.Wrapf(err, "Error reading app %s http response body", req.Name)
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(resBody, &appResp)
|
||||||
|
if err != nil {
|
||||||
|
return App{}, errors.Wrapf(err, "Error deserializing app %s response", req.Name)
|
||||||
|
}
|
||||||
|
return c.mergeAppResource(appResp), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) StartApp(guid string) error {
|
||||||
|
startRequest := strings.NewReader(`{ "state": "STARTED" }`)
|
||||||
|
resp, err := c.DoRequest(c.NewRequestWithBody("PUT", fmt.Sprintf("/v2/apps/%s", guid), startRequest))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
return errors.Wrapf(err, "Error starting app %s, response code: %d", guid, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) StopApp(guid string) error {
|
||||||
|
stopRequest := strings.NewReader(`{ "state": "STOPPED" }`)
|
||||||
|
resp, err := c.DoRequest(c.NewRequestWithBody("PUT", fmt.Sprintf("/v2/apps/%s", guid), stopRequest))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
return errors.Wrapf(err, "Error stopping app %s, response code: %d", guid, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DeleteApp(guid string) error {
|
||||||
|
resp, err := c.DoRequest(c.NewRequest("DELETE", fmt.Sprintf("/v2/apps/%s", guid)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
return errors.Wrapf(err, "Error deleting app %s, response code: %d", guid, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) mergeAppResource(app AppResource) App {
|
||||||
|
app.Entity.Guid = app.Meta.Guid
|
||||||
|
app.Entity.CreatedAt = app.Meta.CreatedAt
|
||||||
|
app.Entity.UpdatedAt = app.Meta.UpdatedAt
|
||||||
|
app.Entity.SpaceData.Entity.Guid = app.Entity.SpaceData.Meta.Guid
|
||||||
|
app.Entity.SpaceData.Entity.OrgData.Entity.Guid = app.Entity.SpaceData.Entity.OrgData.Meta.Guid
|
||||||
|
app.Entity.c = c
|
||||||
|
return app.Entity
|
||||||
|
}
|
||||||
|
|
||||||
|
func isResponseRedirect(res *http.Response) bool {
|
||||||
|
switch res.StatusCode {
|
||||||
|
case http.StatusTemporaryRedirect, http.StatusPermanentRedirect, http.StatusMovedPermanently, http.StatusFound, http.StatusSeeOther:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
247
vendor/github.com/cloudfoundry-community/go-cfclient/buildpacks.go
generated
vendored
Normal file
247
vendor/github.com/cloudfoundry-community/go-cfclient/buildpacks.go
generated
vendored
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"mime/multipart"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"code.cloudfoundry.org/gofileutils/fileutils"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BuildpackResponse struct {
|
||||||
|
Count int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
NextUrl string `json:"next_url"`
|
||||||
|
Resources []BuildpackResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BuildpackResource struct {
|
||||||
|
Meta Meta `json:"metadata"`
|
||||||
|
Entity Buildpack `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Buildpack struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
Locked bool `json:"locked"`
|
||||||
|
Position int `json:"position"`
|
||||||
|
Filename string `json:"filename"`
|
||||||
|
Stack string `json:"stack"`
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type BuildpackRequest struct {
|
||||||
|
// These are all pointers to the values so that we can tell
|
||||||
|
// whether people wanted position 0, or enable/unlock values,
|
||||||
|
// vs whether they didn't specify them and want them unchanged/default.
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
Enabled *bool `json:"enabled,omitempty"`
|
||||||
|
Locked *bool `json:"locked,omitempty"`
|
||||||
|
Position *int `json:"position,omitempty"`
|
||||||
|
Stack *string `json:"stack,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) CreateBuildpack(bpr *BuildpackRequest) (*Buildpack, error) {
|
||||||
|
if bpr.Name == nil || *bpr.Name == "" {
|
||||||
|
return nil, errors.New("Unable to create a buidlpack with no name")
|
||||||
|
}
|
||||||
|
requestUrl := "/v2/buildpacks"
|
||||||
|
req := c.NewRequest("POST", requestUrl)
|
||||||
|
req.obj = bpr
|
||||||
|
resp, err := c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error creating buildpack:")
|
||||||
|
}
|
||||||
|
bp, err := c.handleBuildpackResp(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error creating buildpack:")
|
||||||
|
}
|
||||||
|
return &bp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListBuildpacks() ([]Buildpack, error) {
|
||||||
|
var buildpacks []Buildpack
|
||||||
|
requestUrl := "/v2/buildpacks"
|
||||||
|
for {
|
||||||
|
buildpackResp, err := c.getBuildpackResponse(requestUrl)
|
||||||
|
if err != nil {
|
||||||
|
return []Buildpack{}, err
|
||||||
|
}
|
||||||
|
for _, buildpack := range buildpackResp.Resources {
|
||||||
|
buildpacks = append(buildpacks, c.mergeBuildpackResource(buildpack))
|
||||||
|
}
|
||||||
|
requestUrl = buildpackResp.NextUrl
|
||||||
|
if requestUrl == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buildpacks, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DeleteBuildpack(guid string, async bool) error {
|
||||||
|
resp, err := c.DoRequest(c.NewRequest("DELETE", fmt.Sprintf("/v2/buildpacks/%s?async=%t", guid, async)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if (async && (resp.StatusCode != http.StatusAccepted)) || (!async && (resp.StatusCode != http.StatusNoContent)) {
|
||||||
|
return errors.Wrapf(err, "Error deleting buildpack %s, response code: %d", guid, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) getBuildpackResponse(requestUrl string) (BuildpackResponse, error) {
|
||||||
|
var buildpackResp BuildpackResponse
|
||||||
|
r := c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return BuildpackResponse{}, errors.Wrap(err, "Error requesting buildpacks")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return BuildpackResponse{}, errors.Wrap(err, "Error reading buildpack request")
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(resBody, &buildpackResp)
|
||||||
|
if err != nil {
|
||||||
|
return BuildpackResponse{}, errors.Wrap(err, "Error unmarshalling buildpack")
|
||||||
|
}
|
||||||
|
return buildpackResp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) mergeBuildpackResource(buildpack BuildpackResource) Buildpack {
|
||||||
|
buildpack.Entity.Guid = buildpack.Meta.Guid
|
||||||
|
buildpack.Entity.CreatedAt = buildpack.Meta.CreatedAt
|
||||||
|
buildpack.Entity.UpdatedAt = buildpack.Meta.UpdatedAt
|
||||||
|
buildpack.Entity.c = c
|
||||||
|
return buildpack.Entity
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetBuildpackByGuid(buildpackGUID string) (Buildpack, error) {
|
||||||
|
requestUrl := fmt.Sprintf("/v2/buildpacks/%s", buildpackGUID)
|
||||||
|
r := c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return Buildpack{}, errors.Wrap(err, "Error requesting buildpack info")
|
||||||
|
}
|
||||||
|
return c.handleBuildpackResp(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) handleBuildpackResp(resp *http.Response) (Buildpack, error) {
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return Buildpack{}, err
|
||||||
|
}
|
||||||
|
var buildpackResource BuildpackResource
|
||||||
|
if err := json.Unmarshal(body, &buildpackResource); err != nil {
|
||||||
|
return Buildpack{}, err
|
||||||
|
}
|
||||||
|
return c.mergeBuildpackResource(buildpackResource), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Buildpack) Upload(file io.Reader, fileName string) error {
|
||||||
|
var capturedErr error
|
||||||
|
fileutils.TempFile("requests", func(requestFile *os.File, err error) {
|
||||||
|
if err != nil {
|
||||||
|
capturedErr = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writer := multipart.NewWriter(requestFile)
|
||||||
|
part, err := writer.CreateFormFile("buildpack", fileName)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
_ = writer.Close()
|
||||||
|
capturedErr = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.Copy(part, file)
|
||||||
|
if err != nil {
|
||||||
|
capturedErr = fmt.Errorf("Error creating upload: %s", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = writer.Close()
|
||||||
|
if err != nil {
|
||||||
|
capturedErr = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
requestFile.Seek(0, 0)
|
||||||
|
fileStats, err := requestFile.Stat()
|
||||||
|
if err != nil {
|
||||||
|
capturedErr = fmt.Errorf("Error getting file info: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("PUT", fmt.Sprintf("%s/v2/buildpacks/%s/bits", b.c.Config.ApiAddress, b.Guid), requestFile)
|
||||||
|
if err != nil {
|
||||||
|
capturedErr = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req.ContentLength = fileStats.Size()
|
||||||
|
contentType := fmt.Sprintf("multipart/form-data; boundary=%s", writer.Boundary())
|
||||||
|
req.Header.Set("Content-Type", contentType)
|
||||||
|
resp, err := b.c.Do(req) //client.Do() handles the HTTP status code checking for us
|
||||||
|
if err != nil {
|
||||||
|
capturedErr = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
})
|
||||||
|
|
||||||
|
return errors.Wrap(capturedErr, "Error uploading buildpack:")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Buildpack) Update(bpr *BuildpackRequest) error {
|
||||||
|
requestUrl := fmt.Sprintf("/v2/buildpacks/%s", b.Guid)
|
||||||
|
req := b.c.NewRequest("PUT", requestUrl)
|
||||||
|
req.obj = bpr
|
||||||
|
resp, err := b.c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Error updating buildpack:")
|
||||||
|
}
|
||||||
|
newBp, err := b.c.handleBuildpackResp(resp)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Error updating buildpack:")
|
||||||
|
}
|
||||||
|
b.Name = newBp.Name
|
||||||
|
b.Locked = newBp.Locked
|
||||||
|
b.Enabled = newBp.Enabled
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bpr *BuildpackRequest) Lock() {
|
||||||
|
b := true
|
||||||
|
bpr.Locked = &b
|
||||||
|
}
|
||||||
|
func (bpr *BuildpackRequest) Unlock() {
|
||||||
|
b := false
|
||||||
|
bpr.Locked = &b
|
||||||
|
}
|
||||||
|
func (bpr *BuildpackRequest) Enable() {
|
||||||
|
b := true
|
||||||
|
bpr.Enabled = &b
|
||||||
|
}
|
||||||
|
func (bpr *BuildpackRequest) Disable() {
|
||||||
|
b := false
|
||||||
|
bpr.Enabled = &b
|
||||||
|
}
|
||||||
|
func (bpr *BuildpackRequest) SetPosition(i int) {
|
||||||
|
bpr.Position = &i
|
||||||
|
}
|
||||||
|
func (bpr *BuildpackRequest) SetName(s string) {
|
||||||
|
bpr.Name = &s
|
||||||
|
}
|
||||||
|
func (bpr *BuildpackRequest) SetStack(s string) {
|
||||||
|
bpr.Stack = &s
|
||||||
|
}
|
||||||
3171
vendor/github.com/cloudfoundry-community/go-cfclient/cf_error.go
generated
vendored
Normal file
3171
vendor/github.com/cloudfoundry-community/go-cfclient/cf_error.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
407
vendor/github.com/cloudfoundry-community/go-cfclient/client.go
generated
vendored
Normal file
407
vendor/github.com/cloudfoundry-community/go-cfclient/client.go
generated
vendored
Normal file
@@ -0,0 +1,407 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/tls"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
"golang.org/x/oauth2/clientcredentials"
|
||||||
|
)
|
||||||
|
|
||||||
|
//Client used to communicate with Cloud Foundry
|
||||||
|
type Client struct {
|
||||||
|
Config Config
|
||||||
|
Endpoint Endpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
type Endpoint struct {
|
||||||
|
DopplerEndpoint string `json:"doppler_logging_endpoint"`
|
||||||
|
LoggingEndpoint string `json:"logging_endpoint"`
|
||||||
|
AuthEndpoint string `json:"authorization_endpoint"`
|
||||||
|
TokenEndpoint string `json:"token_endpoint"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//Config is used to configure the creation of a client
|
||||||
|
type Config struct {
|
||||||
|
ApiAddress string `json:"api_url"`
|
||||||
|
Username string `json:"user"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
ClientID string `json:"client_id"`
|
||||||
|
ClientSecret string `json:"client_secret"`
|
||||||
|
SkipSslValidation bool `json:"skip_ssl_validation"`
|
||||||
|
HttpClient *http.Client
|
||||||
|
Token string `json:"auth_token"`
|
||||||
|
TokenSource oauth2.TokenSource
|
||||||
|
tokenSourceDeadline *time.Time
|
||||||
|
UserAgent string `json:"user_agent"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request is used to help build up a request
|
||||||
|
type Request struct {
|
||||||
|
method string
|
||||||
|
url string
|
||||||
|
params url.Values
|
||||||
|
body io.Reader
|
||||||
|
obj interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
//DefaultConfig configuration for client
|
||||||
|
//Keep LoginAdress for backward compatibility
|
||||||
|
//Need to be remove in close future
|
||||||
|
func DefaultConfig() *Config {
|
||||||
|
return &Config{
|
||||||
|
ApiAddress: "http://api.bosh-lite.com",
|
||||||
|
Username: "admin",
|
||||||
|
Password: "admin",
|
||||||
|
Token: "",
|
||||||
|
SkipSslValidation: false,
|
||||||
|
HttpClient: http.DefaultClient,
|
||||||
|
UserAgent: "Go-CF-client/1.1",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultEndpoint() *Endpoint {
|
||||||
|
return &Endpoint{
|
||||||
|
DopplerEndpoint: "wss://doppler.10.244.0.34.xip.io:443",
|
||||||
|
LoggingEndpoint: "wss://loggregator.10.244.0.34.xip.io:443",
|
||||||
|
TokenEndpoint: "https://uaa.10.244.0.34.xip.io",
|
||||||
|
AuthEndpoint: "https://login.10.244.0.34.xip.io",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient returns a new client
|
||||||
|
func NewClient(config *Config) (client *Client, err error) {
|
||||||
|
// bootstrap the config
|
||||||
|
defConfig := DefaultConfig()
|
||||||
|
|
||||||
|
if len(config.ApiAddress) == 0 {
|
||||||
|
config.ApiAddress = defConfig.ApiAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(config.Username) == 0 {
|
||||||
|
config.Username = defConfig.Username
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(config.Password) == 0 {
|
||||||
|
config.Password = defConfig.Password
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(config.Token) == 0 {
|
||||||
|
config.Token = defConfig.Token
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(config.UserAgent) == 0 {
|
||||||
|
config.UserAgent = defConfig.UserAgent
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.HttpClient == nil {
|
||||||
|
config.HttpClient = defConfig.HttpClient
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.HttpClient.Transport == nil {
|
||||||
|
config.HttpClient.Transport = shallowDefaultTransport()
|
||||||
|
}
|
||||||
|
|
||||||
|
var tp *http.Transport
|
||||||
|
|
||||||
|
switch t := config.HttpClient.Transport.(type) {
|
||||||
|
case *http.Transport:
|
||||||
|
tp = t
|
||||||
|
case *oauth2.Transport:
|
||||||
|
if bt, ok := t.Base.(*http.Transport); ok {
|
||||||
|
tp = bt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if tp != nil {
|
||||||
|
if tp.TLSClientConfig == nil {
|
||||||
|
tp.TLSClientConfig = &tls.Config{}
|
||||||
|
}
|
||||||
|
tp.TLSClientConfig.InsecureSkipVerify = config.SkipSslValidation
|
||||||
|
}
|
||||||
|
|
||||||
|
config.ApiAddress = strings.TrimRight(config.ApiAddress, "/")
|
||||||
|
|
||||||
|
client = &Client{
|
||||||
|
Config: *config,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := client.refreshEndpoint(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func shallowDefaultTransport() *http.Transport {
|
||||||
|
defaultTransport := http.DefaultTransport.(*http.Transport)
|
||||||
|
return &http.Transport{
|
||||||
|
Proxy: defaultTransport.Proxy,
|
||||||
|
TLSHandshakeTimeout: defaultTransport.TLSHandshakeTimeout,
|
||||||
|
ExpectContinueTimeout: defaultTransport.ExpectContinueTimeout,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUserAuth(ctx context.Context, config Config, endpoint *Endpoint) (Config, error) {
|
||||||
|
authConfig := &oauth2.Config{
|
||||||
|
ClientID: "cf",
|
||||||
|
Scopes: []string{""},
|
||||||
|
Endpoint: oauth2.Endpoint{
|
||||||
|
AuthURL: endpoint.AuthEndpoint + "/oauth/auth",
|
||||||
|
TokenURL: endpoint.TokenEndpoint + "/oauth/token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := authConfig.PasswordCredentialsToken(ctx, config.Username, config.Password)
|
||||||
|
if err != nil {
|
||||||
|
return config, errors.Wrap(err, "Error getting token")
|
||||||
|
}
|
||||||
|
|
||||||
|
config.tokenSourceDeadline = &token.Expiry
|
||||||
|
config.TokenSource = authConfig.TokenSource(ctx, token)
|
||||||
|
config.HttpClient = oauth2.NewClient(ctx, config.TokenSource)
|
||||||
|
|
||||||
|
return config, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func getClientAuth(ctx context.Context, config Config, endpoint *Endpoint) Config {
|
||||||
|
authConfig := &clientcredentials.Config{
|
||||||
|
ClientID: config.ClientID,
|
||||||
|
ClientSecret: config.ClientSecret,
|
||||||
|
TokenURL: endpoint.TokenEndpoint + "/oauth/token",
|
||||||
|
}
|
||||||
|
|
||||||
|
config.TokenSource = authConfig.TokenSource(ctx)
|
||||||
|
config.HttpClient = authConfig.Client(ctx)
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
// getUserTokenAuth initializes client credentials from existing bearer token.
|
||||||
|
func getUserTokenAuth(ctx context.Context, config Config, endpoint *Endpoint) Config {
|
||||||
|
authConfig := &oauth2.Config{
|
||||||
|
ClientID: "cf",
|
||||||
|
Scopes: []string{""},
|
||||||
|
Endpoint: oauth2.Endpoint{
|
||||||
|
AuthURL: endpoint.AuthEndpoint + "/oauth/auth",
|
||||||
|
TokenURL: endpoint.TokenEndpoint + "/oauth/token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token is expected to have no "bearer" prefix
|
||||||
|
token := &oauth2.Token{
|
||||||
|
AccessToken: config.Token,
|
||||||
|
TokenType: "Bearer"}
|
||||||
|
|
||||||
|
config.TokenSource = authConfig.TokenSource(ctx, token)
|
||||||
|
config.HttpClient = oauth2.NewClient(ctx, config.TokenSource)
|
||||||
|
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInfo(api string, httpClient *http.Client) (*Endpoint, error) {
|
||||||
|
var endpoint Endpoint
|
||||||
|
|
||||||
|
if api == "" {
|
||||||
|
return DefaultEndpoint(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := httpClient.Get(api + "/v2/info")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
err = decodeBody(resp, &endpoint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &endpoint, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRequest is used to create a new Request
|
||||||
|
func (c *Client) NewRequest(method, path string) *Request {
|
||||||
|
r := &Request{
|
||||||
|
method: method,
|
||||||
|
url: c.Config.ApiAddress + path,
|
||||||
|
params: make(map[string][]string),
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRequestWithBody is used to create a new request with
|
||||||
|
// arbigtrary body io.Reader.
|
||||||
|
func (c *Client) NewRequestWithBody(method, path string, body io.Reader) *Request {
|
||||||
|
r := c.NewRequest(method, path)
|
||||||
|
|
||||||
|
// Set request body
|
||||||
|
r.body = body
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// DoRequest runs a request with our client
|
||||||
|
func (c *Client) DoRequest(r *Request) (*http.Response, error) {
|
||||||
|
req, err := r.toHTTP()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c.Do(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DoRequestWithoutRedirects executes the request without following redirects
|
||||||
|
func (c *Client) DoRequestWithoutRedirects(r *Request) (*http.Response, error) {
|
||||||
|
prevCheckRedirect := c.Config.HttpClient.CheckRedirect
|
||||||
|
c.Config.HttpClient.CheckRedirect = func(httpReq *http.Request, via []*http.Request) error {
|
||||||
|
return http.ErrUseLastResponse
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
c.Config.HttpClient.CheckRedirect = prevCheckRedirect
|
||||||
|
}()
|
||||||
|
return c.DoRequest(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) Do(req *http.Request) (*http.Response, error) {
|
||||||
|
req.Header.Set("User-Agent", c.Config.UserAgent)
|
||||||
|
if req.Body != nil && req.Header.Get("Content-type") == "" {
|
||||||
|
req.Header.Set("Content-type", "application/json")
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.Config.HttpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode >= http.StatusBadRequest {
|
||||||
|
return c.handleError(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) handleError(resp *http.Response) (*http.Response, error) {
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return resp, CloudFoundryHTTPError{
|
||||||
|
StatusCode: resp.StatusCode,
|
||||||
|
Status: resp.Status,
|
||||||
|
Body: body,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
// Unmarshal V2 error response
|
||||||
|
if strings.HasPrefix(resp.Request.URL.Path, "/v2/") {
|
||||||
|
var cfErr CloudFoundryError
|
||||||
|
if err := json.Unmarshal(body, &cfErr); err != nil {
|
||||||
|
return resp, CloudFoundryHTTPError{
|
||||||
|
StatusCode: resp.StatusCode,
|
||||||
|
Status: resp.Status,
|
||||||
|
Body: body,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, cfErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal a V3 error response and convert it into a V2 model
|
||||||
|
var cfErrorsV3 CloudFoundryErrorsV3
|
||||||
|
if err := json.Unmarshal(body, &cfErrorsV3); err != nil {
|
||||||
|
return resp, CloudFoundryHTTPError{
|
||||||
|
StatusCode: resp.StatusCode,
|
||||||
|
Status: resp.Status,
|
||||||
|
Body: body,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, NewCloudFoundryErrorFromV3Errors(cfErrorsV3)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) refreshEndpoint() error {
|
||||||
|
// we want to keep the Timeout value from config.HttpClient
|
||||||
|
timeout := c.Config.HttpClient.Timeout
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
ctx = context.WithValue(ctx, oauth2.HTTPClient, c.Config.HttpClient)
|
||||||
|
|
||||||
|
endpoint, err := getInfo(c.Config.ApiAddress, oauth2.NewClient(ctx, nil))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Could not get api /v2/info")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case c.Config.Token != "":
|
||||||
|
c.Config = getUserTokenAuth(ctx, c.Config, endpoint)
|
||||||
|
case c.Config.ClientID != "":
|
||||||
|
c.Config = getClientAuth(ctx, c.Config, endpoint)
|
||||||
|
default:
|
||||||
|
c.Config, err = getUserAuth(ctx, c.Config, endpoint)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// make sure original Timeout value will be used
|
||||||
|
if c.Config.HttpClient.Timeout != timeout {
|
||||||
|
c.Config.HttpClient.Timeout = timeout
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Endpoint = *endpoint
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// toHTTP converts the request to an HTTP Request
|
||||||
|
func (r *Request) toHTTP() (*http.Request, error) {
|
||||||
|
|
||||||
|
// Check if we should encode the body
|
||||||
|
if r.body == nil && r.obj != nil {
|
||||||
|
b, err := encodeBody(r.obj)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
r.body = b
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the HTTP Request
|
||||||
|
return http.NewRequest(r.method, r.url, r.body)
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodeBody is used to JSON decode a body
|
||||||
|
func decodeBody(resp *http.Response, out interface{}) error {
|
||||||
|
defer resp.Body.Close()
|
||||||
|
dec := json.NewDecoder(resp.Body)
|
||||||
|
return dec.Decode(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodeBody is used to encode a request body
|
||||||
|
func encodeBody(obj interface{}) (io.Reader, error) {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
enc := json.NewEncoder(buf)
|
||||||
|
if err := enc.Encode(obj); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return buf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetToken() (string, error) {
|
||||||
|
if c.Config.tokenSourceDeadline != nil && c.Config.tokenSourceDeadline.Before(time.Now()) {
|
||||||
|
if err := c.refreshEndpoint(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := c.Config.TokenSource.Token()
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrap(err, "Error getting bearer token")
|
||||||
|
}
|
||||||
|
return "bearer " + token.AccessToken, nil
|
||||||
|
}
|
||||||
290
vendor/github.com/cloudfoundry-community/go-cfclient/domains.go
generated
vendored
Normal file
290
vendor/github.com/cloudfoundry-community/go-cfclient/domains.go
generated
vendored
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DomainsResponse struct {
|
||||||
|
Count int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
NextUrl string `json:"next_url"`
|
||||||
|
Resources []DomainResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SharedDomainsResponse struct {
|
||||||
|
Count int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
NextUrl string `json:"next_url"`
|
||||||
|
Resources []SharedDomainResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DomainResource struct {
|
||||||
|
Meta Meta `json:"metadata"`
|
||||||
|
Entity Domain `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SharedDomainResource struct {
|
||||||
|
Meta Meta `json:"metadata"`
|
||||||
|
Entity SharedDomain `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Domain struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
OwningOrganizationGuid string `json:"owning_organization_guid"`
|
||||||
|
OwningOrganizationUrl string `json:"owning_organization_url"`
|
||||||
|
SharedOrganizationsUrl string `json:"shared_organizations_url"`
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type SharedDomain struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
RouterGroupGuid string `json:"router_group_guid"`
|
||||||
|
RouterGroupType string `json:"router_group_type"`
|
||||||
|
Internal bool `json:"internal"`
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListDomainsByQuery(query url.Values) ([]Domain, error) {
|
||||||
|
var domains []Domain
|
||||||
|
requestUrl := "/v2/private_domains?" + query.Encode()
|
||||||
|
for {
|
||||||
|
var domainResp DomainsResponse
|
||||||
|
r := c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error requesting domains")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error reading domains request")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(resBody, &domainResp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error unmarshaling domains")
|
||||||
|
}
|
||||||
|
for _, domain := range domainResp.Resources {
|
||||||
|
domain.Entity.Guid = domain.Meta.Guid
|
||||||
|
domain.Entity.CreatedAt = domain.Meta.CreatedAt
|
||||||
|
domain.Entity.UpdatedAt = domain.Meta.UpdatedAt
|
||||||
|
domain.Entity.c = c
|
||||||
|
domains = append(domains, domain.Entity)
|
||||||
|
}
|
||||||
|
requestUrl = domainResp.NextUrl
|
||||||
|
if requestUrl == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return domains, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListDomains() ([]Domain, error) {
|
||||||
|
return c.ListDomainsByQuery(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListSharedDomainsByQuery(query url.Values) ([]SharedDomain, error) {
|
||||||
|
var domains []SharedDomain
|
||||||
|
requestUrl := "/v2/shared_domains?" + query.Encode()
|
||||||
|
for {
|
||||||
|
var domainResp SharedDomainsResponse
|
||||||
|
r := c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error requesting shared domains")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error reading shared domains request")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(resBody, &domainResp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error unmarshaling shared domains")
|
||||||
|
}
|
||||||
|
for _, domain := range domainResp.Resources {
|
||||||
|
domain.Entity.Guid = domain.Meta.Guid
|
||||||
|
domain.Entity.CreatedAt = domain.Meta.CreatedAt
|
||||||
|
domain.Entity.UpdatedAt = domain.Meta.UpdatedAt
|
||||||
|
domain.Entity.c = c
|
||||||
|
domains = append(domains, domain.Entity)
|
||||||
|
}
|
||||||
|
requestUrl = domainResp.NextUrl
|
||||||
|
if requestUrl == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return domains, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListSharedDomains() ([]SharedDomain, error) {
|
||||||
|
return c.ListSharedDomainsByQuery(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetSharedDomainByGuid(guid string) (SharedDomain, error) {
|
||||||
|
r := c.NewRequest("GET", "/v2/shared_domains/"+guid)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return SharedDomain{}, errors.Wrap(err, "Error requesting shared domain")
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
retval, err := c.handleSharedDomainResp(resp)
|
||||||
|
return *retval, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) CreateSharedDomain(name string, internal bool, router_group_guid string) (*SharedDomain, error) {
|
||||||
|
req := c.NewRequest("POST", "/v2/shared_domains")
|
||||||
|
params := map[string]interface{}{
|
||||||
|
"name": name,
|
||||||
|
"internal": internal,
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.TrimSpace(router_group_guid) != "" {
|
||||||
|
params["router_group_guid"] = router_group_guid
|
||||||
|
}
|
||||||
|
|
||||||
|
req.obj = params
|
||||||
|
|
||||||
|
resp, err := c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return nil, errors.Wrapf(err, "Error creating shared domain %s, response code: %d", name, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return c.handleSharedDomainResp(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DeleteSharedDomain(guid string, async bool) error {
|
||||||
|
resp, err := c.DoRequest(c.NewRequest("DELETE", fmt.Sprintf("/v2/shared_domains/%s?async=%t", guid, async)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if (async && (resp.StatusCode != http.StatusAccepted)) || (!async && (resp.StatusCode != http.StatusNoContent)) {
|
||||||
|
return errors.Wrapf(err, "Error deleting organization %s, response code: %d", guid, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetDomainByName(name string) (Domain, error) {
|
||||||
|
q := url.Values{}
|
||||||
|
q.Set("q", "name:"+name)
|
||||||
|
domains, err := c.ListDomainsByQuery(q)
|
||||||
|
if err != nil {
|
||||||
|
return Domain{}, errors.Wrapf(err, "Error during domain lookup %s", name)
|
||||||
|
}
|
||||||
|
if len(domains) == 0 {
|
||||||
|
return Domain{}, fmt.Errorf("Unable to find domain %s", name)
|
||||||
|
}
|
||||||
|
return domains[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetSharedDomainByName(name string) (SharedDomain, error) {
|
||||||
|
q := url.Values{}
|
||||||
|
q.Set("q", "name:"+name)
|
||||||
|
domains, err := c.ListSharedDomainsByQuery(q)
|
||||||
|
if err != nil {
|
||||||
|
return SharedDomain{}, errors.Wrapf(err, "Error during shared domain lookup %s", name)
|
||||||
|
}
|
||||||
|
if len(domains) == 0 {
|
||||||
|
return SharedDomain{}, fmt.Errorf("Unable to find shared domain %s", name)
|
||||||
|
}
|
||||||
|
return domains[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) CreateDomain(name, orgGuid string) (*Domain, error) {
|
||||||
|
req := c.NewRequest("POST", "/v2/private_domains")
|
||||||
|
req.obj = map[string]interface{}{
|
||||||
|
"name": name,
|
||||||
|
"owning_organization_guid": orgGuid,
|
||||||
|
}
|
||||||
|
resp, err := c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return nil, errors.Wrapf(err, "Error creating domain %s, response code: %d", name, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return c.handleDomainResp(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DeleteDomain(guid string) error {
|
||||||
|
resp, err := c.DoRequest(c.NewRequest("DELETE", fmt.Sprintf("/v2/private_domains/%s", guid)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
return errors.Wrapf(err, "Error deleting domain %s, response code: %d", guid, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (c *Client) handleDomainResp(resp *http.Response) (*Domain, error) {
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var domainResource DomainResource
|
||||||
|
err = json.Unmarshal(body, &domainResource)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c.mergeDomainResource(domainResource), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) handleSharedDomainResp(resp *http.Response) (*SharedDomain, error) {
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var domainResource SharedDomainResource
|
||||||
|
err = json.Unmarshal(body, &domainResource)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c.mergeSharedDomainResource(domainResource), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) getDomainsResponse(requestUrl string) (DomainsResponse, error) {
|
||||||
|
var domainResp DomainsResponse
|
||||||
|
r := c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return DomainsResponse{}, errors.Wrap(err, "Error requesting domains")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return DomainsResponse{}, errors.Wrap(err, "Error reading domains request")
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(resBody, &domainResp)
|
||||||
|
if err != nil {
|
||||||
|
return DomainsResponse{}, errors.Wrap(err, "Error unmarshalling org")
|
||||||
|
}
|
||||||
|
return domainResp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) mergeDomainResource(domainResource DomainResource) *Domain {
|
||||||
|
domainResource.Entity.Guid = domainResource.Meta.Guid
|
||||||
|
domainResource.Entity.c = c
|
||||||
|
return &domainResource.Entity
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) mergeSharedDomainResource(domainResource SharedDomainResource) *SharedDomain {
|
||||||
|
domainResource.Entity.Guid = domainResource.Meta.Guid
|
||||||
|
domainResource.Entity.c = c
|
||||||
|
return &domainResource.Entity
|
||||||
|
}
|
||||||
59
vendor/github.com/cloudfoundry-community/go-cfclient/environmentvariablegroups.go
generated
vendored
Normal file
59
vendor/github.com/cloudfoundry-community/go-cfclient/environmentvariablegroups.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EnvironmentVariableGroup map[string]interface{}
|
||||||
|
|
||||||
|
func (c *Client) GetRunningEnvironmentVariableGroup() (EnvironmentVariableGroup, error) {
|
||||||
|
return c.getEnvironmentVariableGroup(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetStagingEnvironmentVariableGroup() (EnvironmentVariableGroup, error) {
|
||||||
|
return c.getEnvironmentVariableGroup(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) getEnvironmentVariableGroup(running bool) (EnvironmentVariableGroup, error) {
|
||||||
|
evgType := "staging"
|
||||||
|
if running {
|
||||||
|
evgType = "running"
|
||||||
|
}
|
||||||
|
|
||||||
|
req := c.NewRequest("GET", fmt.Sprintf("/v2/config/environment_variable_groups/%s", evgType))
|
||||||
|
resp, err := c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
evg := EnvironmentVariableGroup{}
|
||||||
|
err = json.NewDecoder(resp.Body).Decode(&evg)
|
||||||
|
return evg, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) SetRunningEnvironmentVariableGroup(evg EnvironmentVariableGroup) error {
|
||||||
|
return c.setEnvironmentVariableGroup(evg, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) SetStagingEnvironmentVariableGroup(evg EnvironmentVariableGroup) error {
|
||||||
|
return c.setEnvironmentVariableGroup(evg, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) setEnvironmentVariableGroup(evg EnvironmentVariableGroup, running bool) error {
|
||||||
|
evgType := "staging"
|
||||||
|
if running {
|
||||||
|
evgType = "running"
|
||||||
|
}
|
||||||
|
|
||||||
|
marshalled, err := json.Marshal(evg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
req := c.NewRequestWithBody("PUT", fmt.Sprintf("/v2/config/environment_variable_groups/%s", evgType), bytes.NewBuffer(marshalled))
|
||||||
|
_, err = c.DoRequest(req)
|
||||||
|
return err
|
||||||
|
}
|
||||||
54
vendor/github.com/cloudfoundry-community/go-cfclient/error.go
generated
vendored
Normal file
54
vendor/github.com/cloudfoundry-community/go-cfclient/error.go
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
//go:generate go run gen_error.go
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CloudFoundryError struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
ErrorCode string `json:"error_code"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CloudFoundryErrorsV3 struct {
|
||||||
|
Errors []CloudFoundryErrorV3 `json:"errors"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CloudFoundryErrorV3 struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Detail string `json:"detail"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CF APIs v3 can return multiple errors, we take the first one and convert it into a V2 model
|
||||||
|
func NewCloudFoundryErrorFromV3Errors(cfErrorsV3 CloudFoundryErrorsV3) CloudFoundryError {
|
||||||
|
if len(cfErrorsV3.Errors) == 0 {
|
||||||
|
return CloudFoundryError{
|
||||||
|
0,
|
||||||
|
"GO-Client-No-Errors",
|
||||||
|
"No Errors in response from V3",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CloudFoundryError{
|
||||||
|
cfErrorsV3.Errors[0].Code,
|
||||||
|
cfErrorsV3.Errors[0].Title,
|
||||||
|
cfErrorsV3.Errors[0].Detail,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfErr CloudFoundryError) Error() string {
|
||||||
|
return fmt.Sprintf("cfclient error (%s|%d): %s", cfErr.ErrorCode, cfErr.Code, cfErr.Description)
|
||||||
|
}
|
||||||
|
|
||||||
|
type CloudFoundryHTTPError struct {
|
||||||
|
StatusCode int
|
||||||
|
Status string
|
||||||
|
Body []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e CloudFoundryHTTPError) Error() string {
|
||||||
|
return fmt.Sprintf("cfclient: HTTP error (%d): %s", e.StatusCode, e.Status)
|
||||||
|
}
|
||||||
94
vendor/github.com/cloudfoundry-community/go-cfclient/events.go
generated
vendored
Normal file
94
vendor/github.com/cloudfoundry-community/go-cfclient/events.go
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EventsResponse is a type that wraps a collection of event resources.
|
||||||
|
type EventsResponse struct {
|
||||||
|
TotalResults int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
NextURL string `json:"next_url"`
|
||||||
|
Resources []EventResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EventResource is a type that contains metadata and the entity for an event.
|
||||||
|
type EventResource struct {
|
||||||
|
Meta Meta `json:"metadata"`
|
||||||
|
Entity Event `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event is a type that contains event data.
|
||||||
|
type Event struct {
|
||||||
|
GUID string `json:"guid"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
Actor string `json:"actor"`
|
||||||
|
ActorType string `json:"actor_type"`
|
||||||
|
ActorName string `json:"actor_name"`
|
||||||
|
ActorUsername string `json:"actor_username"`
|
||||||
|
Actee string `json:"actee"`
|
||||||
|
ActeeType string `json:"actee_type"`
|
||||||
|
ActeeName string `json:"actee_name"`
|
||||||
|
OrganizationGUID string `json:"organization_guid"`
|
||||||
|
SpaceGUID string `json:"space_guid"`
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListEventsByQuery lists all events matching the provided query.
|
||||||
|
func (c *Client) ListEventsByQuery(query url.Values) ([]Event, error) {
|
||||||
|
var events []Event
|
||||||
|
requestURL := fmt.Sprintf("/v2/events?%s", query.Encode())
|
||||||
|
for {
|
||||||
|
var eventResp EventsResponse
|
||||||
|
r := c.NewRequest("GET", requestURL)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "error requesting events")
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&eventResp); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "error unmarshaling events")
|
||||||
|
}
|
||||||
|
for _, e := range eventResp.Resources {
|
||||||
|
e.Entity.GUID = e.Meta.Guid
|
||||||
|
e.Entity.CreatedAt = e.Meta.CreatedAt
|
||||||
|
e.Entity.c = c
|
||||||
|
events = append(events, e.Entity)
|
||||||
|
}
|
||||||
|
requestURL = eventResp.NextURL
|
||||||
|
if requestURL == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return events, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListEvents lists all unfiltered events.
|
||||||
|
func (c *Client) ListEvents() ([]Event, error) {
|
||||||
|
return c.ListEventsByQuery(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TotalEventsByQuery returns the number of events matching the provided query.
|
||||||
|
func (c *Client) TotalEventsByQuery(query url.Values) (int, error) {
|
||||||
|
r := c.NewRequest("GET", fmt.Sprintf("/v2/events?%s", query.Encode()))
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return 0, errors.Wrap(err, "error requesting events")
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
var apiResp EventsResponse
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&apiResp); err != nil {
|
||||||
|
return 0, errors.Wrap(err, "error unmarshaling events")
|
||||||
|
}
|
||||||
|
return apiResp.TotalResults, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TotalEvents returns the number of unfiltered events.
|
||||||
|
func (c *Client) TotalEvents() (int, error) {
|
||||||
|
return c.TotalEventsByQuery(nil)
|
||||||
|
}
|
||||||
115
vendor/github.com/cloudfoundry-community/go-cfclient/gen_error.go
generated
vendored
Normal file
115
vendor/github.com/cloudfoundry-community/go-cfclient/gen_error.go
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"go/format"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CFCode int
|
||||||
|
type HTTPCode int
|
||||||
|
|
||||||
|
type Definition struct {
|
||||||
|
CFCode `yaml:"-"`
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
HTTPCode `yaml:"http_code"`
|
||||||
|
Message string `yaml:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
const url = "https://raw.githubusercontent.com/cloudfoundry/cloud_controller_ng/master/vendor/errors/v2.yml"
|
||||||
|
|
||||||
|
resp, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var m map[CFCode]Definition
|
||||||
|
|
||||||
|
if err := yaml.Unmarshal(body, &m); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var definitions []Definition
|
||||||
|
|
||||||
|
for c, d := range m {
|
||||||
|
d.CFCode = c
|
||||||
|
definitions = append(definitions, d)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(definitions, func(i, j int) bool {
|
||||||
|
return definitions[i].CFCode < definitions[j].CFCode
|
||||||
|
})
|
||||||
|
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
|
||||||
|
if err := packageTemplate.Execute(buf, struct {
|
||||||
|
Timestamp time.Time
|
||||||
|
Definitions []Definition
|
||||||
|
}{
|
||||||
|
Timestamp: time.Now(),
|
||||||
|
Definitions: definitions,
|
||||||
|
}); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dst, err := format.Source(buf.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("%s", buf.Bytes())
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ioutil.WriteFile("cf_error.go", dst, 0600); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// destutter ensures that s does not end in "Error".
|
||||||
|
func destutter(s string) string {
|
||||||
|
return strings.TrimSuffix(s, "Error")
|
||||||
|
}
|
||||||
|
|
||||||
|
var packageTemplate = template.Must(template.New("").Funcs(template.FuncMap{
|
||||||
|
"destutter": destutter,
|
||||||
|
}).Parse(`
|
||||||
|
package cfclient
|
||||||
|
|
||||||
|
// Code generated by go generate. DO NOT EDIT.
|
||||||
|
// This file was generated by robots at
|
||||||
|
// {{ .Timestamp }}
|
||||||
|
|
||||||
|
import "github.com/pkg/errors"
|
||||||
|
|
||||||
|
{{- range .Definitions }}
|
||||||
|
{{$method := printf "Is%sError" (.Name | destutter) }}
|
||||||
|
// {{ $method }} returns a boolean indicating whether
|
||||||
|
// the error is known to report the Cloud Foundry error:
|
||||||
|
// - Cloud Foundry code: {{ .CFCode }}
|
||||||
|
// - HTTP code: {{ .HTTPCode }}
|
||||||
|
// - message: {{ printf "%q" .Message }}
|
||||||
|
func Is{{ .Name | destutter }}Error(err error) bool {
|
||||||
|
cause := errors.Cause(err)
|
||||||
|
cferr, ok := cause.(CloudFoundryError)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return cferr.Code == {{ .CFCode }}
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
`))
|
||||||
20
vendor/github.com/cloudfoundry-community/go-cfclient/go.mod
generated
vendored
Normal file
20
vendor/github.com/cloudfoundry-community/go-cfclient/go.mod
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
module github.com/cloudfoundry-community/go-cfclient
|
||||||
|
|
||||||
|
require (
|
||||||
|
code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f
|
||||||
|
github.com/Masterminds/semver v1.4.2
|
||||||
|
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect
|
||||||
|
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f // indirect
|
||||||
|
github.com/jtolds/gls v4.2.1+incompatible // indirect
|
||||||
|
github.com/kr/pretty v0.1.0 // indirect
|
||||||
|
github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11
|
||||||
|
github.com/onsi/gomega v1.4.3
|
||||||
|
github.com/oxtoacart/bpool v0.0.0-20150712133111-4e1c5567d7c2 // indirect
|
||||||
|
github.com/pkg/errors v0.8.1
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180725160413-e900ae048470 // indirect
|
||||||
|
github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a
|
||||||
|
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190130055435-99b60b757ec1
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
|
||||||
|
)
|
||||||
65
vendor/github.com/cloudfoundry-community/go-cfclient/go.sum
generated
vendored
Normal file
65
vendor/github.com/cloudfoundry-community/go-cfclient/go.sum
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f h1:UrKzEwTgeiff9vxdrfdqxibzpWjxLnuXDI5m6z3GJAk=
|
||||||
|
code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f/go.mod h1:sk5LnIjB/nIEU7yP5sDQExVm62wu0pBh3yrElngUisI=
|
||||||
|
github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc=
|
||||||
|
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||||
|
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q=
|
||||||
|
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
|
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab h1:xveKWz2iaueeTaUgdetzel+U7exyigDYBryyVfV/rZk=
|
||||||
|
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
|
||||||
|
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f h1:FDM3EtwZLyhW48YRiyqjivNlNZjAObv4xt4NnJaU+NQ=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||||
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
|
github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE=
|
||||||
|
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11 h1:YFh+sjyJTMQSYjKwM4dFKhJPJC/wfo98tPUc17HdoYw=
|
||||||
|
github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11/go.mod h1:Ah2dBMoxZEqk118as2T4u4fjfXarE0pPnMJaArZQZsI=
|
||||||
|
github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw=
|
||||||
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
|
||||||
|
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
|
github.com/oxtoacart/bpool v0.0.0-20150712133111-4e1c5567d7c2 h1:CXwSGu/LYmbjEab5aMCs5usQRVBGThelUKBNnoSOuso=
|
||||||
|
github.com/oxtoacart/bpool v0.0.0-20150712133111-4e1c5567d7c2/go.mod h1:L3UMQOThbttwfYRNFOWLLVXMhk5Lkio4GGOtw5UrxS0=
|
||||||
|
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180725160413-e900ae048470 h1:R0uuDVEvfDha2O6dfJRr4/5NBHKEbZhMPZmqOWpEkSo=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180725160413-e900ae048470/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
|
github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a h1:JSvGDIbmil4Ui/dDdFBExb7/cmkNjyX5F97oglmvCDo=
|
||||||
|
github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225 h1:kNX+jCowfMYzvlSvJu5pQWEmyWFrBXJ3PBy10xKMXK8=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3 h1:ulvT7fqt0yHWzpJwI57MezWnYDVpCAYBVuYst/L+fAY=
|
||||||
|
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190130055435-99b60b757ec1 h1:VeAkjQVzKLmu+JnFcK96TPbkuaTIqwGGAzQ9hgwPjVg=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190130055435-99b60b757ec1/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
|
||||||
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
|
||||||
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||||
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
|
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
|
||||||
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
43
vendor/github.com/cloudfoundry-community/go-cfclient/info.go
generated
vendored
Normal file
43
vendor/github.com/cloudfoundry-community/go-cfclient/info.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Info is metadata about a Cloud Foundry deployment
|
||||||
|
type Info struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Build string `json:"build"`
|
||||||
|
Support string `json:"support"`
|
||||||
|
Version int `json:"version"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
AuthorizationEndpoint string `json:"authorization_endpoint"`
|
||||||
|
TokenEndpoint string `json:"token_endpoint"`
|
||||||
|
MinCLIVersion string `json:"min_cli_version"`
|
||||||
|
MinRecommendedCLIVersion string `json:"min_recommended_cli_version"`
|
||||||
|
APIVersion string `json:"api_version"`
|
||||||
|
AppSSHEndpoint string `json:"app_ssh_endpoint"`
|
||||||
|
AppSSHHostKeyFingerprint string `json:"app_ssh_host_key_fingerprint"`
|
||||||
|
AppSSHOauthClient string `json:"app_ssh_oauth_client"`
|
||||||
|
DopplerLoggingEndpoint string `json:"doppler_logging_endpoint"`
|
||||||
|
RoutingEndpoint string `json:"routing_endpoint"`
|
||||||
|
User string `json:"user,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInfo retrieves Info from the Cloud Controller API
|
||||||
|
func (c *Client) GetInfo() (*Info, error) {
|
||||||
|
r := c.NewRequest("GET", "/v2/info")
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error requesting info")
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
var i Info
|
||||||
|
err = json.NewDecoder(resp.Body).Decode(&i)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error unmarshalling info")
|
||||||
|
}
|
||||||
|
return &i, nil
|
||||||
|
}
|
||||||
251
vendor/github.com/cloudfoundry-community/go-cfclient/isolationsegments.go
generated
vendored
Normal file
251
vendor/github.com/cloudfoundry-community/go-cfclient/isolationsegments.go
generated
vendored
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IsolationSegment struct {
|
||||||
|
GUID string `json:"guid"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type IsolationSegementResponse struct {
|
||||||
|
GUID string `json:"guid"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
Links struct {
|
||||||
|
Self struct {
|
||||||
|
Href string `json:"href"`
|
||||||
|
} `json:"self"`
|
||||||
|
Spaces struct {
|
||||||
|
Href string `json:"href"`
|
||||||
|
} `json:"spaces"`
|
||||||
|
Organizations struct {
|
||||||
|
Href string `json:"href"`
|
||||||
|
} `json:"organizations"`
|
||||||
|
} `json:"links"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListIsolationSegmentsResponse struct {
|
||||||
|
Pagination Pagination `json:"pagination"`
|
||||||
|
Resources []IsolationSegementResponse `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) CreateIsolationSegment(name string) (*IsolationSegment, error) {
|
||||||
|
req := c.NewRequest("POST", "/v3/isolation_segments")
|
||||||
|
req.obj = map[string]interface{}{
|
||||||
|
"name": name,
|
||||||
|
}
|
||||||
|
resp, err := c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error while creating isolation segment")
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return nil, fmt.Errorf("Error creating isolation segment %s, response code: %d", name, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return respBodyToIsolationSegment(resp.Body, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func respBodyToIsolationSegment(body io.ReadCloser, c *Client) (*IsolationSegment, error) {
|
||||||
|
bodyRaw, err := ioutil.ReadAll(body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
isr := IsolationSegementResponse{}
|
||||||
|
err = json.Unmarshal(bodyRaw, &isr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &IsolationSegment{
|
||||||
|
GUID: isr.GUID,
|
||||||
|
Name: isr.Name,
|
||||||
|
CreatedAt: isr.CreatedAt,
|
||||||
|
UpdatedAt: isr.UpdatedAt,
|
||||||
|
c: c,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetIsolationSegmentByGUID(guid string) (*IsolationSegment, error) {
|
||||||
|
var isr IsolationSegementResponse
|
||||||
|
r := c.NewRequest("GET", "/v3/isolation_segments/"+guid)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error requesting isolation segment by GUID")
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error reading isolation segment response body")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(resBody, &isr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error unmarshalling isolation segment response")
|
||||||
|
}
|
||||||
|
return &IsolationSegment{Name: isr.Name, GUID: isr.GUID, CreatedAt: isr.CreatedAt, UpdatedAt: isr.UpdatedAt, c: c}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListIsolationSegmentsByQuery(query url.Values) ([]IsolationSegment, error) {
|
||||||
|
var iss []IsolationSegment
|
||||||
|
requestUrl := "/v3/isolation_segments?" + query.Encode()
|
||||||
|
for {
|
||||||
|
var isr ListIsolationSegmentsResponse
|
||||||
|
r := c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error requesting isolation segments")
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error reading isolation segment request")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(resBody, &isr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error unmarshalling isolation segment")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, is := range isr.Resources {
|
||||||
|
iss = append(iss, IsolationSegment{
|
||||||
|
Name: is.Name,
|
||||||
|
GUID: is.GUID,
|
||||||
|
CreatedAt: is.CreatedAt,
|
||||||
|
UpdatedAt: is.UpdatedAt,
|
||||||
|
c: c,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var ok bool
|
||||||
|
requestUrl, ok = isr.Pagination.Next.(string)
|
||||||
|
if !ok || requestUrl == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return iss, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListIsolationSegments() ([]IsolationSegment, error) {
|
||||||
|
return c.ListIsolationSegmentsByQuery(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO listOrgsForIsolationSegments
|
||||||
|
// TODO listSpacesForIsolationSegments
|
||||||
|
// TODO setDefaultIsolationSegmentForOrg
|
||||||
|
|
||||||
|
func (c *Client) DeleteIsolationSegmentByGUID(guid string) error {
|
||||||
|
resp, err := c.DoRequest(c.NewRequest("DELETE", fmt.Sprintf("/v3/isolation_segments/%s", guid)))
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Error during sending DELETE request for isolation segments")
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
return fmt.Errorf("Error deleting isolation segment %s, response code: %d", guid, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IsolationSegment) Delete() error {
|
||||||
|
return i.c.DeleteIsolationSegmentByGUID(i.GUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AddIsolationSegmentToOrg(isolationSegmentGUID, orgGUID string) error {
|
||||||
|
isoSegment := IsolationSegment{GUID: isolationSegmentGUID, c: c}
|
||||||
|
return isoSegment.AddOrg(orgGUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RemoveIsolationSegmentFromOrg(isolationSegmentGUID, orgGUID string) error {
|
||||||
|
isoSegment := IsolationSegment{GUID: isolationSegmentGUID, c: c}
|
||||||
|
return isoSegment.RemoveOrg(orgGUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AddIsolationSegmentToSpace(isolationSegmentGUID, spaceGUID string) error {
|
||||||
|
isoSegment := IsolationSegment{GUID: isolationSegmentGUID, c: c}
|
||||||
|
return isoSegment.AddSpace(spaceGUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RemoveIsolationSegmentFromSpace(isolationSegmentGUID, spaceGUID string) error {
|
||||||
|
isoSegment := IsolationSegment{GUID: isolationSegmentGUID, c: c}
|
||||||
|
return isoSegment.RemoveSpace(spaceGUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IsolationSegment) AddOrg(orgGuid string) error {
|
||||||
|
if i == nil || i.c == nil {
|
||||||
|
return errors.New("No communication handle.")
|
||||||
|
}
|
||||||
|
req := i.c.NewRequest("POST", fmt.Sprintf("/v3/isolation_segments/%s/relationships/organizations", i.GUID))
|
||||||
|
type Entry struct {
|
||||||
|
GUID string `json:"guid"`
|
||||||
|
}
|
||||||
|
req.obj = map[string]interface{}{
|
||||||
|
"data": []Entry{{GUID: orgGuid}},
|
||||||
|
}
|
||||||
|
resp, err := i.c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Error during adding org to isolation segment")
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return fmt.Errorf("Error adding org %s to isolation segment %s, response code: %d", orgGuid, i.Name, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IsolationSegment) RemoveOrg(orgGuid string) error {
|
||||||
|
if i == nil || i.c == nil {
|
||||||
|
return errors.New("No communication handle.")
|
||||||
|
}
|
||||||
|
req := i.c.NewRequest("DELETE", fmt.Sprintf("/v3/isolation_segments/%s/relationships/organizations/%s", i.GUID, orgGuid))
|
||||||
|
resp, err := i.c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "Error during removing org %s in isolation segment %s", orgGuid, i.Name)
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
return fmt.Errorf("Error deleting org %s in isolation segment %s, response code: %d", orgGuid, i.Name, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IsolationSegment) AddSpace(spaceGuid string) error {
|
||||||
|
if i == nil || i.c == nil {
|
||||||
|
return errors.New("No communication handle.")
|
||||||
|
}
|
||||||
|
req := i.c.NewRequest("PUT", fmt.Sprintf("/v2/spaces/%s", spaceGuid))
|
||||||
|
req.obj = map[string]interface{}{
|
||||||
|
"isolation_segment_guid": i.GUID,
|
||||||
|
}
|
||||||
|
resp, err := i.c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "Error during adding space %s to isolation segment %s", spaceGuid, i.Name)
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return fmt.Errorf("Error adding space to isolation segment %s, response code: %d", i.Name, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IsolationSegment) RemoveSpace(spaceGuid string) error {
|
||||||
|
if i == nil || i.c == nil {
|
||||||
|
return errors.New("No communication handle.")
|
||||||
|
}
|
||||||
|
req := i.c.NewRequest("DELETE", fmt.Sprintf("/v2/spaces/%s/isolation_segment", spaceGuid))
|
||||||
|
resp, err := i.c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "Error during deleting space %s in isolation segment %s", spaceGuid, i.Name)
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
return fmt.Errorf("Error deleting space %s from isolation segment %s, response code: %d", spaceGuid, i.Name, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
184
vendor/github.com/cloudfoundry-community/go-cfclient/org_quotas.go
generated
vendored
Normal file
184
vendor/github.com/cloudfoundry-community/go-cfclient/org_quotas.go
generated
vendored
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OrgQuotasResponse struct {
|
||||||
|
Count int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
NextUrl string `json:"next_url"`
|
||||||
|
Resources []OrgQuotasResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrgQuotasResource struct {
|
||||||
|
Meta Meta `json:"metadata"`
|
||||||
|
Entity OrgQuota `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrgQuotaRequest struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
NonBasicServicesAllowed bool `json:"non_basic_services_allowed"`
|
||||||
|
TotalServices int `json:"total_services"`
|
||||||
|
TotalRoutes int `json:"total_routes"`
|
||||||
|
TotalPrivateDomains int `json:"total_private_domains"`
|
||||||
|
MemoryLimit int `json:"memory_limit"`
|
||||||
|
TrialDBAllowed bool `json:"trial_db_allowed"`
|
||||||
|
InstanceMemoryLimit int `json:"instance_memory_limit"`
|
||||||
|
AppInstanceLimit int `json:"app_instance_limit"`
|
||||||
|
AppTaskLimit int `json:"app_task_limit"`
|
||||||
|
TotalServiceKeys int `json:"total_service_keys"`
|
||||||
|
TotalReservedRoutePorts int `json:"total_reserved_route_ports"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrgQuota struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
CreatedAt string `json:"created_at,omitempty"`
|
||||||
|
UpdatedAt string `json:"updated_at,omitempty"`
|
||||||
|
NonBasicServicesAllowed bool `json:"non_basic_services_allowed"`
|
||||||
|
TotalServices int `json:"total_services"`
|
||||||
|
TotalRoutes int `json:"total_routes"`
|
||||||
|
TotalPrivateDomains int `json:"total_private_domains"`
|
||||||
|
MemoryLimit int `json:"memory_limit"`
|
||||||
|
TrialDBAllowed bool `json:"trial_db_allowed"`
|
||||||
|
InstanceMemoryLimit int `json:"instance_memory_limit"`
|
||||||
|
AppInstanceLimit int `json:"app_instance_limit"`
|
||||||
|
AppTaskLimit int `json:"app_task_limit"`
|
||||||
|
TotalServiceKeys int `json:"total_service_keys"`
|
||||||
|
TotalReservedRoutePorts int `json:"total_reserved_route_ports"`
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListOrgQuotasByQuery(query url.Values) ([]OrgQuota, error) {
|
||||||
|
var orgQuotas []OrgQuota
|
||||||
|
requestUrl := "/v2/quota_definitions?" + query.Encode()
|
||||||
|
for {
|
||||||
|
orgQuotasResp, err := c.getOrgQuotasResponse(requestUrl)
|
||||||
|
if err != nil {
|
||||||
|
return []OrgQuota{}, err
|
||||||
|
}
|
||||||
|
for _, org := range orgQuotasResp.Resources {
|
||||||
|
org.Entity.Guid = org.Meta.Guid
|
||||||
|
org.Entity.CreatedAt = org.Meta.CreatedAt
|
||||||
|
org.Entity.UpdatedAt = org.Meta.UpdatedAt
|
||||||
|
org.Entity.c = c
|
||||||
|
orgQuotas = append(orgQuotas, org.Entity)
|
||||||
|
}
|
||||||
|
requestUrl = orgQuotasResp.NextUrl
|
||||||
|
if requestUrl == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return orgQuotas, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListOrgQuotas() ([]OrgQuota, error) {
|
||||||
|
return c.ListOrgQuotasByQuery(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetOrgQuotaByName(name string) (OrgQuota, error) {
|
||||||
|
q := url.Values{}
|
||||||
|
q.Set("q", "name:"+name)
|
||||||
|
orgQuotas, err := c.ListOrgQuotasByQuery(q)
|
||||||
|
if err != nil {
|
||||||
|
return OrgQuota{}, err
|
||||||
|
}
|
||||||
|
if len(orgQuotas) != 1 {
|
||||||
|
return OrgQuota{}, fmt.Errorf("Unable to find org quota " + name)
|
||||||
|
}
|
||||||
|
return orgQuotas[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) getOrgQuotasResponse(requestUrl string) (OrgQuotasResponse, error) {
|
||||||
|
var orgQuotasResp OrgQuotasResponse
|
||||||
|
r := c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return OrgQuotasResponse{}, errors.Wrap(err, "Error requesting org quotas")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return OrgQuotasResponse{}, errors.Wrap(err, "Error reading org quotas body")
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(resBody, &orgQuotasResp)
|
||||||
|
if err != nil {
|
||||||
|
return OrgQuotasResponse{}, errors.Wrap(err, "Error unmarshalling org quotas")
|
||||||
|
}
|
||||||
|
return orgQuotasResp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) CreateOrgQuota(orgQuote OrgQuotaRequest) (*OrgQuota, error) {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
err := json.NewEncoder(buf).Encode(orgQuote)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
r := c.NewRequestWithBody("POST", "/v2/quota_definitions", buf)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return nil, fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return c.handleOrgQuotaResp(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) UpdateOrgQuota(orgQuotaGUID string, orgQuota OrgQuotaRequest) (*OrgQuota, error) {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
err := json.NewEncoder(buf).Encode(orgQuota)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
r := c.NewRequestWithBody("PUT", fmt.Sprintf("/v2/quota_definitions/%s", orgQuotaGUID), buf)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return nil, fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return c.handleOrgQuotaResp(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DeleteOrgQuota(guid string, async bool) error {
|
||||||
|
resp, err := c.DoRequest(c.NewRequest("DELETE", fmt.Sprintf("/v2/quota_definitions/%s?async=%t", guid, async)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if (async && (resp.StatusCode != http.StatusAccepted)) || (!async && (resp.StatusCode != http.StatusNoContent)) {
|
||||||
|
return errors.Wrapf(err, "Error deleting organization %s, response code: %d", guid, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) handleOrgQuotaResp(resp *http.Response) (*OrgQuota, error) {
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var orgQuotasResource OrgQuotasResource
|
||||||
|
err = json.Unmarshal(body, &orgQuotasResource)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c.mergeOrgQuotaResource(orgQuotasResource), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) mergeOrgQuotaResource(orgQuotaResource OrgQuotasResource) *OrgQuota {
|
||||||
|
orgQuotaResource.Entity.Guid = orgQuotaResource.Meta.Guid
|
||||||
|
orgQuotaResource.Entity.CreatedAt = orgQuotaResource.Meta.CreatedAt
|
||||||
|
orgQuotaResource.Entity.UpdatedAt = orgQuotaResource.Meta.UpdatedAt
|
||||||
|
orgQuotaResource.Entity.c = c
|
||||||
|
return &orgQuotaResource.Entity
|
||||||
|
}
|
||||||
832
vendor/github.com/cloudfoundry-community/go-cfclient/orgs.go
generated
vendored
Normal file
832
vendor/github.com/cloudfoundry-community/go-cfclient/orgs.go
generated
vendored
Normal file
@@ -0,0 +1,832 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OrgResponse struct {
|
||||||
|
Count int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
NextUrl string `json:"next_url"`
|
||||||
|
Resources []OrgResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrgResource struct {
|
||||||
|
Meta Meta `json:"metadata"`
|
||||||
|
Entity Org `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrgUserResponse struct {
|
||||||
|
Count int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
NextURL string `json:"next_url"`
|
||||||
|
Resources []UserResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Org struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
QuotaDefinitionGuid string `json:"quota_definition_guid"`
|
||||||
|
DefaultIsolationSegmentGuid string `json:"default_isolation_segment_guid"`
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrgSummary struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Spaces []OrgSummarySpaces `json:"spaces"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrgSummarySpaces struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
ServiceCount int `json:"service_count"`
|
||||||
|
AppCount int `json:"app_count"`
|
||||||
|
MemDevTotal int `json:"mem_dev_total"`
|
||||||
|
MemProdTotal int `json:"mem_prod_total"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrgRequest struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Status string `json:"status,omitempty"`
|
||||||
|
QuotaDefinitionGuid string `json:"quota_definition_guid,omitempty"`
|
||||||
|
DefaultIsolationSegmentGuid string `json:"default_isolation_segment_guid,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListOrgsByQuery(query url.Values) ([]Org, error) {
|
||||||
|
var orgs []Org
|
||||||
|
requestURL := "/v2/organizations?" + query.Encode()
|
||||||
|
for {
|
||||||
|
orgResp, err := c.getOrgResponse(requestURL)
|
||||||
|
if err != nil {
|
||||||
|
return []Org{}, err
|
||||||
|
}
|
||||||
|
for _, org := range orgResp.Resources {
|
||||||
|
orgs = append(orgs, c.mergeOrgResource(org))
|
||||||
|
}
|
||||||
|
requestURL = orgResp.NextUrl
|
||||||
|
if requestURL == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return orgs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListOrgs() ([]Org, error) {
|
||||||
|
return c.ListOrgsByQuery(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetOrgByName(name string) (Org, error) {
|
||||||
|
var org Org
|
||||||
|
q := url.Values{}
|
||||||
|
q.Set("q", "name:"+name)
|
||||||
|
orgs, err := c.ListOrgsByQuery(q)
|
||||||
|
if err != nil {
|
||||||
|
return org, err
|
||||||
|
}
|
||||||
|
if len(orgs) == 0 {
|
||||||
|
return org, fmt.Errorf("Unable to find org %s", name)
|
||||||
|
}
|
||||||
|
return orgs[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetOrgByGuid(guid string) (Org, error) {
|
||||||
|
var orgRes OrgResource
|
||||||
|
r := c.NewRequest("GET", "/v2/organizations/"+guid)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return Org{}, err
|
||||||
|
}
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return Org{}, err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(body, &orgRes)
|
||||||
|
if err != nil {
|
||||||
|
return Org{}, err
|
||||||
|
}
|
||||||
|
return c.mergeOrgResource(orgRes), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) OrgSpaces(guid string) ([]Space, error) {
|
||||||
|
return c.fetchSpaces(fmt.Sprintf("/v2/organizations/%s/spaces", guid))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) Summary() (OrgSummary, error) {
|
||||||
|
var orgSummary OrgSummary
|
||||||
|
requestURL := fmt.Sprintf("/v2/organizations/%s/summary", o.Guid)
|
||||||
|
r := o.c.NewRequest("GET", requestURL)
|
||||||
|
resp, err := o.c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return OrgSummary{}, errors.Wrap(err, "Error requesting org summary")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return OrgSummary{}, errors.Wrap(err, "Error reading org summary body")
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(resBody, &orgSummary)
|
||||||
|
if err != nil {
|
||||||
|
return OrgSummary{}, errors.Wrap(err, "Error unmarshalling org summary")
|
||||||
|
}
|
||||||
|
return orgSummary, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) Quota() (*OrgQuota, error) {
|
||||||
|
var orgQuota *OrgQuota
|
||||||
|
var orgQuotaResource OrgQuotasResource
|
||||||
|
if o.QuotaDefinitionGuid == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
requestURL := fmt.Sprintf("/v2/quota_definitions/%s", o.QuotaDefinitionGuid)
|
||||||
|
r := o.c.NewRequest("GET", requestURL)
|
||||||
|
resp, err := o.c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return &OrgQuota{}, errors.Wrap(err, "Error requesting org quota")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return &OrgQuota{}, errors.Wrap(err, "Error reading org quota body")
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(resBody, &orgQuotaResource)
|
||||||
|
if err != nil {
|
||||||
|
return &OrgQuota{}, errors.Wrap(err, "Error unmarshalling org quota")
|
||||||
|
}
|
||||||
|
orgQuota = &orgQuotaResource.Entity
|
||||||
|
orgQuota.Guid = orgQuotaResource.Meta.Guid
|
||||||
|
orgQuota.c = o.c
|
||||||
|
return orgQuota, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListOrgUsersByQuery(orgGUID string, query url.Values) ([]User, error) {
|
||||||
|
var users []User
|
||||||
|
requestURL := fmt.Sprintf("/v2/organizations/%s/users?%s", orgGUID, query.Encode())
|
||||||
|
for {
|
||||||
|
omResp, err := c.getOrgUserResponse(requestURL)
|
||||||
|
if err != nil {
|
||||||
|
return []User{}, err
|
||||||
|
}
|
||||||
|
for _, u := range omResp.Resources {
|
||||||
|
users = append(users, c.mergeUserResource(u))
|
||||||
|
}
|
||||||
|
requestURL = omResp.NextURL
|
||||||
|
if requestURL == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return users, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListOrgUsers(orgGUID string) ([]User, error) {
|
||||||
|
return c.ListOrgUsersByQuery(orgGUID, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) listOrgRolesByQuery(orgGUID, role string, query url.Values) ([]User, error) {
|
||||||
|
var users []User
|
||||||
|
requestURL := fmt.Sprintf("/v2/organizations/%s/%s?%s", orgGUID, role, query.Encode())
|
||||||
|
for {
|
||||||
|
omResp, err := c.getOrgUserResponse(requestURL)
|
||||||
|
if err != nil {
|
||||||
|
return []User{}, err
|
||||||
|
}
|
||||||
|
for _, u := range omResp.Resources {
|
||||||
|
users = append(users, c.mergeUserResource(u))
|
||||||
|
}
|
||||||
|
requestURL = omResp.NextURL
|
||||||
|
if requestURL == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return users, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListOrgManagersByQuery(orgGUID string, query url.Values) ([]User, error) {
|
||||||
|
return c.listOrgRolesByQuery(orgGUID, "managers", query)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListOrgManagers(orgGUID string) ([]User, error) {
|
||||||
|
return c.ListOrgManagersByQuery(orgGUID, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListOrgAuditorsByQuery(orgGUID string, query url.Values) ([]User, error) {
|
||||||
|
return c.listOrgRolesByQuery(orgGUID, "auditors", query)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListOrgAuditors(orgGUID string) ([]User, error) {
|
||||||
|
return c.ListOrgAuditorsByQuery(orgGUID, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListOrgBillingManagersByQuery(orgGUID string, query url.Values) ([]User, error) {
|
||||||
|
return c.listOrgRolesByQuery(orgGUID, "billing_managers", query)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListOrgBillingManagers(orgGUID string) ([]User, error) {
|
||||||
|
return c.ListOrgBillingManagersByQuery(orgGUID, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AssociateOrgManager(orgGUID, userGUID string) (Org, error) {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.AssociateManager(userGUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AssociateOrgManagerByUsername(orgGUID, name string) (Org, error) {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.AssociateManagerByUsername(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AssociateOrgManagerByUsernameAndOrigin(orgGUID, name, origin string) (Org, error) {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.AssociateManagerByUsernameAndOrigin(name, origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AssociateOrgUser(orgGUID, userGUID string) (Org, error) {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.AssociateUser(userGUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AssociateOrgAuditor(orgGUID, userGUID string) (Org, error) {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.AssociateAuditor(userGUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AssociateOrgUserByUsername(orgGUID, name string) (Org, error) {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.AssociateUserByUsername(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AssociateOrgUserByUsernameAndOrigin(orgGUID, name, origin string) (Org, error) {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.AssociateUserByUsernameAndOrigin(name, origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AssociateOrgAuditorByUsername(orgGUID, name string) (Org, error) {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.AssociateAuditorByUsername(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AssociateOrgAuditorByUsernameAndOrigin(orgGUID, name, origin string) (Org, error) {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.AssociateAuditorByUsernameAndOrigin(name, origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AssociateOrgBillingManager(orgGUID, userGUID string) (Org, error) {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.AssociateBillingManager(userGUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AssociateOrgBillingManagerByUsername(orgGUID, name string) (Org, error) {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.AssociateBillingManagerByUsername(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AssociateOrgBillingManagerByUsernameAndOrigin(orgGUID, name, origin string) (Org, error) {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.AssociateBillingManagerByUsernameAndOrigin(name, origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RemoveOrgManager(orgGUID, userGUID string) error {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.RemoveManager(userGUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RemoveOrgManagerByUsername(orgGUID, name string) error {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.RemoveManagerByUsername(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RemoveOrgManagerByUsernameAndOrigin(orgGUID, name, origin string) error {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.RemoveManagerByUsernameAndOrigin(name, origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RemoveOrgUser(orgGUID, userGUID string) error {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.RemoveUser(userGUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RemoveOrgAuditor(orgGUID, userGUID string) error {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.RemoveAuditor(userGUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RemoveOrgUserByUsername(orgGUID, name string) error {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.RemoveUserByUsername(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RemoveOrgUserByUsernameAndOrigin(orgGUID, name, origin string) error {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.RemoveUserByUsernameAndOrigin(name, origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RemoveOrgAuditorByUsername(orgGUID, name string) error {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.RemoveAuditorByUsername(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RemoveOrgAuditorByUsernameAndOrigin(orgGUID, name, origin string) error {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.RemoveAuditorByUsernameAndOrigin(name, origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RemoveOrgBillingManager(orgGUID, userGUID string) error {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.RemoveBillingManager(userGUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RemoveOrgBillingManagerByUsername(orgGUID, name string) error {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.RemoveBillingManagerByUsername(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RemoveOrgBillingManagerByUsernameAndOrigin(orgGUID, name, origin string) error {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.RemoveBillingManagerByUsernameAndOrigin(name, origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListOrgSpaceQuotas(orgGUID string) ([]SpaceQuota, error) {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.ListSpaceQuotas()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListOrgPrivateDomains(orgGUID string) ([]Domain, error) {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.ListPrivateDomains()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ShareOrgPrivateDomain(orgGUID, privateDomainGUID string) (*Domain, error) {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.SharePrivateDomain(privateDomainGUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) UnshareOrgPrivateDomain(orgGUID, privateDomainGUID string) error {
|
||||||
|
org := Org{Guid: orgGUID, c: c}
|
||||||
|
return org.UnsharePrivateDomain(privateDomainGUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) ListSpaceQuotas() ([]SpaceQuota, error) {
|
||||||
|
var spaceQuotas []SpaceQuota
|
||||||
|
requestURL := fmt.Sprintf("/v2/organizations/%s/space_quota_definitions", o.Guid)
|
||||||
|
for {
|
||||||
|
spaceQuotasResp, err := o.c.getSpaceQuotasResponse(requestURL)
|
||||||
|
if err != nil {
|
||||||
|
return []SpaceQuota{}, err
|
||||||
|
}
|
||||||
|
for _, resource := range spaceQuotasResp.Resources {
|
||||||
|
spaceQuotas = append(spaceQuotas, *o.c.mergeSpaceQuotaResource(resource))
|
||||||
|
}
|
||||||
|
requestURL = spaceQuotasResp.NextUrl
|
||||||
|
if requestURL == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return spaceQuotas, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) ListPrivateDomains() ([]Domain, error) {
|
||||||
|
var domains []Domain
|
||||||
|
requestURL := fmt.Sprintf("/v2/organizations/%s/private_domains", o.Guid)
|
||||||
|
for {
|
||||||
|
domainsResp, err := o.c.getDomainsResponse(requestURL)
|
||||||
|
if err != nil {
|
||||||
|
return []Domain{}, err
|
||||||
|
}
|
||||||
|
for _, resource := range domainsResp.Resources {
|
||||||
|
domains = append(domains, *o.c.mergeDomainResource(resource))
|
||||||
|
}
|
||||||
|
requestURL = domainsResp.NextUrl
|
||||||
|
if requestURL == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return domains, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) SharePrivateDomain(privateDomainGUID string) (*Domain, error) {
|
||||||
|
requestURL := fmt.Sprintf("/v2/organizations/%s/private_domains/%s", o.Guid, privateDomainGUID)
|
||||||
|
r := o.c.NewRequest("PUT", requestURL)
|
||||||
|
resp, err := o.c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return nil, errors.Wrapf(err, "Error sharing domain %s for org %s, response code: %d", privateDomainGUID, o.Guid, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return o.c.handleDomainResp(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) UnsharePrivateDomain(privateDomainGUID string) error {
|
||||||
|
requestURL := fmt.Sprintf("/v2/organizations/%s/private_domains/%s", o.Guid, privateDomainGUID)
|
||||||
|
r := o.c.NewRequest("DELETE", requestURL)
|
||||||
|
resp, err := o.c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
return errors.Wrapf(err, "Error unsharing domain %s for org %s, response code: %d", privateDomainGUID, o.Guid, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) associateRole(userGUID, role string) (Org, error) {
|
||||||
|
requestURL := fmt.Sprintf("/v2/organizations/%s/%s/%s", o.Guid, role, userGUID)
|
||||||
|
r := o.c.NewRequest("PUT", requestURL)
|
||||||
|
resp, err := o.c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return Org{}, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return Org{}, errors.Wrapf(err, "Error associating %s %s, response code: %d", role, userGUID, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return o.c.handleOrgResp(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) associateRoleByUsernameAndOrigin(name, role, origin string) (Org, error) {
|
||||||
|
requestURL := fmt.Sprintf("/v2/organizations/%s/%s", o.Guid, role)
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
payload := make(map[string]string)
|
||||||
|
payload["username"] = name
|
||||||
|
if origin != "" {
|
||||||
|
payload["origin"] = origin
|
||||||
|
}
|
||||||
|
err := json.NewEncoder(buf).Encode(payload)
|
||||||
|
if err != nil {
|
||||||
|
return Org{}, err
|
||||||
|
}
|
||||||
|
r := o.c.NewRequestWithBody("PUT", requestURL, buf)
|
||||||
|
resp, err := o.c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return Org{}, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return Org{}, errors.Wrapf(err, "Error associating %s %s, response code: %d", role, name, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return o.c.handleOrgResp(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) AssociateManager(userGUID string) (Org, error) {
|
||||||
|
return o.associateRole(userGUID, "managers")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) AssociateManagerByUsername(name string) (Org, error) {
|
||||||
|
return o.associateRoleByUsernameAndOrigin(name, "managers", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) AssociateManagerByUsernameAndOrigin(name, origin string) (Org, error) {
|
||||||
|
return o.associateRoleByUsernameAndOrigin(name, "managers", origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) AssociateUser(userGUID string) (Org, error) {
|
||||||
|
requestURL := fmt.Sprintf("/v2/organizations/%s/users/%s", o.Guid, userGUID)
|
||||||
|
r := o.c.NewRequest("PUT", requestURL)
|
||||||
|
resp, err := o.c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return Org{}, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return Org{}, errors.Wrapf(err, "Error associating user %s, response code: %d", userGUID, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return o.c.handleOrgResp(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) AssociateAuditor(userGUID string) (Org, error) {
|
||||||
|
return o.associateRole(userGUID, "auditors")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) AssociateAuditorByUsername(name string) (Org, error) {
|
||||||
|
return o.associateRoleByUsernameAndOrigin(name, "auditors", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) AssociateAuditorByUsernameAndOrigin(name, origin string) (Org, error) {
|
||||||
|
return o.associateRoleByUsernameAndOrigin(name, "auditors", origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) AssociateBillingManager(userGUID string) (Org, error) {
|
||||||
|
return o.associateRole(userGUID, "billing_managers")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) AssociateBillingManagerByUsername(name string) (Org, error) {
|
||||||
|
return o.associateRoleByUsernameAndOrigin(name, "billing_managers", "")
|
||||||
|
}
|
||||||
|
func (o *Org) AssociateBillingManagerByUsernameAndOrigin(name, origin string) (Org, error) {
|
||||||
|
return o.associateRoleByUsernameAndOrigin(name, "billing_managers", origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) AssociateUserByUsername(name string) (Org, error) {
|
||||||
|
return o.associateUserByUsernameAndOrigin(name, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) AssociateUserByUsernameAndOrigin(name, origin string) (Org, error) {
|
||||||
|
return o.associateUserByUsernameAndOrigin(name, origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) associateUserByUsernameAndOrigin(name, origin string) (Org, error) {
|
||||||
|
requestURL := fmt.Sprintf("/v2/organizations/%s/users", o.Guid)
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
payload := make(map[string]string)
|
||||||
|
payload["username"] = name
|
||||||
|
if origin != "" {
|
||||||
|
payload["origin"] = origin
|
||||||
|
}
|
||||||
|
err := json.NewEncoder(buf).Encode(payload)
|
||||||
|
if err != nil {
|
||||||
|
return Org{}, err
|
||||||
|
}
|
||||||
|
r := o.c.NewRequestWithBody("PUT", requestURL, buf)
|
||||||
|
resp, err := o.c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return Org{}, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return Org{}, errors.Wrapf(err, "Error associating user %s, response code: %d", name, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return o.c.handleOrgResp(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) removeRole(userGUID, role string) error {
|
||||||
|
requestURL := fmt.Sprintf("/v2/organizations/%s/%s/%s", o.Guid, role, userGUID)
|
||||||
|
r := o.c.NewRequest("DELETE", requestURL)
|
||||||
|
resp, err := o.c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
return errors.Wrapf(err, "Error removing %s %s, response code: %d", role, userGUID, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) removeRoleByUsernameAndOrigin(name, role, origin string) error {
|
||||||
|
var requestURL string
|
||||||
|
var method string
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
payload := make(map[string]string)
|
||||||
|
payload["username"] = name
|
||||||
|
if origin != "" {
|
||||||
|
requestURL = fmt.Sprintf("/v2/organizations/%s/%s/remove", o.Guid, role)
|
||||||
|
method = "POST"
|
||||||
|
payload["origin"] = origin
|
||||||
|
} else {
|
||||||
|
requestURL = fmt.Sprintf("/v2/organizations/%s/%s", o.Guid, role)
|
||||||
|
method = "DELETE"
|
||||||
|
}
|
||||||
|
err := json.NewEncoder(buf).Encode(payload)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
r := o.c.NewRequestWithBody(method, requestURL, buf)
|
||||||
|
resp, err := o.c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
return errors.Wrapf(err, "Error removing manager %s, response code: %d", name, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) RemoveManager(userGUID string) error {
|
||||||
|
return o.removeRole(userGUID, "managers")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) RemoveManagerByUsername(name string) error {
|
||||||
|
return o.removeRoleByUsernameAndOrigin(name, "managers", "")
|
||||||
|
}
|
||||||
|
func (o *Org) RemoveManagerByUsernameAndOrigin(name, origin string) error {
|
||||||
|
return o.removeRoleByUsernameAndOrigin(name, "managers", origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) RemoveAuditor(userGUID string) error {
|
||||||
|
return o.removeRole(userGUID, "auditors")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) RemoveAuditorByUsername(name string) error {
|
||||||
|
return o.removeRoleByUsernameAndOrigin(name, "auditors", "")
|
||||||
|
}
|
||||||
|
func (o *Org) RemoveAuditorByUsernameAndOrigin(name, origin string) error {
|
||||||
|
return o.removeRoleByUsernameAndOrigin(name, "auditors", origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) RemoveBillingManager(userGUID string) error {
|
||||||
|
return o.removeRole(userGUID, "billing_managers")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) RemoveBillingManagerByUsername(name string) error {
|
||||||
|
return o.removeRoleByUsernameAndOrigin(name, "billing_managers", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) RemoveBillingManagerByUsernameAndOrigin(name, origin string) error {
|
||||||
|
return o.removeRoleByUsernameAndOrigin(name, "billing_managers", origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) RemoveUser(userGUID string) error {
|
||||||
|
requestURL := fmt.Sprintf("/v2/organizations/%s/users/%s", o.Guid, userGUID)
|
||||||
|
r := o.c.NewRequest("DELETE", requestURL)
|
||||||
|
resp, err := o.c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
return errors.Wrapf(err, "Error removing user %s, response code: %d", userGUID, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) RemoveUserByUsername(name string) error {
|
||||||
|
return o.removeUserByUsernameAndOrigin(name, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) RemoveUserByUsernameAndOrigin(name, origin string) error {
|
||||||
|
return o.removeUserByUsernameAndOrigin(name, origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) removeUserByUsernameAndOrigin(name, origin string) error {
|
||||||
|
var requestURL string
|
||||||
|
var method string
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
payload := make(map[string]string)
|
||||||
|
payload["username"] = name
|
||||||
|
if origin != "" {
|
||||||
|
payload["origin"] = origin
|
||||||
|
requestURL = fmt.Sprintf("/v2/organizations/%s/users/remove", o.Guid)
|
||||||
|
method = "POST"
|
||||||
|
} else {
|
||||||
|
requestURL = fmt.Sprintf("/v2/organizations/%s/users", o.Guid)
|
||||||
|
method = "DELETE"
|
||||||
|
}
|
||||||
|
err := json.NewEncoder(buf).Encode(payload)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r := o.c.NewRequestWithBody(method, requestURL, buf)
|
||||||
|
resp, err := o.c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
return errors.Wrapf(err, "Error removing user %s, response code: %d", name, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) CreateOrg(req OrgRequest) (Org, error) {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
err := json.NewEncoder(buf).Encode(req)
|
||||||
|
if err != nil {
|
||||||
|
return Org{}, err
|
||||||
|
}
|
||||||
|
r := c.NewRequestWithBody("POST", "/v2/organizations", buf)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return Org{}, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return Org{}, errors.Wrapf(err, "Error creating organization, response code: %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return c.handleOrgResp(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) UpdateOrg(orgGUID string, orgRequest OrgRequest) (Org, error) {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
err := json.NewEncoder(buf).Encode(orgRequest)
|
||||||
|
if err != nil {
|
||||||
|
return Org{}, err
|
||||||
|
}
|
||||||
|
r := c.NewRequestWithBody("PUT", fmt.Sprintf("/v2/organizations/%s", orgGUID), buf)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return Org{}, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return Org{}, errors.Wrapf(err, "Error updating organization, response code: %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return c.handleOrgResp(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DeleteOrg(guid string, recursive, async bool) error {
|
||||||
|
resp, err := c.DoRequest(c.NewRequest("DELETE", fmt.Sprintf("/v2/organizations/%s?recursive=%t&async=%t", guid, recursive, async)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
return errors.Wrapf(err, "Error deleting organization %s, response code: %d", guid, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) getOrgResponse(requestURL string) (OrgResponse, error) {
|
||||||
|
var orgResp OrgResponse
|
||||||
|
r := c.NewRequest("GET", requestURL)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return OrgResponse{}, errors.Wrap(err, "Error requesting orgs")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return OrgResponse{}, errors.Wrap(err, "Error reading org request")
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(resBody, &orgResp)
|
||||||
|
if err != nil {
|
||||||
|
return OrgResponse{}, errors.Wrap(err, "Error unmarshalling org")
|
||||||
|
}
|
||||||
|
return orgResp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) fetchOrgs(requestURL string) ([]Org, error) {
|
||||||
|
var orgs []Org
|
||||||
|
for {
|
||||||
|
orgResp, err := c.getOrgResponse(requestURL)
|
||||||
|
if err != nil {
|
||||||
|
return []Org{}, err
|
||||||
|
}
|
||||||
|
for _, org := range orgResp.Resources {
|
||||||
|
orgs = append(orgs, c.mergeOrgResource(org))
|
||||||
|
}
|
||||||
|
requestURL = orgResp.NextUrl
|
||||||
|
if requestURL == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return orgs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) handleOrgResp(resp *http.Response) (Org, error) {
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return Org{}, err
|
||||||
|
}
|
||||||
|
var orgResource OrgResource
|
||||||
|
err = json.Unmarshal(body, &orgResource)
|
||||||
|
if err != nil {
|
||||||
|
return Org{}, err
|
||||||
|
}
|
||||||
|
return c.mergeOrgResource(orgResource), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) getOrgUserResponse(requestURL string) (OrgUserResponse, error) {
|
||||||
|
var omResp OrgUserResponse
|
||||||
|
r := c.NewRequest("GET", requestURL)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return OrgUserResponse{}, errors.Wrap(err, "error requesting org managers")
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return OrgUserResponse{}, errors.Wrap(err, "error reading org managers response body")
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(resBody, &omResp); err != nil {
|
||||||
|
return OrgUserResponse{}, errors.Wrap(err, "error unmarshaling org managers")
|
||||||
|
}
|
||||||
|
return omResp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) mergeOrgResource(org OrgResource) Org {
|
||||||
|
org.Entity.Guid = org.Meta.Guid
|
||||||
|
org.Entity.CreatedAt = org.Meta.CreatedAt
|
||||||
|
org.Entity.UpdatedAt = org.Meta.UpdatedAt
|
||||||
|
org.Entity.c = c
|
||||||
|
return org.Entity
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DefaultIsolationSegmentForOrg(orgGUID, isolationSegmentGUID string) error {
|
||||||
|
return c.updateOrgDefaultIsolationSegment(orgGUID, map[string]interface{}{"guid": isolationSegmentGUID})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ResetDefaultIsolationSegmentForOrg(orgGUID string) error {
|
||||||
|
return c.updateOrgDefaultIsolationSegment(orgGUID, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) updateOrgDefaultIsolationSegment(orgGUID string, data interface{}) error {
|
||||||
|
requestURL := fmt.Sprintf("/v3/organizations/%s/relationships/default_isolation_segment", orgGUID)
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
err := json.NewEncoder(buf).Encode(map[string]interface{}{"data": data})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r := c.NewRequestWithBody("PATCH", requestURL, buf)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return errors.Wrapf(err, "Error setting default isolation segment for org %s, response code: %d", orgGUID, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
124
vendor/github.com/cloudfoundry-community/go-cfclient/processes.go
generated
vendored
Normal file
124
vendor/github.com/cloudfoundry-community/go-cfclient/processes.go
generated
vendored
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProcessListResponse is the json body returned from the API
|
||||||
|
type ProcessListResponse struct {
|
||||||
|
Pagination Pagination `json:"pagination"`
|
||||||
|
Processes []Process `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process represents a running process in a container.
|
||||||
|
type Process struct {
|
||||||
|
GUID string `json:"guid"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Instances int `json:"instances"`
|
||||||
|
MemoryInMB int `json:"memory_in_mb"`
|
||||||
|
DiskInMB int `json:"disk_in_mb"`
|
||||||
|
Ports []int `json:"ports,omitempty"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
HealthCheck struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Data struct {
|
||||||
|
Timeout int `json:"timeout"`
|
||||||
|
InvocationTimeout int `json:"invocation_timeout"`
|
||||||
|
Endpoint string `json:"endpoint"`
|
||||||
|
} `json:"data"`
|
||||||
|
} `json:"health_check"`
|
||||||
|
Links struct {
|
||||||
|
Self Link `json:"self"`
|
||||||
|
Scale Link `json:"scale"`
|
||||||
|
App Link `json:"app"`
|
||||||
|
Space Link `json:"space"`
|
||||||
|
Stats Link `json:"stats"`
|
||||||
|
} `json:"links"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAllProcesses will call the v3 processes api
|
||||||
|
func (c *Client) ListAllProcesses() ([]Process, error) {
|
||||||
|
return c.ListAllProcessesByQuery(url.Values{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAllProcessesByQuery will call the v3 processes api
|
||||||
|
func (c *Client) ListAllProcessesByQuery(query url.Values) ([]Process, error) {
|
||||||
|
var allProcesses []Process
|
||||||
|
|
||||||
|
urlPath := "/v3/processes"
|
||||||
|
for {
|
||||||
|
resp, err := c.getProcessPage(urlPath, query)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.Pagination.TotalResults == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if allProcesses == nil {
|
||||||
|
allProcesses = make([]Process, 0, resp.Pagination.TotalResults)
|
||||||
|
}
|
||||||
|
|
||||||
|
allProcesses = append(allProcesses, resp.Processes...)
|
||||||
|
if resp.Pagination.Next == nil {
|
||||||
|
return allProcesses, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var nextURL string
|
||||||
|
|
||||||
|
if resp.Pagination.Next == nil {
|
||||||
|
return allProcesses, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch resp.Pagination.Next.(type) {
|
||||||
|
case string:
|
||||||
|
nextURL = resp.Pagination.Next.(string)
|
||||||
|
case map[string]interface{}:
|
||||||
|
m := resp.Pagination.Next.(map[string]interface{})
|
||||||
|
u, ok := m["href"]
|
||||||
|
if ok {
|
||||||
|
nextURL = u.(string)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("Unexpected type [%s] for next url", reflect.TypeOf(resp.Pagination.Next).String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if nextURL == "" {
|
||||||
|
return allProcesses, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := url.Parse(nextURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
urlPath = u.Path
|
||||||
|
query, err = url.ParseQuery(u.RawQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) getProcessPage(urlPath string, query url.Values) (*ProcessListResponse, error) {
|
||||||
|
req := c.NewRequest("GET", fmt.Sprintf("%s?%s", urlPath, query.Encode()))
|
||||||
|
|
||||||
|
resp, err := c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
procResp := new(ProcessListResponse)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
err = json.NewDecoder(resp.Body).Decode(procResp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return procResp, nil
|
||||||
|
}
|
||||||
159
vendor/github.com/cloudfoundry-community/go-cfclient/route_mappings.go
generated
vendored
Normal file
159
vendor/github.com/cloudfoundry-community/go-cfclient/route_mappings.go
generated
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RouteMappingRequest struct {
|
||||||
|
AppGUID string `json:"app_guid"`
|
||||||
|
RouteGUID string `json:"route_guid"`
|
||||||
|
AppPort int `json:"app_port"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RouteMappingResponse struct {
|
||||||
|
Count int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
NextUrl string `json:"next_url"`
|
||||||
|
Resources []RouteMappingResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RouteMapping struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
AppPort int `json:"app_port"`
|
||||||
|
AppGUID string `json:"app_guid"`
|
||||||
|
RouteGUID string `json:"route_guid"`
|
||||||
|
AppUrl string `json:"app_url"`
|
||||||
|
RouteUrl string `json:"route_url"`
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type RouteMappingResource struct {
|
||||||
|
Meta Meta `json:"metadata"`
|
||||||
|
Entity RouteMapping `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) MappingAppAndRoute(req RouteMappingRequest) (*RouteMapping, error) {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
err := json.NewEncoder(buf).Encode(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
r := c.NewRequestWithBody("POST", "/v2/route_mappings", buf)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return nil, fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return c.handleMappingResp(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListRouteMappings() ([]*RouteMapping, error) {
|
||||||
|
return c.ListRouteMappingsByQuery(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListRouteMappingsByQuery(query url.Values) ([]*RouteMapping, error) {
|
||||||
|
var routeMappings []*RouteMapping
|
||||||
|
var routeMappingsResp RouteMappingResponse
|
||||||
|
pages := 0
|
||||||
|
|
||||||
|
requestUrl := "/v2/route_mappings?" + query.Encode()
|
||||||
|
for {
|
||||||
|
r := c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error requesting route mappings")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error reading route mappings request:")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(resBody, &routeMappingsResp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error unmarshalling route mappings")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, routeMapping := range routeMappingsResp.Resources {
|
||||||
|
routeMappings = append(routeMappings, c.mergeRouteMappingResource(routeMapping))
|
||||||
|
}
|
||||||
|
requestUrl = routeMappingsResp.NextUrl
|
||||||
|
if requestUrl == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
pages++
|
||||||
|
totalPages := routeMappingsResp.Pages
|
||||||
|
if totalPages > 0 && pages >= totalPages {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return routeMappings, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetRouteMappingByGuid(guid string) (*RouteMapping, error) {
|
||||||
|
var routeMapping RouteMappingResource
|
||||||
|
requestUrl := fmt.Sprintf("/v2/route_mappings/%s", guid)
|
||||||
|
r := c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error requesting route mapping")
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error reading route mapping response body")
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(resBody, &routeMapping)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error unmarshalling route mapping")
|
||||||
|
}
|
||||||
|
routeMapping.Entity.Guid = routeMapping.Meta.Guid
|
||||||
|
routeMapping.Entity.CreatedAt = routeMapping.Meta.CreatedAt
|
||||||
|
routeMapping.Entity.UpdatedAt = routeMapping.Meta.UpdatedAt
|
||||||
|
routeMapping.Entity.c = c
|
||||||
|
return &routeMapping.Entity, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DeleteRouteMapping(guid string) error {
|
||||||
|
requestUrl := fmt.Sprintf("/v2/route_mappings/%s?", guid)
|
||||||
|
resp, err := c.DoRequest(c.NewRequest("DELETE", requestUrl))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
return errors.Wrapf(err, "Error deleting route mapping %s, response code %d", guid, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) handleMappingResp(resp *http.Response) (*RouteMapping, error) {
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var mappingResource RouteMappingResource
|
||||||
|
err = json.Unmarshal(body, &mappingResource)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c.mergeRouteMappingResource(mappingResource), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) mergeRouteMappingResource(mapping RouteMappingResource) *RouteMapping {
|
||||||
|
mapping.Entity.Guid = mapping.Meta.Guid
|
||||||
|
mapping.Entity.CreatedAt = mapping.Meta.CreatedAt
|
||||||
|
mapping.Entity.UpdatedAt = mapping.Meta.UpdatedAt
|
||||||
|
mapping.Entity.c = c
|
||||||
|
return &mapping.Entity
|
||||||
|
}
|
||||||
168
vendor/github.com/cloudfoundry-community/go-cfclient/routes.go
generated
vendored
Normal file
168
vendor/github.com/cloudfoundry-community/go-cfclient/routes.go
generated
vendored
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RoutesResponse struct {
|
||||||
|
Count int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
NextUrl string `json:"next_url"`
|
||||||
|
Resources []RoutesResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RoutesResource struct {
|
||||||
|
Meta Meta `json:"metadata"`
|
||||||
|
Entity Route `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RouteRequest struct {
|
||||||
|
DomainGuid string `json:"domain_guid"`
|
||||||
|
SpaceGuid string `json:"space_guid"`
|
||||||
|
Host string `json:"host"` // required for http routes
|
||||||
|
Path string `json:"path"`
|
||||||
|
Port int `json:"port"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Route struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
Host string `json:"host"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
DomainGuid string `json:"domain_guid"`
|
||||||
|
SpaceGuid string `json:"space_guid"`
|
||||||
|
ServiceInstanceGuid string `json:"service_instance_guid"`
|
||||||
|
Port int `json:"port"`
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateRoute creates a regular http route
|
||||||
|
func (c *Client) CreateRoute(routeRequest RouteRequest) (Route, error) {
|
||||||
|
routesResource, err := c.createRoute("/v2/routes", routeRequest)
|
||||||
|
if nil != err {
|
||||||
|
return Route{}, err
|
||||||
|
}
|
||||||
|
return c.mergeRouteResource(routesResource), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateTcpRoute creates a TCP route
|
||||||
|
func (c *Client) CreateTcpRoute(routeRequest RouteRequest) (Route, error) {
|
||||||
|
routesResource, err := c.createRoute("/v2/routes?generate_port=true", routeRequest)
|
||||||
|
if nil != err {
|
||||||
|
return Route{}, err
|
||||||
|
}
|
||||||
|
return c.mergeRouteResource(routesResource), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindRoute associates the specified route with the application
|
||||||
|
func (c *Client) BindRoute(routeGUID, appGUID string) error {
|
||||||
|
resp, err := c.DoRequest(c.NewRequest("PUT", fmt.Sprintf("/v2/routes/%s/apps/%s", routeGUID, appGUID)))
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "Error binding route %s to app %s", routeGUID, appGUID)
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return fmt.Errorf("Error binding route %s to app %s, response code: %d", routeGUID, appGUID, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListRoutesByQuery(query url.Values) ([]Route, error) {
|
||||||
|
return c.fetchRoutes("/v2/routes?" + query.Encode())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) fetchRoutes(requestUrl string) ([]Route, error) {
|
||||||
|
var routes []Route
|
||||||
|
for {
|
||||||
|
routesResp, err := c.getRoutesResponse(requestUrl)
|
||||||
|
if err != nil {
|
||||||
|
return []Route{}, err
|
||||||
|
}
|
||||||
|
for _, route := range routesResp.Resources {
|
||||||
|
route.Entity.Guid = route.Meta.Guid
|
||||||
|
route.Entity.CreatedAt = route.Meta.CreatedAt
|
||||||
|
route.Entity.UpdatedAt = route.Meta.UpdatedAt
|
||||||
|
route.Entity.c = c
|
||||||
|
routes = append(routes, route.Entity)
|
||||||
|
}
|
||||||
|
requestUrl = routesResp.NextUrl
|
||||||
|
if requestUrl == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return routes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListRoutes() ([]Route, error) {
|
||||||
|
return c.ListRoutesByQuery(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) getRoutesResponse(requestUrl string) (RoutesResponse, error) {
|
||||||
|
var routesResp RoutesResponse
|
||||||
|
r := c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return RoutesResponse{}, errors.Wrap(err, "Error requesting routes")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return RoutesResponse{}, errors.Wrap(err, "Error reading routes body")
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(resBody, &routesResp)
|
||||||
|
if err != nil {
|
||||||
|
return RoutesResponse{}, errors.Wrap(err, "Error unmarshalling routes")
|
||||||
|
}
|
||||||
|
return routesResp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) createRoute(requestUrl string, routeRequest RouteRequest) (RoutesResource, error) {
|
||||||
|
var routeResp RoutesResource
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
err := json.NewEncoder(buf).Encode(routeRequest)
|
||||||
|
if err != nil {
|
||||||
|
return RoutesResource{}, errors.Wrap(err, "Error creating route - failed to serialize request body")
|
||||||
|
}
|
||||||
|
r := c.NewRequestWithBody("POST", requestUrl, buf)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return RoutesResource{}, errors.Wrap(err, "Error creating route")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return RoutesResource{}, errors.Wrap(err, "Error creating route")
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(resBody, &routeResp)
|
||||||
|
if err != nil {
|
||||||
|
return RoutesResource{}, errors.Wrap(err, "Error unmarshalling routes")
|
||||||
|
}
|
||||||
|
routeResp.Entity.c = c
|
||||||
|
return routeResp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DeleteRoute(guid string) error {
|
||||||
|
resp, err := c.DoRequest(c.NewRequest("DELETE", fmt.Sprintf("/v2/routes/%s", guid)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
return errors.Wrapf(err, "Error deleting route %s, response code: %d", guid, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) mergeRouteResource(rr RoutesResource) Route {
|
||||||
|
rr.Entity.Guid = rr.Meta.Guid
|
||||||
|
rr.Entity.CreatedAt = rr.Meta.CreatedAt
|
||||||
|
rr.Entity.UpdatedAt = rr.Meta.UpdatedAt
|
||||||
|
rr.Entity.c = c
|
||||||
|
return rr.Entity
|
||||||
|
}
|
||||||
565
vendor/github.com/cloudfoundry-community/go-cfclient/secgroups.go
generated
vendored
Normal file
565
vendor/github.com/cloudfoundry-community/go-cfclient/secgroups.go
generated
vendored
Normal file
@@ -0,0 +1,565 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/Masterminds/semver"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SecGroupResponse struct {
|
||||||
|
Count int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
NextUrl string `json:"next_url"`
|
||||||
|
Resources []SecGroupResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SecGroupCreateResponse struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
ErrorCode string `json:"error_code"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SecGroupResource struct {
|
||||||
|
Meta Meta `json:"metadata"`
|
||||||
|
Entity SecGroup `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SecGroup struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
Rules []SecGroupRule `json:"rules"`
|
||||||
|
Running bool `json:"running_default"`
|
||||||
|
Staging bool `json:"staging_default"`
|
||||||
|
SpacesURL string `json:"spaces_url"`
|
||||||
|
StagingSpacesURL string `json:"staging_spaces_url"`
|
||||||
|
SpacesData []SpaceResource `json:"spaces"`
|
||||||
|
StagingSpacesData []SpaceResource `json:"staging_spaces"`
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type SecGroupRule struct {
|
||||||
|
Protocol string `json:"protocol"`
|
||||||
|
Ports string `json:"ports,omitempty"` //e.g. "4000-5000,9142"
|
||||||
|
Destination string `json:"destination"` //CIDR Format
|
||||||
|
Description string `json:"description,omitempty"` //Optional description
|
||||||
|
Code int `json:"code"` // ICMP code
|
||||||
|
Type int `json:"type"` //ICMP type. Only valid if Protocol=="icmp"
|
||||||
|
Log bool `json:"log,omitempty"` //If true, log this rule
|
||||||
|
}
|
||||||
|
|
||||||
|
var MinStagingSpacesVersion *semver.Version = getMinStagingSpacesVersion()
|
||||||
|
|
||||||
|
func (c *Client) ListSecGroups() (secGroups []SecGroup, err error) {
|
||||||
|
requestURL := "/v2/security_groups?inline-relations-depth=1"
|
||||||
|
for requestURL != "" {
|
||||||
|
var secGroupResp SecGroupResponse
|
||||||
|
r := c.NewRequest("GET", requestURL)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error requesting sec groups")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error reading sec group response body")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(resBody, &secGroupResp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error unmarshaling sec group")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, secGroup := range secGroupResp.Resources {
|
||||||
|
secGroup.Entity.Guid = secGroup.Meta.Guid
|
||||||
|
secGroup.Entity.CreatedAt = secGroup.Meta.CreatedAt
|
||||||
|
secGroup.Entity.UpdatedAt = secGroup.Meta.UpdatedAt
|
||||||
|
secGroup.Entity.c = c
|
||||||
|
for i, space := range secGroup.Entity.SpacesData {
|
||||||
|
space.Entity.Guid = space.Meta.Guid
|
||||||
|
secGroup.Entity.SpacesData[i] = space
|
||||||
|
}
|
||||||
|
if len(secGroup.Entity.SpacesData) == 0 {
|
||||||
|
spaces, err := secGroup.Entity.ListSpaceResources()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, space := range spaces {
|
||||||
|
secGroup.Entity.SpacesData = append(secGroup.Entity.SpacesData, space)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(secGroup.Entity.StagingSpacesData) == 0 {
|
||||||
|
spaces, err := secGroup.Entity.ListStagingSpaceResources()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, space := range spaces {
|
||||||
|
secGroup.Entity.StagingSpacesData = append(secGroup.Entity.SpacesData, space)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
secGroups = append(secGroups, secGroup.Entity)
|
||||||
|
}
|
||||||
|
|
||||||
|
requestURL = secGroupResp.NextUrl
|
||||||
|
resp.Body.Close()
|
||||||
|
}
|
||||||
|
return secGroups, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListRunningSecGroups() ([]SecGroup, error) {
|
||||||
|
secGroups := make([]SecGroup, 0)
|
||||||
|
requestURL := "/v2/config/running_security_groups"
|
||||||
|
for requestURL != "" {
|
||||||
|
var secGroupResp SecGroupResponse
|
||||||
|
r := c.NewRequest("GET", requestURL)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error requesting sec groups")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error reading sec group response body")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(resBody, &secGroupResp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error unmarshaling sec group")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, secGroup := range secGroupResp.Resources {
|
||||||
|
secGroup.Entity.Guid = secGroup.Meta.Guid
|
||||||
|
secGroup.Entity.CreatedAt = secGroup.Meta.CreatedAt
|
||||||
|
secGroup.Entity.UpdatedAt = secGroup.Meta.UpdatedAt
|
||||||
|
secGroup.Entity.c = c
|
||||||
|
|
||||||
|
secGroups = append(secGroups, secGroup.Entity)
|
||||||
|
}
|
||||||
|
|
||||||
|
requestURL = secGroupResp.NextUrl
|
||||||
|
resp.Body.Close()
|
||||||
|
}
|
||||||
|
return secGroups, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListStagingSecGroups() ([]SecGroup, error) {
|
||||||
|
secGroups := make([]SecGroup, 0)
|
||||||
|
requestURL := "/v2/config/staging_security_groups"
|
||||||
|
for requestURL != "" {
|
||||||
|
var secGroupResp SecGroupResponse
|
||||||
|
r := c.NewRequest("GET", requestURL)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error requesting sec groups")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error reading sec group response body")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(resBody, &secGroupResp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error unmarshaling sec group")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, secGroup := range secGroupResp.Resources {
|
||||||
|
secGroup.Entity.Guid = secGroup.Meta.Guid
|
||||||
|
secGroup.Entity.CreatedAt = secGroup.Meta.CreatedAt
|
||||||
|
secGroup.Entity.UpdatedAt = secGroup.Meta.UpdatedAt
|
||||||
|
secGroup.Entity.c = c
|
||||||
|
|
||||||
|
secGroups = append(secGroups, secGroup.Entity)
|
||||||
|
}
|
||||||
|
|
||||||
|
requestURL = secGroupResp.NextUrl
|
||||||
|
resp.Body.Close()
|
||||||
|
}
|
||||||
|
return secGroups, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetSecGroupByName(name string) (secGroup SecGroup, err error) {
|
||||||
|
requestURL := "/v2/security_groups?q=name:" + name
|
||||||
|
var secGroupResp SecGroupResponse
|
||||||
|
r := c.NewRequest("GET", requestURL)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return secGroup, errors.Wrap(err, "Error requesting sec groups")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return secGroup, errors.Wrap(err, "Error reading sec group response body")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(resBody, &secGroupResp)
|
||||||
|
if err != nil {
|
||||||
|
return secGroup, errors.Wrap(err, "Error unmarshaling sec group")
|
||||||
|
}
|
||||||
|
if len(secGroupResp.Resources) == 0 {
|
||||||
|
return secGroup, fmt.Errorf("No security group with name %v found", name)
|
||||||
|
}
|
||||||
|
secGroup = secGroupResp.Resources[0].Entity
|
||||||
|
secGroup.Guid = secGroupResp.Resources[0].Meta.Guid
|
||||||
|
secGroup.CreatedAt = secGroupResp.Resources[0].Meta.CreatedAt
|
||||||
|
secGroup.UpdatedAt = secGroupResp.Resources[0].Meta.UpdatedAt
|
||||||
|
secGroup.c = c
|
||||||
|
|
||||||
|
resp.Body.Close()
|
||||||
|
return secGroup, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (secGroup *SecGroup) ListSpaceResources() ([]SpaceResource, error) {
|
||||||
|
var spaceResources []SpaceResource
|
||||||
|
requestURL := secGroup.SpacesURL
|
||||||
|
for requestURL != "" {
|
||||||
|
spaceResp, err := secGroup.c.getSpaceResponse(requestURL)
|
||||||
|
if err != nil {
|
||||||
|
return []SpaceResource{}, err
|
||||||
|
}
|
||||||
|
for i, spaceRes := range spaceResp.Resources {
|
||||||
|
spaceRes.Entity.Guid = spaceRes.Meta.Guid
|
||||||
|
spaceRes.Entity.CreatedAt = spaceRes.Meta.CreatedAt
|
||||||
|
spaceRes.Entity.UpdatedAt = spaceRes.Meta.UpdatedAt
|
||||||
|
spaceResp.Resources[i] = spaceRes
|
||||||
|
}
|
||||||
|
spaceResources = append(spaceResources, spaceResp.Resources...)
|
||||||
|
requestURL = spaceResp.NextUrl
|
||||||
|
}
|
||||||
|
return spaceResources, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (secGroup *SecGroup) ListStagingSpaceResources() ([]SpaceResource, error) {
|
||||||
|
var spaceResources []SpaceResource
|
||||||
|
requestURL := secGroup.StagingSpacesURL
|
||||||
|
for requestURL != "" {
|
||||||
|
spaceResp, err := secGroup.c.getSpaceResponse(requestURL)
|
||||||
|
if err != nil {
|
||||||
|
// if this is a 404, let's make sure that it's not because we're on a legacy system
|
||||||
|
if cause := errors.Cause(err); cause != nil {
|
||||||
|
if httpErr, ok := cause.(CloudFoundryHTTPError); ok {
|
||||||
|
if httpErr.StatusCode == 404 {
|
||||||
|
info, infoErr := secGroup.c.GetInfo()
|
||||||
|
if infoErr != nil {
|
||||||
|
return nil, infoErr
|
||||||
|
}
|
||||||
|
|
||||||
|
apiVersion, versionErr := semver.NewVersion(info.APIVersion)
|
||||||
|
if versionErr != nil {
|
||||||
|
return nil, versionErr
|
||||||
|
}
|
||||||
|
|
||||||
|
if MinStagingSpacesVersion.GreaterThan(apiVersion) {
|
||||||
|
// this is probably not really an error, we're just trying to use a non-existent api
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return []SpaceResource{}, err
|
||||||
|
}
|
||||||
|
for i, spaceRes := range spaceResp.Resources {
|
||||||
|
spaceRes.Entity.Guid = spaceRes.Meta.Guid
|
||||||
|
spaceRes.Entity.CreatedAt = spaceRes.Meta.CreatedAt
|
||||||
|
spaceRes.Entity.UpdatedAt = spaceRes.Meta.UpdatedAt
|
||||||
|
spaceResp.Resources[i] = spaceRes
|
||||||
|
}
|
||||||
|
spaceResources = append(spaceResources, spaceResp.Resources...)
|
||||||
|
requestURL = spaceResp.NextUrl
|
||||||
|
}
|
||||||
|
return spaceResources, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
CreateSecGroup contacts the CF endpoint for creating a new security group.
|
||||||
|
name: the name to give to the created security group
|
||||||
|
rules: A slice of rule objects that describe the rules that this security group enforces.
|
||||||
|
This can technically be nil or an empty slice - we won't judge you
|
||||||
|
spaceGuids: The security group will be associated with the spaces specified by the contents of this slice.
|
||||||
|
If nil, the security group will not be associated with any spaces initially.
|
||||||
|
*/
|
||||||
|
func (c *Client) CreateSecGroup(name string, rules []SecGroupRule, spaceGuids []string) (*SecGroup, error) {
|
||||||
|
return c.secGroupCreateHelper("/v2/security_groups", "POST", name, rules, spaceGuids)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
UpdateSecGroup contacts the CF endpoint to update an existing security group.
|
||||||
|
guid: identifies the security group that you would like to update.
|
||||||
|
name: the new name to give to the security group
|
||||||
|
rules: A slice of rule objects that describe the rules that this security group enforces.
|
||||||
|
If this is left nil, the rules will not be changed.
|
||||||
|
spaceGuids: The security group will be associated with the spaces specified by the contents of this slice.
|
||||||
|
If nil, the space associations will not be changed.
|
||||||
|
*/
|
||||||
|
func (c *Client) UpdateSecGroup(guid, name string, rules []SecGroupRule, spaceGuids []string) (*SecGroup, error) {
|
||||||
|
return c.secGroupCreateHelper("/v2/security_groups/"+guid, "PUT", name, rules, spaceGuids)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
DeleteSecGroup contacts the CF endpoint to delete an existing security group.
|
||||||
|
guid: Indentifies the security group to be deleted.
|
||||||
|
*/
|
||||||
|
func (c *Client) DeleteSecGroup(guid string) error {
|
||||||
|
//Perform the DELETE and check for errors
|
||||||
|
resp, err := c.DoRequest(c.NewRequest("DELETE", fmt.Sprintf("/v2/security_groups/%s", guid)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != 204 { //204 No Content
|
||||||
|
return fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
GetSecGroup contacts the CF endpoint for fetching the info for a particular security group.
|
||||||
|
guid: Identifies the security group to fetch information from
|
||||||
|
*/
|
||||||
|
func (c *Client) GetSecGroup(guid string) (*SecGroup, error) {
|
||||||
|
//Perform the GET and check for errors
|
||||||
|
resp, err := c.DoRequest(c.NewRequest("GET", "/v2/security_groups/"+guid))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
|
return nil, fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
//get the json out of the response body
|
||||||
|
return respBodyToSecGroup(resp.Body, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
BindSecGroup contacts the CF endpoint to associate a space with a security group
|
||||||
|
secGUID: identifies the security group to add a space to
|
||||||
|
spaceGUID: identifies the space to associate
|
||||||
|
*/
|
||||||
|
func (c *Client) BindSecGroup(secGUID, spaceGUID string) error {
|
||||||
|
//Perform the PUT and check for errors
|
||||||
|
resp, err := c.DoRequest(c.NewRequest("PUT", fmt.Sprintf("/v2/security_groups/%s/spaces/%s", secGUID, spaceGUID)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != 201 { //201 Created
|
||||||
|
return fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
BindSpaceStagingSecGroup contacts the CF endpoint to associate a space with a security group for staging functions only
|
||||||
|
secGUID: identifies the security group to add a space to
|
||||||
|
spaceGUID: identifies the space to associate
|
||||||
|
*/
|
||||||
|
func (c *Client) BindStagingSecGroupToSpace(secGUID, spaceGUID string) error {
|
||||||
|
//Perform the PUT and check for errors
|
||||||
|
resp, err := c.DoRequest(c.NewRequest("PUT", fmt.Sprintf("/v2/security_groups/%s/staging_spaces/%s", secGUID, spaceGUID)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != 201 { //201 Created
|
||||||
|
return fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
BindRunningSecGroup contacts the CF endpoint to associate a security group
|
||||||
|
secGUID: identifies the security group to add a space to
|
||||||
|
*/
|
||||||
|
func (c *Client) BindRunningSecGroup(secGUID string) error {
|
||||||
|
//Perform the PUT and check for errors
|
||||||
|
resp, err := c.DoRequest(c.NewRequest("PUT", fmt.Sprintf("/v2/config/running_security_groups/%s", secGUID)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != 200 { //200
|
||||||
|
return fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
UnbindRunningSecGroup contacts the CF endpoint to dis-associate a security group
|
||||||
|
secGUID: identifies the security group to add a space to
|
||||||
|
*/
|
||||||
|
func (c *Client) UnbindRunningSecGroup(secGUID string) error {
|
||||||
|
//Perform the DELETE and check for errors
|
||||||
|
resp, err := c.DoRequest(c.NewRequest("DELETE", fmt.Sprintf("/v2/config/running_security_groups/%s", secGUID)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent { //204
|
||||||
|
return fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
BindStagingSecGroup contacts the CF endpoint to associate a space with a security group
|
||||||
|
secGUID: identifies the security group to add a space to
|
||||||
|
*/
|
||||||
|
func (c *Client) BindStagingSecGroup(secGUID string) error {
|
||||||
|
//Perform the PUT and check for errors
|
||||||
|
resp, err := c.DoRequest(c.NewRequest("PUT", fmt.Sprintf("/v2/config/staging_security_groups/%s", secGUID)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != 200 { //200
|
||||||
|
return fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
UnbindStagingSecGroup contacts the CF endpoint to dis-associate a space with a security group
|
||||||
|
secGUID: identifies the security group to add a space to
|
||||||
|
*/
|
||||||
|
func (c *Client) UnbindStagingSecGroup(secGUID string) error {
|
||||||
|
//Perform the DELETE and check for errors
|
||||||
|
resp, err := c.DoRequest(c.NewRequest("DELETE", fmt.Sprintf("/v2/config/staging_security_groups/%s", secGUID)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent { //204
|
||||||
|
return fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
UnbindSecGroup contacts the CF endpoint to dissociate a space from a security group
|
||||||
|
secGUID: identifies the security group to remove a space from
|
||||||
|
spaceGUID: identifies the space to dissociate from the security group
|
||||||
|
*/
|
||||||
|
func (c *Client) UnbindSecGroup(secGUID, spaceGUID string) error {
|
||||||
|
//Perform the DELETE and check for errors
|
||||||
|
resp, err := c.DoRequest(c.NewRequest("DELETE", fmt.Sprintf("/v2/security_groups/%s/spaces/%s", secGUID, spaceGUID)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != 204 { //204 No Content
|
||||||
|
return fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//Reads most security group response bodies into a SecGroup object
|
||||||
|
func respBodyToSecGroup(body io.ReadCloser, c *Client) (*SecGroup, error) {
|
||||||
|
//get the json from the response body
|
||||||
|
bodyRaw, err := ioutil.ReadAll(body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Could not read response body")
|
||||||
|
}
|
||||||
|
jStruct := SecGroupResource{}
|
||||||
|
//make it a SecGroup
|
||||||
|
err = json.Unmarshal(bodyRaw, &jStruct)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Could not unmarshal response body as json")
|
||||||
|
}
|
||||||
|
//pull a few extra fields from other places
|
||||||
|
ret := jStruct.Entity
|
||||||
|
ret.Guid = jStruct.Meta.Guid
|
||||||
|
ret.CreatedAt = jStruct.Meta.CreatedAt
|
||||||
|
ret.UpdatedAt = jStruct.Meta.UpdatedAt
|
||||||
|
ret.c = c
|
||||||
|
return &ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertStructToMap(st interface{}) map[string]interface{} {
|
||||||
|
reqRules := make(map[string]interface{})
|
||||||
|
|
||||||
|
v := reflect.ValueOf(st)
|
||||||
|
t := reflect.TypeOf(st)
|
||||||
|
|
||||||
|
for i := 0; i < v.NumField(); i++ {
|
||||||
|
key := strings.ToLower(t.Field(i).Name)
|
||||||
|
typ := v.FieldByName(t.Field(i).Name).Kind().String()
|
||||||
|
structTag := t.Field(i).Tag.Get("json")
|
||||||
|
jsonName := strings.TrimSpace(strings.Split(structTag, ",")[0])
|
||||||
|
value := v.FieldByName(t.Field(i).Name)
|
||||||
|
|
||||||
|
// if jsonName is not empty use it for the key
|
||||||
|
if jsonName != "" {
|
||||||
|
key = jsonName
|
||||||
|
}
|
||||||
|
|
||||||
|
if typ == "string" {
|
||||||
|
if !(value.String() == "" && strings.Contains(structTag, "omitempty")) {
|
||||||
|
reqRules[key] = value.String()
|
||||||
|
}
|
||||||
|
} else if typ == "int" {
|
||||||
|
reqRules[key] = value.Int()
|
||||||
|
} else {
|
||||||
|
reqRules[key] = value.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return reqRules
|
||||||
|
}
|
||||||
|
|
||||||
|
//Create and Update secGroup pretty much do the same thing, so this function abstracts those out.
|
||||||
|
func (c *Client) secGroupCreateHelper(url, method, name string, rules []SecGroupRule, spaceGuids []string) (*SecGroup, error) {
|
||||||
|
reqRules := make([]map[string]interface{}, len(rules))
|
||||||
|
|
||||||
|
for i, rule := range rules {
|
||||||
|
reqRules[i] = convertStructToMap(rule)
|
||||||
|
protocol := strings.ToLower(reqRules[i]["protocol"].(string))
|
||||||
|
|
||||||
|
// if not icmp protocol need to remove the Code/Type fields
|
||||||
|
if protocol != "icmp" {
|
||||||
|
delete(reqRules[i], "code")
|
||||||
|
delete(reqRules[i], "type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
req := c.NewRequest(method, url)
|
||||||
|
//set up request body
|
||||||
|
inputs := map[string]interface{}{
|
||||||
|
"name": name,
|
||||||
|
"rules": reqRules,
|
||||||
|
}
|
||||||
|
|
||||||
|
if spaceGuids != nil {
|
||||||
|
inputs["space_guids"] = spaceGuids
|
||||||
|
}
|
||||||
|
req.obj = inputs
|
||||||
|
//fire off the request and check for problems
|
||||||
|
resp, err := c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != 201 { // Both create and update should give 201 CREATED
|
||||||
|
var response SecGroupCreateResponse
|
||||||
|
|
||||||
|
bodyRaw, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
|
||||||
|
err = json.Unmarshal(bodyRaw, &response)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error unmarshaling response")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf(`Request failed CF API returned with status code %d
|
||||||
|
-------------------------------
|
||||||
|
Error Code %s
|
||||||
|
Code %d
|
||||||
|
Description %s`,
|
||||||
|
resp.StatusCode, response.ErrorCode, response.Code, response.Description)
|
||||||
|
}
|
||||||
|
//get the json from the response body
|
||||||
|
return respBodyToSecGroup(resp.Body, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMinStagingSpacesVersion() *semver.Version {
|
||||||
|
v, _ := semver.NewVersion("2.68.0")
|
||||||
|
return v
|
||||||
|
}
|
||||||
176
vendor/github.com/cloudfoundry-community/go-cfclient/service_bindings.go
generated
vendored
Normal file
176
vendor/github.com/cloudfoundry-community/go-cfclient/service_bindings.go
generated
vendored
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServiceBindingsResponse struct {
|
||||||
|
Count int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
Resources []ServiceBindingResource `json:"resources"`
|
||||||
|
NextUrl string `json:"next_url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceBindingResource struct {
|
||||||
|
Meta Meta `json:"metadata"`
|
||||||
|
Entity ServiceBinding `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceBinding struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
AppGuid string `json:"app_guid"`
|
||||||
|
ServiceInstanceGuid string `json:"service_instance_guid"`
|
||||||
|
Credentials interface{} `json:"credentials"`
|
||||||
|
BindingOptions interface{} `json:"binding_options"`
|
||||||
|
GatewayData interface{} `json:"gateway_data"`
|
||||||
|
GatewayName string `json:"gateway_name"`
|
||||||
|
SyslogDrainUrl string `json:"syslog_drain_url"`
|
||||||
|
VolumeMounts interface{} `json:"volume_mounts"`
|
||||||
|
AppUrl string `json:"app_url"`
|
||||||
|
ServiceInstanceUrl string `json:"service_instance_url"`
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListServiceBindingsByQuery(query url.Values) ([]ServiceBinding, error) {
|
||||||
|
var serviceBindings []ServiceBinding
|
||||||
|
requestUrl := "/v2/service_bindings?" + query.Encode()
|
||||||
|
|
||||||
|
for {
|
||||||
|
var serviceBindingsResp ServiceBindingsResponse
|
||||||
|
|
||||||
|
r := c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error requesting service bindings")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error reading service bindings request:")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(resBody, &serviceBindingsResp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error unmarshaling service bindings")
|
||||||
|
}
|
||||||
|
for _, serviceBinding := range serviceBindingsResp.Resources {
|
||||||
|
serviceBinding.Entity.Guid = serviceBinding.Meta.Guid
|
||||||
|
serviceBinding.Entity.CreatedAt = serviceBinding.Meta.CreatedAt
|
||||||
|
serviceBinding.Entity.UpdatedAt = serviceBinding.Meta.UpdatedAt
|
||||||
|
serviceBinding.Entity.c = c
|
||||||
|
serviceBindings = append(serviceBindings, serviceBinding.Entity)
|
||||||
|
}
|
||||||
|
requestUrl = serviceBindingsResp.NextUrl
|
||||||
|
if requestUrl == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return serviceBindings, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListServiceBindings() ([]ServiceBinding, error) {
|
||||||
|
return c.ListServiceBindingsByQuery(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetServiceBindingByGuid(guid string) (ServiceBinding, error) {
|
||||||
|
var serviceBinding ServiceBindingResource
|
||||||
|
r := c.NewRequest("GET", "/v2/service_bindings/"+url.QueryEscape(guid))
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return ServiceBinding{}, errors.Wrap(err, "Error requesting serving binding")
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return ServiceBinding{}, errors.Wrap(err, "Error reading service binding response body")
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(resBody, &serviceBinding)
|
||||||
|
if err != nil {
|
||||||
|
return ServiceBinding{}, errors.Wrap(err, "Error unmarshalling service binding")
|
||||||
|
}
|
||||||
|
serviceBinding.Entity.Guid = serviceBinding.Meta.Guid
|
||||||
|
serviceBinding.Entity.CreatedAt = serviceBinding.Meta.CreatedAt
|
||||||
|
serviceBinding.Entity.UpdatedAt = serviceBinding.Meta.UpdatedAt
|
||||||
|
serviceBinding.Entity.c = c
|
||||||
|
return serviceBinding.Entity, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ServiceBindingByGuid(guid string) (ServiceBinding, error) {
|
||||||
|
return c.GetServiceBindingByGuid(guid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DeleteServiceBinding(guid string) error {
|
||||||
|
resp, err := c.DoRequest(c.NewRequest("DELETE", fmt.Sprintf("/v2/service_bindings/%s", guid)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
return errors.Wrapf(err, "Error deleting service binding %s, response code %d", guid, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) CreateServiceBinding(appGUID, serviceInstanceGUID string) (*ServiceBinding, error) {
|
||||||
|
req := c.NewRequest("POST", fmt.Sprintf("/v2/service_bindings"))
|
||||||
|
req.obj = map[string]interface{}{
|
||||||
|
"app_guid": appGUID,
|
||||||
|
"service_instance_guid": serviceInstanceGUID,
|
||||||
|
}
|
||||||
|
resp, err := c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return nil, errors.Wrapf(err, "Error binding app %s to service instance %s, response code %d", appGUID, serviceInstanceGUID, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return c.handleServiceBindingResp(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) CreateRouteServiceBinding(routeGUID, serviceInstanceGUID string) error {
|
||||||
|
req := c.NewRequest("PUT", fmt.Sprintf("/v2/user_provided_service_instances/%s/routes/%s", serviceInstanceGUID, routeGUID))
|
||||||
|
resp, err := c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return errors.Wrapf(err, "Error binding route %s to service instance %s, response code %d", routeGUID, serviceInstanceGUID, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DeleteRouteServiceBinding(routeGUID, serviceInstanceGUID string) error {
|
||||||
|
req := c.NewRequest("DELETE", fmt.Sprintf("/v2/service_instances/%s/routes/%s", serviceInstanceGUID, routeGUID))
|
||||||
|
resp, err := c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return errors.Wrapf(err, "Error deleting bound route %s from service instance %s, response code %d", routeGUID, serviceInstanceGUID, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) handleServiceBindingResp(resp *http.Response) (*ServiceBinding, error) {
|
||||||
|
defer resp.Body.Close()
|
||||||
|
var sb ServiceBindingResource
|
||||||
|
err := json.NewDecoder(resp.Body).Decode(&sb)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c.mergeServiceBindingResource(sb), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) mergeServiceBindingResource(serviceBinding ServiceBindingResource) *ServiceBinding {
|
||||||
|
serviceBinding.Entity.Guid = serviceBinding.Meta.Guid
|
||||||
|
serviceBinding.Entity.c = c
|
||||||
|
return &serviceBinding.Entity
|
||||||
|
}
|
||||||
207
vendor/github.com/cloudfoundry-community/go-cfclient/service_brokers.go
generated
vendored
Normal file
207
vendor/github.com/cloudfoundry-community/go-cfclient/service_brokers.go
generated
vendored
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServiceBrokerResponse struct {
|
||||||
|
Count int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
NextUrl string `json:"next_url"`
|
||||||
|
Resources []ServiceBrokerResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceBrokerResource struct {
|
||||||
|
Meta Meta `json:"metadata"`
|
||||||
|
Entity ServiceBroker `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateServiceBrokerRequest struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
BrokerURL string `json:"broker_url"`
|
||||||
|
Username string `json:"auth_username"`
|
||||||
|
Password string `json:"auth_password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateServiceBrokerRequest struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
BrokerURL string `json:"broker_url"`
|
||||||
|
Username string `json:"auth_username"`
|
||||||
|
Password string `json:"auth_password"`
|
||||||
|
SpaceGUID string `json:"space_guid,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceBroker struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
BrokerURL string `json:"broker_url"`
|
||||||
|
Username string `json:"auth_username"`
|
||||||
|
Password string `json:"auth_password"`
|
||||||
|
SpaceGUID string `json:"space_guid,omitempty"`
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DeleteServiceBroker(guid string) error {
|
||||||
|
requestUrl := fmt.Sprintf("/v2/service_brokers/%s", guid)
|
||||||
|
r := c.NewRequest("DELETE", requestUrl)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
return errors.Wrapf(err, "Error deleteing service broker %s, response code: %d", guid, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) UpdateServiceBroker(guid string, usb UpdateServiceBrokerRequest) (ServiceBroker, error) {
|
||||||
|
var serviceBrokerResource ServiceBrokerResource
|
||||||
|
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
err := json.NewEncoder(buf).Encode(usb)
|
||||||
|
if err != nil {
|
||||||
|
return ServiceBroker{}, err
|
||||||
|
}
|
||||||
|
req := c.NewRequestWithBody("PUT", fmt.Sprintf("/v2/service_brokers/%s", guid), buf)
|
||||||
|
resp, err := c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return ServiceBroker{}, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return ServiceBroker{}, fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return ServiceBroker{}, err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(body, &serviceBrokerResource)
|
||||||
|
if err != nil {
|
||||||
|
return ServiceBroker{}, err
|
||||||
|
}
|
||||||
|
serviceBrokerResource.Entity.Guid = serviceBrokerResource.Meta.Guid
|
||||||
|
return serviceBrokerResource.Entity, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) CreateServiceBroker(csb CreateServiceBrokerRequest) (ServiceBroker, error) {
|
||||||
|
var serviceBrokerResource ServiceBrokerResource
|
||||||
|
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
err := json.NewEncoder(buf).Encode(csb)
|
||||||
|
if err != nil {
|
||||||
|
return ServiceBroker{}, err
|
||||||
|
}
|
||||||
|
req := c.NewRequestWithBody("POST", "/v2/service_brokers", buf)
|
||||||
|
resp, err := c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return ServiceBroker{}, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return ServiceBroker{}, fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return ServiceBroker{}, err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(body, &serviceBrokerResource)
|
||||||
|
if err != nil {
|
||||||
|
return ServiceBroker{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
serviceBrokerResource.Entity.Guid = serviceBrokerResource.Meta.Guid
|
||||||
|
return serviceBrokerResource.Entity, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListServiceBrokersByQuery(query url.Values) ([]ServiceBroker, error) {
|
||||||
|
var sbs []ServiceBroker
|
||||||
|
requestUrl := "/v2/service_brokers?" + query.Encode()
|
||||||
|
for {
|
||||||
|
serviceBrokerResp, err := c.getServiceBrokerResponse(requestUrl)
|
||||||
|
if err != nil {
|
||||||
|
return []ServiceBroker{}, err
|
||||||
|
}
|
||||||
|
for _, sb := range serviceBrokerResp.Resources {
|
||||||
|
sb.Entity.Guid = sb.Meta.Guid
|
||||||
|
sb.Entity.CreatedAt = sb.Meta.CreatedAt
|
||||||
|
sb.Entity.UpdatedAt = sb.Meta.UpdatedAt
|
||||||
|
sbs = append(sbs, sb.Entity)
|
||||||
|
}
|
||||||
|
requestUrl = serviceBrokerResp.NextUrl
|
||||||
|
if requestUrl == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sbs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListServiceBrokers() ([]ServiceBroker, error) {
|
||||||
|
return c.ListServiceBrokersByQuery(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetServiceBrokerByGuid(guid string) (ServiceBroker, error) {
|
||||||
|
var serviceBrokerRes ServiceBrokerResource
|
||||||
|
r := c.NewRequest("GET", "/v2/service_brokers/"+guid)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return ServiceBroker{}, err
|
||||||
|
}
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return ServiceBroker{}, err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(body, &serviceBrokerRes)
|
||||||
|
if err != nil {
|
||||||
|
return ServiceBroker{}, err
|
||||||
|
}
|
||||||
|
serviceBrokerRes.Entity.Guid = serviceBrokerRes.Meta.Guid
|
||||||
|
serviceBrokerRes.Entity.CreatedAt = serviceBrokerRes.Meta.CreatedAt
|
||||||
|
serviceBrokerRes.Entity.UpdatedAt = serviceBrokerRes.Meta.UpdatedAt
|
||||||
|
return serviceBrokerRes.Entity, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetServiceBrokerByName(name string) (ServiceBroker, error) {
|
||||||
|
var sb ServiceBroker
|
||||||
|
q := url.Values{}
|
||||||
|
q.Set("q", "name:"+name)
|
||||||
|
sbs, err := c.ListServiceBrokersByQuery(q)
|
||||||
|
if err != nil {
|
||||||
|
return sb, err
|
||||||
|
}
|
||||||
|
if len(sbs) == 0 {
|
||||||
|
return sb, fmt.Errorf("Unable to find service broker %s", name)
|
||||||
|
}
|
||||||
|
return sbs[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) getServiceBrokerResponse(requestUrl string) (ServiceBrokerResponse, error) {
|
||||||
|
var serviceBrokerResp ServiceBrokerResponse
|
||||||
|
r := c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return ServiceBrokerResponse{}, errors.Wrap(err, "Error requesting Service Brokers")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return ServiceBrokerResponse{}, errors.Wrap(err, "Error reading Service Broker request")
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(resBody, &serviceBrokerResp)
|
||||||
|
if err != nil {
|
||||||
|
return ServiceBrokerResponse{}, errors.Wrap(err, "Error unmarshalling Service Broker")
|
||||||
|
}
|
||||||
|
return serviceBrokerResp, nil
|
||||||
|
}
|
||||||
186
vendor/github.com/cloudfoundry-community/go-cfclient/service_instances.go
generated
vendored
Normal file
186
vendor/github.com/cloudfoundry-community/go-cfclient/service_instances.go
generated
vendored
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServiceInstancesResponse struct {
|
||||||
|
Count int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
NextUrl string `json:"next_url"`
|
||||||
|
Resources []ServiceInstanceResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceInstanceRequest struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
SpaceGuid string `json:"space_guid"`
|
||||||
|
ServicePlanGuid string `json:"service_plan_guid"`
|
||||||
|
Parameters map[string]interface{} `json:"parameters,omitempty"`
|
||||||
|
Tags []string `json:"tags,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceInstanceResource struct {
|
||||||
|
Meta Meta `json:"metadata"`
|
||||||
|
Entity ServiceInstance `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceInstance struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
Credentials map[string]interface{} `json:"credentials"`
|
||||||
|
ServicePlanGuid string `json:"service_plan_guid"`
|
||||||
|
SpaceGuid string `json:"space_guid"`
|
||||||
|
DashboardUrl string `json:"dashboard_url"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
LastOperation LastOperation `json:"last_operation"`
|
||||||
|
Tags []string `json:"tags"`
|
||||||
|
ServiceGuid string `json:"service_guid"`
|
||||||
|
SpaceUrl string `json:"space_url"`
|
||||||
|
ServicePlanUrl string `json:"service_plan_url"`
|
||||||
|
ServiceBindingsUrl string `json:"service_bindings_url"`
|
||||||
|
ServiceKeysUrl string `json:"service_keys_url"`
|
||||||
|
RoutesUrl string `json:"routes_url"`
|
||||||
|
ServiceUrl string `json:"service_url"`
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type LastOperation struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
State string `json:"state"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListServiceInstancesByQuery(query url.Values) ([]ServiceInstance, error) {
|
||||||
|
var instances []ServiceInstance
|
||||||
|
|
||||||
|
requestUrl := "/v2/service_instances?" + query.Encode()
|
||||||
|
for {
|
||||||
|
var sir ServiceInstancesResponse
|
||||||
|
r := c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error requesting service instances")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error reading service instances request:")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(resBody, &sir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error unmarshaling service instances")
|
||||||
|
}
|
||||||
|
for _, instance := range sir.Resources {
|
||||||
|
instances = append(instances, c.mergeServiceInstance(instance))
|
||||||
|
}
|
||||||
|
|
||||||
|
requestUrl = sir.NextUrl
|
||||||
|
if requestUrl == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return instances, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListServiceInstances() ([]ServiceInstance, error) {
|
||||||
|
return c.ListServiceInstancesByQuery(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetServiceInstanceByGuid(guid string) (ServiceInstance, error) {
|
||||||
|
var sir ServiceInstanceResource
|
||||||
|
req := c.NewRequest("GET", "/v2/service_instances/"+guid)
|
||||||
|
res, err := c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return ServiceInstance{}, errors.Wrap(err, "Error requesting service instance")
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return ServiceInstance{}, errors.Wrap(err, "Error reading service instance response")
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(data, &sir)
|
||||||
|
if err != nil {
|
||||||
|
return ServiceInstance{}, errors.Wrap(err, "Error JSON parsing service instance response")
|
||||||
|
}
|
||||||
|
return c.mergeServiceInstance(sir), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ServiceInstanceByGuid(guid string) (ServiceInstance, error) {
|
||||||
|
return c.GetServiceInstanceByGuid(guid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) mergeServiceInstance(instance ServiceInstanceResource) ServiceInstance {
|
||||||
|
instance.Entity.Guid = instance.Meta.Guid
|
||||||
|
instance.Entity.CreatedAt = instance.Meta.CreatedAt
|
||||||
|
instance.Entity.UpdatedAt = instance.Meta.UpdatedAt
|
||||||
|
instance.Entity.c = c
|
||||||
|
return instance.Entity
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) CreateServiceInstance(req ServiceInstanceRequest) (ServiceInstance, error) {
|
||||||
|
var sir ServiceInstanceResource
|
||||||
|
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
err := json.NewEncoder(buf).Encode(req)
|
||||||
|
if err != nil {
|
||||||
|
return ServiceInstance{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
r := c.NewRequestWithBody("POST", "/v2/service_instances?accepts_incomplete=true", buf)
|
||||||
|
|
||||||
|
res, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return ServiceInstance{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.StatusCode != http.StatusAccepted && res.StatusCode != http.StatusCreated {
|
||||||
|
return ServiceInstance{}, errors.Wrapf(err, "Error creating service, response code: %d", res.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return ServiceInstance{}, errors.Wrap(err, "Error reading service instance response")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(data, &sir)
|
||||||
|
if err != nil {
|
||||||
|
return ServiceInstance{}, errors.Wrap(err, "Error JSON parsing service instance response")
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.mergeServiceInstance(sir), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) UpdateServiceInstance(serviceInstanceGuid string, updatedConfiguration io.Reader, async bool) error {
|
||||||
|
u := fmt.Sprintf("/v2/service_instances/%s?accepts_incomplete=%t", serviceInstanceGuid, async)
|
||||||
|
resp, err := c.DoRequest(c.NewRequestWithBody("PUT", u, updatedConfiguration))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusAccepted {
|
||||||
|
return errors.Wrapf(err, "Error updating service instance %s, response code %d", serviceInstanceGuid, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DeleteServiceInstance(guid string, recursive, async bool) error {
|
||||||
|
resp, err := c.DoRequest(c.NewRequest("DELETE", fmt.Sprintf("/v2/service_instances/%s?recursive=%t&accepts_incomplete=%t&async=%t", guid, recursive, async, async)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusAccepted {
|
||||||
|
return errors.Wrapf(err, "Error deleting service instance %s, response code %d", guid, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
171
vendor/github.com/cloudfoundry-community/go-cfclient/service_keys.go
generated
vendored
Normal file
171
vendor/github.com/cloudfoundry-community/go-cfclient/service_keys.go
generated
vendored
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServiceKeysResponse struct {
|
||||||
|
Count int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
Resources []ServiceKeyResource `json:"resources"`
|
||||||
|
NextUrl string `json:"next_url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceKeyResource struct {
|
||||||
|
Meta Meta `json:"metadata"`
|
||||||
|
Entity ServiceKey `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateServiceKeyRequest struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
ServiceInstanceGuid string `json:"service_instance_guid"`
|
||||||
|
Parameters interface{} `json:"parameters,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceKey struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
ServiceInstanceGuid string `json:"service_instance_guid"`
|
||||||
|
Credentials interface{} `json:"credentials"`
|
||||||
|
ServiceInstanceUrl string `json:"service_instance_url"`
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListServiceKeysByQuery(query url.Values) ([]ServiceKey, error) {
|
||||||
|
var serviceKeys []ServiceKey
|
||||||
|
requestUrl := "/v2/service_keys?" + query.Encode()
|
||||||
|
|
||||||
|
for {
|
||||||
|
var serviceKeysResp ServiceKeysResponse
|
||||||
|
|
||||||
|
r := c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error requesting service keys")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error reading service keys request:")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(resBody, &serviceKeysResp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Error unmarshaling service keys: %q", string(resBody))
|
||||||
|
}
|
||||||
|
for _, serviceKey := range serviceKeysResp.Resources {
|
||||||
|
serviceKey.Entity.Guid = serviceKey.Meta.Guid
|
||||||
|
serviceKey.Entity.CreatedAt = serviceKey.Meta.CreatedAt
|
||||||
|
serviceKey.Entity.UpdatedAt = serviceKey.Meta.UpdatedAt
|
||||||
|
serviceKey.Entity.c = c
|
||||||
|
serviceKeys = append(serviceKeys, serviceKey.Entity)
|
||||||
|
}
|
||||||
|
|
||||||
|
requestUrl = serviceKeysResp.NextUrl
|
||||||
|
if requestUrl == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return serviceKeys, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListServiceKeys() ([]ServiceKey, error) {
|
||||||
|
return c.ListServiceKeysByQuery(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetServiceKeyByName(name string) (ServiceKey, error) {
|
||||||
|
var serviceKey ServiceKey
|
||||||
|
q := url.Values{}
|
||||||
|
q.Set("q", "name:"+name)
|
||||||
|
serviceKeys, err := c.ListServiceKeysByQuery(q)
|
||||||
|
if err != nil {
|
||||||
|
return serviceKey, err
|
||||||
|
}
|
||||||
|
if len(serviceKeys) == 0 {
|
||||||
|
return serviceKey, fmt.Errorf("Unable to find service key %s", name)
|
||||||
|
}
|
||||||
|
return serviceKeys[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetServiceKeyByInstanceGuid is deprecated in favor of GetServiceKeysByInstanceGuid
|
||||||
|
func (c *Client) GetServiceKeyByInstanceGuid(guid string) (ServiceKey, error) {
|
||||||
|
var serviceKey ServiceKey
|
||||||
|
q := url.Values{}
|
||||||
|
q.Set("q", "service_instance_guid:"+guid)
|
||||||
|
serviceKeys, err := c.ListServiceKeysByQuery(q)
|
||||||
|
if err != nil {
|
||||||
|
return serviceKey, err
|
||||||
|
}
|
||||||
|
if len(serviceKeys) == 0 {
|
||||||
|
return serviceKey, fmt.Errorf("Unable to find service key for guid %s", guid)
|
||||||
|
}
|
||||||
|
return serviceKeys[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetServiceKeysByInstanceGuid returns the service keys for a service instance.
|
||||||
|
// If none are found, it returns an error.
|
||||||
|
func (c *Client) GetServiceKeysByInstanceGuid(guid string) ([]ServiceKey, error) {
|
||||||
|
q := url.Values{}
|
||||||
|
q.Set("q", "service_instance_guid:"+guid)
|
||||||
|
serviceKeys, err := c.ListServiceKeysByQuery(q)
|
||||||
|
if err != nil {
|
||||||
|
return serviceKeys, err
|
||||||
|
}
|
||||||
|
if len(serviceKeys) == 0 {
|
||||||
|
return serviceKeys, fmt.Errorf("Unable to find service key for guid %s", guid)
|
||||||
|
}
|
||||||
|
return serviceKeys, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateServiceKey creates a service key from the request. If a service key
|
||||||
|
// exists already, it returns an error containing `CF-ServiceKeyNameTaken`
|
||||||
|
func (c *Client) CreateServiceKey(csr CreateServiceKeyRequest) (ServiceKey, error) {
|
||||||
|
var serviceKeyResource ServiceKeyResource
|
||||||
|
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
err := json.NewEncoder(buf).Encode(csr)
|
||||||
|
if err != nil {
|
||||||
|
return ServiceKey{}, err
|
||||||
|
}
|
||||||
|
req := c.NewRequestWithBody("POST", "/v2/service_keys", buf)
|
||||||
|
resp, err := c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return ServiceKey{}, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return ServiceKey{}, fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return ServiceKey{}, err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(body, &serviceKeyResource)
|
||||||
|
if err != nil {
|
||||||
|
return ServiceKey{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return serviceKeyResource.Entity, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteServiceKey removes a service key instance
|
||||||
|
func (c *Client) DeleteServiceKey(guid string) error {
|
||||||
|
resp, err := c.DoRequest(c.NewRequest("DELETE", fmt.Sprintf("/v2/service_keys/%s", guid)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
return errors.Wrapf(err, "Error deleting service instance key %s, response code %d", guid, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
169
vendor/github.com/cloudfoundry-community/go-cfclient/service_plan_visibilities.go
generated
vendored
Normal file
169
vendor/github.com/cloudfoundry-community/go-cfclient/service_plan_visibilities.go
generated
vendored
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServicePlanVisibilitiesResponse struct {
|
||||||
|
Count int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
NextUrl string `json:"next_url"`
|
||||||
|
Resources []ServicePlanVisibilityResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServicePlanVisibilityResource struct {
|
||||||
|
Meta Meta `json:"metadata"`
|
||||||
|
Entity ServicePlanVisibility `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServicePlanVisibility struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
ServicePlanGuid string `json:"service_plan_guid"`
|
||||||
|
OrganizationGuid string `json:"organization_guid"`
|
||||||
|
ServicePlanUrl string `json:"service_plan_url"`
|
||||||
|
OrganizationUrl string `json:"organization_url"`
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListServicePlanVisibilitiesByQuery(query url.Values) ([]ServicePlanVisibility, error) {
|
||||||
|
var servicePlanVisibilities []ServicePlanVisibility
|
||||||
|
requestUrl := "/v2/service_plan_visibilities?" + query.Encode()
|
||||||
|
for {
|
||||||
|
var servicePlanVisibilitiesResp ServicePlanVisibilitiesResponse
|
||||||
|
r := c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error requesting service plan visibilities")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error reading service plan visibilities request:")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(resBody, &servicePlanVisibilitiesResp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error unmarshaling service plan visibilities")
|
||||||
|
}
|
||||||
|
for _, servicePlanVisibility := range servicePlanVisibilitiesResp.Resources {
|
||||||
|
servicePlanVisibility.Entity.Guid = servicePlanVisibility.Meta.Guid
|
||||||
|
servicePlanVisibility.Entity.CreatedAt = servicePlanVisibility.Meta.CreatedAt
|
||||||
|
servicePlanVisibility.Entity.UpdatedAt = servicePlanVisibility.Meta.UpdatedAt
|
||||||
|
servicePlanVisibility.Entity.c = c
|
||||||
|
servicePlanVisibilities = append(servicePlanVisibilities, servicePlanVisibility.Entity)
|
||||||
|
}
|
||||||
|
requestUrl = servicePlanVisibilitiesResp.NextUrl
|
||||||
|
if requestUrl == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return servicePlanVisibilities, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListServicePlanVisibilities() ([]ServicePlanVisibility, error) {
|
||||||
|
return c.ListServicePlanVisibilitiesByQuery(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetServicePlanVisibilityByGuid(guid string) (ServicePlanVisibility, error) {
|
||||||
|
r := c.NewRequest("GET", "/v2/service_plan_visibilities/"+guid)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return ServicePlanVisibility{}, err
|
||||||
|
}
|
||||||
|
return respBodyToServicePlanVisibility(resp.Body, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
//a uniqueID is the id of the service in the catalog and not in cf internal db
|
||||||
|
func (c *Client) CreateServicePlanVisibilityByUniqueId(uniqueId string, organizationGuid string) (ServicePlanVisibility, error) {
|
||||||
|
q := url.Values{}
|
||||||
|
q.Set("q", fmt.Sprintf("unique_id:%s", uniqueId))
|
||||||
|
plans, err := c.ListServicePlansByQuery(q)
|
||||||
|
if err != nil {
|
||||||
|
return ServicePlanVisibility{}, errors.Wrap(err, fmt.Sprintf("Couldn't find a service plan with unique_id: %s", uniqueId))
|
||||||
|
}
|
||||||
|
return c.CreateServicePlanVisibility(plans[0].Guid, organizationGuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) CreateServicePlanVisibility(servicePlanGuid string, organizationGuid string) (ServicePlanVisibility, error) {
|
||||||
|
req := c.NewRequest("POST", "/v2/service_plan_visibilities")
|
||||||
|
req.obj = map[string]interface{}{
|
||||||
|
"service_plan_guid": servicePlanGuid,
|
||||||
|
"organization_guid": organizationGuid,
|
||||||
|
}
|
||||||
|
resp, err := c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return ServicePlanVisibility{}, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return ServicePlanVisibility{}, errors.Wrapf(err, "Error creating service plan visibility, response code: %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return respBodyToServicePlanVisibility(resp.Body, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DeleteServicePlanVisibilityByPlanAndOrg(servicePlanGuid string, organizationGuid string, async bool) error {
|
||||||
|
q := url.Values{}
|
||||||
|
q.Set("q", fmt.Sprintf("organization_guid:%s;service_plan_guid:%s", organizationGuid, servicePlanGuid))
|
||||||
|
plans, err := c.ListServicePlanVisibilitiesByQuery(q)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, fmt.Sprintf("Couldn't find a service plan visibility for service plan %s and org %s", servicePlanGuid, organizationGuid))
|
||||||
|
}
|
||||||
|
if len(plans) != 1 {
|
||||||
|
return fmt.Errorf("Query for a service plan visibility did not return exactly one result when searching for a service plan visibility for service plan %s and org %s",
|
||||||
|
servicePlanGuid, organizationGuid)
|
||||||
|
}
|
||||||
|
return c.DeleteServicePlanVisibility(plans[0].Guid, async)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DeleteServicePlanVisibility(guid string, async bool) error {
|
||||||
|
req := c.NewRequest("DELETE", fmt.Sprintf("/v2/service_plan_visibilities/%s?async=%v", guid, async))
|
||||||
|
resp, err := c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
return errors.Wrapf(err, "Error deleting service plan visibility, response code: %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) UpdateServicePlanVisibility(guid string, servicePlanGuid string, organizationGuid string) (ServicePlanVisibility, error) {
|
||||||
|
req := c.NewRequest("PUT", "/v2/service_plan_visibilities/"+guid)
|
||||||
|
req.obj = map[string]interface{}{
|
||||||
|
"service_plan_guid": servicePlanGuid,
|
||||||
|
"organization_guid": organizationGuid,
|
||||||
|
}
|
||||||
|
resp, err := c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return ServicePlanVisibility{}, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return ServicePlanVisibility{}, errors.Wrapf(err, "Error updating service plan visibility, response code: %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return respBodyToServicePlanVisibility(resp.Body, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func respBodyToServicePlanVisibility(body io.ReadCloser, c *Client) (ServicePlanVisibility, error) {
|
||||||
|
bodyRaw, err := ioutil.ReadAll(body)
|
||||||
|
if err != nil {
|
||||||
|
return ServicePlanVisibility{}, err
|
||||||
|
}
|
||||||
|
servicePlanVisibilityRes := ServicePlanVisibilityResource{}
|
||||||
|
err = json.Unmarshal(bodyRaw, &servicePlanVisibilityRes)
|
||||||
|
if err != nil {
|
||||||
|
return ServicePlanVisibility{}, err
|
||||||
|
}
|
||||||
|
servicePlanVisibility := servicePlanVisibilityRes.Entity
|
||||||
|
servicePlanVisibility.Guid = servicePlanVisibilityRes.Meta.Guid
|
||||||
|
servicePlanVisibility.CreatedAt = servicePlanVisibilityRes.Meta.CreatedAt
|
||||||
|
servicePlanVisibility.UpdatedAt = servicePlanVisibilityRes.Meta.UpdatedAt
|
||||||
|
servicePlanVisibility.c = c
|
||||||
|
return servicePlanVisibility, nil
|
||||||
|
}
|
||||||
129
vendor/github.com/cloudfoundry-community/go-cfclient/service_plans.go
generated
vendored
Normal file
129
vendor/github.com/cloudfoundry-community/go-cfclient/service_plans.go
generated
vendored
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServicePlansResponse struct {
|
||||||
|
Count int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
NextUrl string `json:"next_url"`
|
||||||
|
Resources []ServicePlanResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServicePlanResource struct {
|
||||||
|
Meta Meta `json:"metadata"`
|
||||||
|
Entity ServicePlan `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServicePlan struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
Free bool `json:"free"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
ServiceGuid string `json:"service_guid"`
|
||||||
|
Extra interface{} `json:"extra"`
|
||||||
|
UniqueId string `json:"unique_id"`
|
||||||
|
Public bool `json:"public"`
|
||||||
|
Active bool `json:"active"`
|
||||||
|
Bindable bool `json:"bindable"`
|
||||||
|
ServiceUrl string `json:"service_url"`
|
||||||
|
ServiceInstancesUrl string `json:"service_instances_url"`
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListServicePlansByQuery(query url.Values) ([]ServicePlan, error) {
|
||||||
|
var servicePlans []ServicePlan
|
||||||
|
requestUrl := "/v2/service_plans?" + query.Encode()
|
||||||
|
for {
|
||||||
|
var servicePlansResp ServicePlansResponse
|
||||||
|
r := c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error requesting service plans")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error reading service plans request:")
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(resBody, &servicePlansResp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error unmarshaling service plans")
|
||||||
|
}
|
||||||
|
for _, servicePlan := range servicePlansResp.Resources {
|
||||||
|
servicePlan.Entity.Guid = servicePlan.Meta.Guid
|
||||||
|
servicePlan.Entity.CreatedAt = servicePlan.Meta.CreatedAt
|
||||||
|
servicePlan.Entity.UpdatedAt = servicePlan.Meta.UpdatedAt
|
||||||
|
servicePlan.Entity.c = c
|
||||||
|
servicePlans = append(servicePlans, servicePlan.Entity)
|
||||||
|
}
|
||||||
|
requestUrl = servicePlansResp.NextUrl
|
||||||
|
if requestUrl == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return servicePlans, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListServicePlans() ([]ServicePlan, error) {
|
||||||
|
return c.ListServicePlansByQuery(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetServicePlanByGUID(guid string) (*ServicePlan, error) {
|
||||||
|
var (
|
||||||
|
plan *ServicePlan
|
||||||
|
planResponse ServicePlanResource
|
||||||
|
)
|
||||||
|
|
||||||
|
r := c.NewRequest("GET", "/v2/service_plans/"+guid)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(body, &planResponse)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
planResponse.Entity.Guid = planResponse.Meta.Guid
|
||||||
|
planResponse.Entity.CreatedAt = planResponse.Meta.CreatedAt
|
||||||
|
planResponse.Entity.UpdatedAt = planResponse.Meta.UpdatedAt
|
||||||
|
plan = &planResponse.Entity
|
||||||
|
|
||||||
|
return plan, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) MakeServicePlanPublic(servicePlanGUID string) error {
|
||||||
|
return c.setPlanGlobalVisibility(servicePlanGUID, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) MakeServicePlanPrivate(servicePlanGUID string) error {
|
||||||
|
return c.setPlanGlobalVisibility(servicePlanGUID, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) setPlanGlobalVisibility(servicePlanGUID string, public bool) error {
|
||||||
|
bodyString := fmt.Sprintf(`{"public": %t}`, public)
|
||||||
|
req := c.NewRequestWithBody("PUT", fmt.Sprintf("/v2/service_plans/%s", servicePlanGUID), bytes.NewBufferString(bodyString))
|
||||||
|
|
||||||
|
resp, err := c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
72
vendor/github.com/cloudfoundry-community/go-cfclient/service_usage_events.go
generated
vendored
Normal file
72
vendor/github.com/cloudfoundry-community/go-cfclient/service_usage_events.go
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServiceUsageEvent struct {
|
||||||
|
GUID string `json:"guid"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
State string `json:"state"`
|
||||||
|
OrgGUID string `json:"org_guid"`
|
||||||
|
SpaceGUID string `json:"space_guid"`
|
||||||
|
SpaceName string `json:"space_name"`
|
||||||
|
ServiceInstanceGUID string `json:"service_instance_guid"`
|
||||||
|
ServiceInstanceName string `json:"service_instance_name"`
|
||||||
|
ServiceInstanceType string `json:"service_instance_type"`
|
||||||
|
ServicePlanGUID string `json:"service_plan_guid"`
|
||||||
|
ServicePlanName string `json:"service_plan_name"`
|
||||||
|
ServiceGUID string `json:"service_guid"`
|
||||||
|
ServiceLabel string `json:"service_label"`
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceUsageEventsResponse struct {
|
||||||
|
TotalResults int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
NextURL string `json:"next_url"`
|
||||||
|
Resources []ServiceUsageEventResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceUsageEventResource struct {
|
||||||
|
Meta Meta `json:"metadata"`
|
||||||
|
Entity ServiceUsageEvent `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListServiceUsageEventsByQuery lists all events matching the provided query.
|
||||||
|
func (c *Client) ListServiceUsageEventsByQuery(query url.Values) ([]ServiceUsageEvent, error) {
|
||||||
|
var serviceUsageEvents []ServiceUsageEvent
|
||||||
|
requestURL := fmt.Sprintf("/v2/service_usage_events?%s", query.Encode())
|
||||||
|
for {
|
||||||
|
var serviceUsageEventsResponse ServiceUsageEventsResponse
|
||||||
|
r := c.NewRequest("GET", requestURL)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "error requesting events")
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&serviceUsageEventsResponse); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "error unmarshaling events")
|
||||||
|
}
|
||||||
|
for _, e := range serviceUsageEventsResponse.Resources {
|
||||||
|
e.Entity.GUID = e.Meta.Guid
|
||||||
|
e.Entity.CreatedAt = e.Meta.CreatedAt
|
||||||
|
e.Entity.c = c
|
||||||
|
serviceUsageEvents = append(serviceUsageEvents, e.Entity)
|
||||||
|
}
|
||||||
|
requestURL = serviceUsageEventsResponse.NextURL
|
||||||
|
if requestURL == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return serviceUsageEvents, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListServiceUsageEvents lists all unfiltered events.
|
||||||
|
func (c *Client) ListServiceUsageEvents() ([]ServiceUsageEvent, error) {
|
||||||
|
return c.ListServiceUsageEventsByQuery(nil)
|
||||||
|
}
|
||||||
107
vendor/github.com/cloudfoundry-community/go-cfclient/services.go
generated
vendored
Normal file
107
vendor/github.com/cloudfoundry-community/go-cfclient/services.go
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServicesResponse struct {
|
||||||
|
Count int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
NextUrl string `json:"next_url"`
|
||||||
|
Resources []ServicesResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServicesResource struct {
|
||||||
|
Meta Meta `json:"metadata"`
|
||||||
|
Entity Service `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
Label string `json:"label"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Active bool `json:"active"`
|
||||||
|
Bindable bool `json:"bindable"`
|
||||||
|
ServiceBrokerGuid string `json:"service_broker_guid"`
|
||||||
|
PlanUpdateable bool `json:"plan_updateable"`
|
||||||
|
Tags []string `json:"tags"`
|
||||||
|
UniqueID string `json:"unique_id"`
|
||||||
|
Extra string `json:"extra"`
|
||||||
|
Requires []string `json:"requires"`
|
||||||
|
InstancesRetrievable bool `json:"instances_retrievable"`
|
||||||
|
BindingsRetrievable bool `json:"bindings_retrievable"`
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceSummary struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
BoundAppCount int `json:"bound_app_count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetServiceByGuid(guid string) (Service, error) {
|
||||||
|
var serviceRes ServicesResource
|
||||||
|
r := c.NewRequest("GET", "/v2/services/"+guid)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return Service{}, err
|
||||||
|
}
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return Service{}, err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(body, &serviceRes)
|
||||||
|
if err != nil {
|
||||||
|
return Service{}, err
|
||||||
|
}
|
||||||
|
serviceRes.Entity.Guid = serviceRes.Meta.Guid
|
||||||
|
serviceRes.Entity.CreatedAt = serviceRes.Meta.CreatedAt
|
||||||
|
serviceRes.Entity.UpdatedAt = serviceRes.Meta.UpdatedAt
|
||||||
|
return serviceRes.Entity, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListServicesByQuery(query url.Values) ([]Service, error) {
|
||||||
|
var services []Service
|
||||||
|
requestUrl := "/v2/services?" + query.Encode()
|
||||||
|
for {
|
||||||
|
var serviceResp ServicesResponse
|
||||||
|
r := c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error requesting services")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error reading services request:")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(resBody, &serviceResp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error unmarshaling services")
|
||||||
|
}
|
||||||
|
for _, service := range serviceResp.Resources {
|
||||||
|
service.Entity.Guid = service.Meta.Guid
|
||||||
|
service.Entity.CreatedAt = service.Meta.CreatedAt
|
||||||
|
service.Entity.UpdatedAt = service.Meta.UpdatedAt
|
||||||
|
service.Entity.c = c
|
||||||
|
services = append(services, service.Entity)
|
||||||
|
}
|
||||||
|
requestUrl = serviceResp.NextUrl
|
||||||
|
if requestUrl == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return services, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListServices() ([]Service, error) {
|
||||||
|
return c.ListServicesByQuery(nil)
|
||||||
|
}
|
||||||
183
vendor/github.com/cloudfoundry-community/go-cfclient/space_quotas.go
generated
vendored
Normal file
183
vendor/github.com/cloudfoundry-community/go-cfclient/space_quotas.go
generated
vendored
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SpaceQuotasResponse struct {
|
||||||
|
Count int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
NextUrl string `json:"next_url"`
|
||||||
|
Resources []SpaceQuotasResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SpaceQuotasResource struct {
|
||||||
|
Meta Meta `json:"metadata"`
|
||||||
|
Entity SpaceQuota `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SpaceQuotaRequest struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
OrganizationGuid string `json:"organization_guid"`
|
||||||
|
NonBasicServicesAllowed bool `json:"non_basic_services_allowed"`
|
||||||
|
TotalServices int `json:"total_services"`
|
||||||
|
TotalRoutes int `json:"total_routes"`
|
||||||
|
MemoryLimit int `json:"memory_limit"`
|
||||||
|
InstanceMemoryLimit int `json:"instance_memory_limit"`
|
||||||
|
AppInstanceLimit int `json:"app_instance_limit"`
|
||||||
|
AppTaskLimit int `json:"app_task_limit"`
|
||||||
|
TotalServiceKeys int `json:"total_service_keys"`
|
||||||
|
TotalReservedRoutePorts int `json:"total_reserved_route_ports"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SpaceQuota struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
CreatedAt string `json:"created_at,omitempty"`
|
||||||
|
UpdatedAt string `json:"updated_at,omitempty"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
OrganizationGuid string `json:"organization_guid"`
|
||||||
|
NonBasicServicesAllowed bool `json:"non_basic_services_allowed"`
|
||||||
|
TotalServices int `json:"total_services"`
|
||||||
|
TotalRoutes int `json:"total_routes"`
|
||||||
|
MemoryLimit int `json:"memory_limit"`
|
||||||
|
InstanceMemoryLimit int `json:"instance_memory_limit"`
|
||||||
|
AppInstanceLimit int `json:"app_instance_limit"`
|
||||||
|
AppTaskLimit int `json:"app_task_limit"`
|
||||||
|
TotalServiceKeys int `json:"total_service_keys"`
|
||||||
|
TotalReservedRoutePorts int `json:"total_reserved_route_ports"`
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListSpaceQuotasByQuery(query url.Values) ([]SpaceQuota, error) {
|
||||||
|
var spaceQuotas []SpaceQuota
|
||||||
|
requestUrl := "/v2/space_quota_definitions?" + query.Encode()
|
||||||
|
for {
|
||||||
|
spaceQuotasResp, err := c.getSpaceQuotasResponse(requestUrl)
|
||||||
|
if err != nil {
|
||||||
|
return []SpaceQuota{}, err
|
||||||
|
}
|
||||||
|
for _, space := range spaceQuotasResp.Resources {
|
||||||
|
space.Entity.Guid = space.Meta.Guid
|
||||||
|
space.Entity.CreatedAt = space.Meta.CreatedAt
|
||||||
|
space.Entity.UpdatedAt = space.Meta.UpdatedAt
|
||||||
|
space.Entity.c = c
|
||||||
|
spaceQuotas = append(spaceQuotas, space.Entity)
|
||||||
|
}
|
||||||
|
requestUrl = spaceQuotasResp.NextUrl
|
||||||
|
if requestUrl == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return spaceQuotas, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListSpaceQuotas() ([]SpaceQuota, error) {
|
||||||
|
return c.ListSpaceQuotasByQuery(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetSpaceQuotaByName(name string) (SpaceQuota, error) {
|
||||||
|
q := url.Values{}
|
||||||
|
q.Set("q", "name:"+name)
|
||||||
|
spaceQuotas, err := c.ListSpaceQuotasByQuery(q)
|
||||||
|
if err != nil {
|
||||||
|
return SpaceQuota{}, err
|
||||||
|
}
|
||||||
|
if len(spaceQuotas) != 1 {
|
||||||
|
return SpaceQuota{}, fmt.Errorf("Unable to find space quota " + name)
|
||||||
|
}
|
||||||
|
return spaceQuotas[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) getSpaceQuotasResponse(requestUrl string) (SpaceQuotasResponse, error) {
|
||||||
|
var spaceQuotasResp SpaceQuotasResponse
|
||||||
|
r := c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return SpaceQuotasResponse{}, errors.Wrap(err, "Error requesting space quotas")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return SpaceQuotasResponse{}, errors.Wrap(err, "Error reading space quotas body")
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(resBody, &spaceQuotasResp)
|
||||||
|
if err != nil {
|
||||||
|
return SpaceQuotasResponse{}, errors.Wrap(err, "Error unmarshalling space quotas")
|
||||||
|
}
|
||||||
|
return spaceQuotasResp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AssignSpaceQuota(quotaGUID, spaceGUID string) error {
|
||||||
|
//Perform the PUT and check for errors
|
||||||
|
resp, err := c.DoRequest(c.NewRequest("PUT", fmt.Sprintf("/v2/space_quota_definitions/%s/spaces/%s", quotaGUID, spaceGUID)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated { //201
|
||||||
|
return fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) CreateSpaceQuota(spaceQuote SpaceQuotaRequest) (*SpaceQuota, error) {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
err := json.NewEncoder(buf).Encode(spaceQuote)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
r := c.NewRequestWithBody("POST", "/v2/space_quota_definitions", buf)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return nil, fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return c.handleSpaceQuotaResp(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) UpdateSpaceQuota(spaceQuotaGUID string, spaceQuote SpaceQuotaRequest) (*SpaceQuota, error) {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
err := json.NewEncoder(buf).Encode(spaceQuote)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
r := c.NewRequestWithBody("PUT", fmt.Sprintf("/v2/space_quota_definitions/%s", spaceQuotaGUID), buf)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return nil, fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return c.handleSpaceQuotaResp(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) handleSpaceQuotaResp(resp *http.Response) (*SpaceQuota, error) {
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var spaceQuotasResource SpaceQuotasResource
|
||||||
|
err = json.Unmarshal(body, &spaceQuotasResource)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c.mergeSpaceQuotaResource(spaceQuotasResource), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) mergeSpaceQuotaResource(spaceQuote SpaceQuotasResource) *SpaceQuota {
|
||||||
|
spaceQuote.Entity.Guid = spaceQuote.Meta.Guid
|
||||||
|
spaceQuote.Entity.CreatedAt = spaceQuote.Meta.CreatedAt
|
||||||
|
spaceQuote.Entity.UpdatedAt = spaceQuote.Meta.UpdatedAt
|
||||||
|
spaceQuote.Entity.c = c
|
||||||
|
return &spaceQuote.Entity
|
||||||
|
}
|
||||||
790
vendor/github.com/cloudfoundry-community/go-cfclient/spaces.go
generated
vendored
Normal file
790
vendor/github.com/cloudfoundry-community/go-cfclient/spaces.go
generated
vendored
Normal file
@@ -0,0 +1,790 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SpaceRequest struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
OrganizationGuid string `json:"organization_guid"`
|
||||||
|
DeveloperGuid []string `json:"developer_guids,omitempty"`
|
||||||
|
ManagerGuid []string `json:"manager_guids,omitempty"`
|
||||||
|
AuditorGuid []string `json:"auditor_guids,omitempty"`
|
||||||
|
DomainGuid []string `json:"domain_guids,omitempty"`
|
||||||
|
SecurityGroupGuids []string `json:"security_group_guids,omitempty"`
|
||||||
|
SpaceQuotaDefGuid string `json:"space_quota_definition_guid,omitempty"`
|
||||||
|
IsolationSegmentGuid string `json:"isolation_segment_guid,omitempty"`
|
||||||
|
AllowSSH bool `json:"allow_ssh"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SpaceResponse struct {
|
||||||
|
Count int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
NextUrl string `json:"next_url"`
|
||||||
|
Resources []SpaceResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SpaceResource struct {
|
||||||
|
Meta Meta `json:"metadata"`
|
||||||
|
Entity Space `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServicePlanEntity struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Free bool `json:"free"`
|
||||||
|
Public bool `json:"public"`
|
||||||
|
Active bool `json:"active"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
ServiceOfferingGUID string `json:"service_guid"`
|
||||||
|
ServiceOffering ServiceOfferingResource `json:"service"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceOfferingExtra struct {
|
||||||
|
DisplayName string `json:"displayName"`
|
||||||
|
DocumentationURL string `json:"documentationURL"`
|
||||||
|
LongDescription string `json:"longDescription"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceOfferingEntity struct {
|
||||||
|
Label string
|
||||||
|
Description string
|
||||||
|
Provider string `json:"provider"`
|
||||||
|
BrokerGUID string `json:"service_broker_guid"`
|
||||||
|
Requires []string `json:"requires"`
|
||||||
|
ServicePlans []interface{} `json:"service_plans"`
|
||||||
|
Extra ServiceOfferingExtra
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceOfferingResource struct {
|
||||||
|
Metadata Meta
|
||||||
|
Entity ServiceOfferingEntity
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceOfferingResponse struct {
|
||||||
|
Count int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
NextUrl string `json:"next_url"`
|
||||||
|
PrevUrl string `json:"prev_url"`
|
||||||
|
Resources []ServiceOfferingResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SpaceUserResponse struct {
|
||||||
|
Count int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
NextURL string `json:"next_url"`
|
||||||
|
Resources []UserResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Space struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
OrganizationGuid string `json:"organization_guid"`
|
||||||
|
OrgURL string `json:"organization_url"`
|
||||||
|
OrgData OrgResource `json:"organization"`
|
||||||
|
QuotaDefinitionGuid string `json:"space_quota_definition_guid"`
|
||||||
|
IsolationSegmentGuid string `json:"isolation_segment_guid"`
|
||||||
|
AllowSSH bool `json:"allow_ssh"`
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type SpaceSummary struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Apps []AppSummary `json:"apps"`
|
||||||
|
Services []ServiceSummary `json:"services"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SpaceRoleResponse struct {
|
||||||
|
Count int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
NextUrl string `json:"next_url"`
|
||||||
|
Resources []SpaceRoleResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SpaceRoleResource struct {
|
||||||
|
Meta Meta `json:"metadata"`
|
||||||
|
Entity SpaceRole `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SpaceRole struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
Admin bool `json:"admin"`
|
||||||
|
Active bool `json:"active"`
|
||||||
|
DefaultSpaceGuid string `json:"default_space_guid"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
SpaceRoles []string `json:"space_roles"`
|
||||||
|
SpacesUrl string `json:"spaces_url"`
|
||||||
|
OrganizationsUrl string `json:"organizations_url"`
|
||||||
|
ManagedOrganizationsUrl string `json:"managed_organizations_url"`
|
||||||
|
BillingManagedOrganizationsUrl string `json:"billing_managed_organizations_url"`
|
||||||
|
AuditedOrganizationsUrl string `json:"audited_organizations_url"`
|
||||||
|
ManagedSpacesUrl string `json:"managed_spaces_url"`
|
||||||
|
AuditedSpacesUrl string `json:"audited_spaces_url"`
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) Org() (Org, error) {
|
||||||
|
var orgResource OrgResource
|
||||||
|
r := s.c.NewRequest("GET", s.OrgURL)
|
||||||
|
resp, err := s.c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return Org{}, errors.Wrap(err, "Error requesting org")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return Org{}, errors.Wrap(err, "Error reading org request")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(resBody, &orgResource)
|
||||||
|
if err != nil {
|
||||||
|
return Org{}, errors.Wrap(err, "Error unmarshaling org")
|
||||||
|
}
|
||||||
|
return s.c.mergeOrgResource(orgResource), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) Quota() (*SpaceQuota, error) {
|
||||||
|
var spaceQuota *SpaceQuota
|
||||||
|
var spaceQuotaResource SpaceQuotasResource
|
||||||
|
if s.QuotaDefinitionGuid == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
requestUrl := fmt.Sprintf("/v2/space_quota_definitions/%s", s.QuotaDefinitionGuid)
|
||||||
|
r := s.c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := s.c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return &SpaceQuota{}, errors.Wrap(err, "Error requesting space quota")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return &SpaceQuota{}, errors.Wrap(err, "Error reading space quota body")
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(resBody, &spaceQuotaResource)
|
||||||
|
if err != nil {
|
||||||
|
return &SpaceQuota{}, errors.Wrap(err, "Error unmarshalling space quota")
|
||||||
|
}
|
||||||
|
spaceQuota = &spaceQuotaResource.Entity
|
||||||
|
spaceQuota.Guid = spaceQuotaResource.Meta.Guid
|
||||||
|
spaceQuota.c = s.c
|
||||||
|
return spaceQuota, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) Summary() (SpaceSummary, error) {
|
||||||
|
var spaceSummary SpaceSummary
|
||||||
|
requestUrl := fmt.Sprintf("/v2/spaces/%s/summary", s.Guid)
|
||||||
|
r := s.c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := s.c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return SpaceSummary{}, errors.Wrap(err, "Error requesting space summary")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return SpaceSummary{}, errors.Wrap(err, "Error reading space summary body")
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(resBody, &spaceSummary)
|
||||||
|
if err != nil {
|
||||||
|
return SpaceSummary{}, errors.Wrap(err, "Error unmarshalling space summary")
|
||||||
|
}
|
||||||
|
return spaceSummary, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) Roles() ([]SpaceRole, error) {
|
||||||
|
var roles []SpaceRole
|
||||||
|
requestUrl := fmt.Sprintf("/v2/spaces/%s/user_roles", s.Guid)
|
||||||
|
for {
|
||||||
|
rolesResp, err := s.c.getSpaceRolesResponse(requestUrl)
|
||||||
|
if err != nil {
|
||||||
|
return roles, err
|
||||||
|
}
|
||||||
|
for _, role := range rolesResp.Resources {
|
||||||
|
role.Entity.Guid = role.Meta.Guid
|
||||||
|
role.Entity.c = s.c
|
||||||
|
roles = append(roles, role.Entity)
|
||||||
|
}
|
||||||
|
requestUrl = rolesResp.NextUrl
|
||||||
|
if requestUrl == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return roles, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) CreateSpace(req SpaceRequest) (Space, error) {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
err := json.NewEncoder(buf).Encode(req)
|
||||||
|
if err != nil {
|
||||||
|
return Space{}, err
|
||||||
|
}
|
||||||
|
r := c.NewRequestWithBody("POST", "/v2/spaces", buf)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return Space{}, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return Space{}, fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return c.handleSpaceResp(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) UpdateSpace(spaceGUID string, req SpaceRequest) (Space, error) {
|
||||||
|
space := Space{Guid: spaceGUID, c: c}
|
||||||
|
return space.Update(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DeleteSpace(guid string, recursive, async bool) error {
|
||||||
|
resp, err := c.DoRequest(c.NewRequest("DELETE", fmt.Sprintf("/v2/spaces/%s?recursive=%t&async=%t", guid, recursive, async)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
return errors.Wrapf(err, "Error deleting space %s, response code: %d", guid, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListSpaceManagersByQuery(spaceGUID string, query url.Values) ([]User, error) {
|
||||||
|
return c.listSpaceUsersByRoleAndQuery(spaceGUID, "managers", query)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListSpaceManagers(spaceGUID string) ([]User, error) {
|
||||||
|
return c.ListSpaceManagersByQuery(spaceGUID, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListSpaceAuditorsByQuery(spaceGUID string, query url.Values) ([]User, error) {
|
||||||
|
return c.listSpaceUsersByRoleAndQuery(spaceGUID, "auditors", query)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListSpaceAuditors(spaceGUID string) ([]User, error) {
|
||||||
|
return c.ListSpaceAuditorsByQuery(spaceGUID, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListSpaceDevelopersByQuery(spaceGUID string, query url.Values) ([]User, error) {
|
||||||
|
return c.listSpaceUsersByRoleAndQuery(spaceGUID, "developers", query)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) listSpaceUsersByRoleAndQuery(spaceGUID, role string, query url.Values) ([]User, error) {
|
||||||
|
var users []User
|
||||||
|
requestURL := fmt.Sprintf("/v2/spaces/%s/%s?%s", spaceGUID, role, query.Encode())
|
||||||
|
for {
|
||||||
|
userResp, err := c.getUserResponse(requestURL)
|
||||||
|
if err != nil {
|
||||||
|
return []User{}, err
|
||||||
|
}
|
||||||
|
for _, u := range userResp.Resources {
|
||||||
|
users = append(users, c.mergeUserResource(u))
|
||||||
|
}
|
||||||
|
requestURL = userResp.NextUrl
|
||||||
|
if requestURL == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return users, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListSpaceDevelopers(spaceGUID string) ([]User, error) {
|
||||||
|
return c.ListSpaceDevelopersByQuery(spaceGUID, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AssociateSpaceDeveloper(spaceGUID, userGUID string) (Space, error) {
|
||||||
|
space := Space{Guid: spaceGUID, c: c}
|
||||||
|
return space.AssociateDeveloper(userGUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AssociateSpaceDeveloperByUsername(spaceGUID, name string) (Space, error) {
|
||||||
|
space := Space{Guid: spaceGUID, c: c}
|
||||||
|
return space.AssociateDeveloperByUsername(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AssociateSpaceDeveloperByUsernameAndOrigin(spaceGUID, name, origin string) (Space, error) {
|
||||||
|
space := Space{Guid: spaceGUID, c: c}
|
||||||
|
return space.AssociateDeveloperByUsernameAndOrigin(name, origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RemoveSpaceDeveloper(spaceGUID, userGUID string) error {
|
||||||
|
space := Space{Guid: spaceGUID, c: c}
|
||||||
|
return space.RemoveDeveloper(userGUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RemoveSpaceDeveloperByUsername(spaceGUID, name string) error {
|
||||||
|
space := Space{Guid: spaceGUID, c: c}
|
||||||
|
return space.RemoveDeveloperByUsername(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RemoveSpaceDeveloperByUsernameAndOrigin(spaceGUID, name, origin string) error {
|
||||||
|
space := Space{Guid: spaceGUID, c: c}
|
||||||
|
return space.RemoveDeveloperByUsernameAndOrigin(name, origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AssociateSpaceAuditor(spaceGUID, userGUID string) (Space, error) {
|
||||||
|
space := Space{Guid: spaceGUID, c: c}
|
||||||
|
return space.AssociateAuditor(userGUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AssociateSpaceAuditorByUsername(spaceGUID, name string) (Space, error) {
|
||||||
|
space := Space{Guid: spaceGUID, c: c}
|
||||||
|
return space.AssociateAuditorByUsername(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AssociateSpaceAuditorByUsernameAndOrigin(spaceGUID, name, origin string) (Space, error) {
|
||||||
|
space := Space{Guid: spaceGUID, c: c}
|
||||||
|
return space.AssociateAuditorByUsernameAndOrigin(name, origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RemoveSpaceAuditor(spaceGUID, userGUID string) error {
|
||||||
|
space := Space{Guid: spaceGUID, c: c}
|
||||||
|
return space.RemoveAuditor(userGUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RemoveSpaceAuditorByUsername(spaceGUID, name string) error {
|
||||||
|
space := Space{Guid: spaceGUID, c: c}
|
||||||
|
return space.RemoveAuditorByUsername(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RemoveSpaceAuditorByUsernameAndOrigin(spaceGUID, name, origin string) error {
|
||||||
|
space := Space{Guid: spaceGUID, c: c}
|
||||||
|
return space.RemoveAuditorByUsernameAndOrigin(name, origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AssociateSpaceManager(spaceGUID, userGUID string) (Space, error) {
|
||||||
|
space := Space{Guid: spaceGUID, c: c}
|
||||||
|
return space.AssociateManager(userGUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AssociateSpaceManagerByUsername(spaceGUID, name string) (Space, error) {
|
||||||
|
space := Space{Guid: spaceGUID, c: c}
|
||||||
|
return space.AssociateManagerByUsername(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AssociateSpaceManagerByUsernameAndOrigin(spaceGUID, name, origin string) (Space, error) {
|
||||||
|
space := Space{Guid: spaceGUID, c: c}
|
||||||
|
return space.AssociateManagerByUsernameAndOrigin(name, origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RemoveSpaceManager(spaceGUID, userGUID string) error {
|
||||||
|
space := Space{Guid: spaceGUID, c: c}
|
||||||
|
return space.RemoveManager(userGUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RemoveSpaceManagerByUsername(spaceGUID, name string) error {
|
||||||
|
space := Space{Guid: spaceGUID, c: c}
|
||||||
|
return space.RemoveManagerByUsername(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RemoveSpaceManagerByUsernameAndOrigin(spaceGUID, name, origin string) error {
|
||||||
|
space := Space{Guid: spaceGUID, c: c}
|
||||||
|
return space.RemoveManagerByUsernameAndOrigin(name, origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) AssociateDeveloper(userGUID string) (Space, error) {
|
||||||
|
return s.associateRole(userGUID, "developers")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) AssociateDeveloperByUsername(name string) (Space, error) {
|
||||||
|
return s.associateUserByRole(name, "developers", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) AssociateDeveloperByUsernameAndOrigin(name, origin string) (Space, error) {
|
||||||
|
return s.associateUserByRole(name, "developers", origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) RemoveDeveloper(userGUID string) error {
|
||||||
|
return s.removeRole(userGUID, "developers")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) RemoveDeveloperByUsername(name string) error {
|
||||||
|
return s.removeUserByRole(name, "developers", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) RemoveDeveloperByUsernameAndOrigin(name, origin string) error {
|
||||||
|
return s.removeUserByRole(name, "developers", origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) AssociateAuditor(userGUID string) (Space, error) {
|
||||||
|
return s.associateRole(userGUID, "auditors")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) AssociateAuditorByUsername(name string) (Space, error) {
|
||||||
|
return s.associateUserByRole(name, "auditors", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) AssociateAuditorByUsernameAndOrigin(name, origin string) (Space, error) {
|
||||||
|
return s.associateUserByRole(name, "auditors", origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) RemoveAuditor(userGUID string) error {
|
||||||
|
return s.removeRole(userGUID, "auditors")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) RemoveAuditorByUsername(name string) error {
|
||||||
|
return s.removeUserByRole(name, "auditors", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) RemoveAuditorByUsernameAndOrigin(name, origin string) error {
|
||||||
|
return s.removeUserByRole(name, "auditors", origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) AssociateManager(userGUID string) (Space, error) {
|
||||||
|
return s.associateRole(userGUID, "managers")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) AssociateManagerByUsername(name string) (Space, error) {
|
||||||
|
return s.associateUserByRole(name, "managers", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) AssociateManagerByUsernameAndOrigin(name, origin string) (Space, error) {
|
||||||
|
return s.associateUserByRole(name, "managers", origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) RemoveManager(userGUID string) error {
|
||||||
|
return s.removeRole(userGUID, "managers")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) RemoveManagerByUsername(name string) error {
|
||||||
|
return s.removeUserByRole(name, "managers", "")
|
||||||
|
}
|
||||||
|
func (s *Space) RemoveManagerByUsernameAndOrigin(name, origin string) error {
|
||||||
|
return s.removeUserByRole(name, "managers", origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) associateRole(userGUID, role string) (Space, error) {
|
||||||
|
requestUrl := fmt.Sprintf("/v2/spaces/%s/%s/%s", s.Guid, role, userGUID)
|
||||||
|
r := s.c.NewRequest("PUT", requestUrl)
|
||||||
|
resp, err := s.c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return Space{}, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return Space{}, errors.Wrapf(err, "Error associating %s %s, response code: %d", role, userGUID, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return s.c.handleSpaceResp(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) associateUserByRole(name, role, origin string) (Space, error) {
|
||||||
|
requestUrl := fmt.Sprintf("/v2/spaces/%s/%s", s.Guid, role)
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
payload := make(map[string]string)
|
||||||
|
payload["username"] = name
|
||||||
|
if origin != "" {
|
||||||
|
payload["origin"] = origin
|
||||||
|
}
|
||||||
|
err := json.NewEncoder(buf).Encode(payload)
|
||||||
|
if err != nil {
|
||||||
|
return Space{}, err
|
||||||
|
}
|
||||||
|
r := s.c.NewRequestWithBody("PUT", requestUrl, buf)
|
||||||
|
resp, err := s.c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return Space{}, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return Space{}, errors.Wrapf(err, "Error associating %s %s, response code: %d", role, name, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return s.c.handleSpaceResp(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) removeRole(userGUID, role string) error {
|
||||||
|
requestUrl := fmt.Sprintf("/v2/spaces/%s/%s/%s", s.Guid, role, userGUID)
|
||||||
|
r := s.c.NewRequest("DELETE", requestUrl)
|
||||||
|
resp, err := s.c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
return errors.Wrapf(err, "Error removing %s %s, response code: %d", role, userGUID, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) removeUserByRole(name, role, origin string) error {
|
||||||
|
var requestURL string
|
||||||
|
var method string
|
||||||
|
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
payload := make(map[string]string)
|
||||||
|
payload["username"] = name
|
||||||
|
if origin != "" {
|
||||||
|
payload["origin"] = origin
|
||||||
|
requestURL = fmt.Sprintf("/v2/spaces/%s/%s/remove", s.Guid, role)
|
||||||
|
method = "POST"
|
||||||
|
} else {
|
||||||
|
requestURL = fmt.Sprintf("/v2/spaces/%s/%s", s.Guid, role)
|
||||||
|
method = "DELETE"
|
||||||
|
}
|
||||||
|
err := json.NewEncoder(buf).Encode(payload)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r := s.c.NewRequestWithBody(method, requestURL, buf)
|
||||||
|
resp, err := s.c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return errors.Wrapf(err, "Error removing %s %s, response code: %d", role, name, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListSpaceSecGroups(spaceGUID string) (secGroups []SecGroup, err error) {
|
||||||
|
space := Space{Guid: spaceGUID, c: c}
|
||||||
|
return space.ListSecGroups()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) ListSecGroups() (secGroups []SecGroup, err error) {
|
||||||
|
requestURL := fmt.Sprintf("/v2/spaces/%s/security_groups?inline-relations-depth=1", s.Guid)
|
||||||
|
for requestURL != "" {
|
||||||
|
var secGroupResp SecGroupResponse
|
||||||
|
r := s.c.NewRequest("GET", requestURL)
|
||||||
|
resp, err := s.c.DoRequest(r)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error requesting sec groups")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error reading sec group response body")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(resBody, &secGroupResp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error unmarshaling sec group")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, secGroup := range secGroupResp.Resources {
|
||||||
|
secGroup.Entity.Guid = secGroup.Meta.Guid
|
||||||
|
secGroup.Entity.c = s.c
|
||||||
|
for i, space := range secGroup.Entity.SpacesData {
|
||||||
|
space.Entity.Guid = space.Meta.Guid
|
||||||
|
secGroup.Entity.SpacesData[i] = space
|
||||||
|
}
|
||||||
|
if len(secGroup.Entity.SpacesData) == 0 {
|
||||||
|
spaces, err := secGroup.Entity.ListSpaceResources()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, space := range spaces {
|
||||||
|
secGroup.Entity.SpacesData = append(secGroup.Entity.SpacesData, space)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
secGroups = append(secGroups, secGroup.Entity)
|
||||||
|
}
|
||||||
|
|
||||||
|
requestURL = secGroupResp.NextUrl
|
||||||
|
resp.Body.Close()
|
||||||
|
}
|
||||||
|
return secGroups, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) GetServiceOfferings() (ServiceOfferingResponse, error) {
|
||||||
|
var response ServiceOfferingResponse
|
||||||
|
requestURL := fmt.Sprintf("/v2/spaces/%s/services", s.Guid)
|
||||||
|
req := s.c.NewRequest("GET", requestURL)
|
||||||
|
|
||||||
|
resp, err := s.c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return ServiceOfferingResponse{}, errors.Wrap(err, "Error requesting service offerings")
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return ServiceOfferingResponse{}, errors.Wrap(err, "Error reading service offering response")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(body, &response)
|
||||||
|
if err != nil {
|
||||||
|
return ServiceOfferingResponse{}, errors.Wrap(err, "Error unmarshalling service offering response")
|
||||||
|
}
|
||||||
|
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Space) Update(req SpaceRequest) (Space, error) {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
err := json.NewEncoder(buf).Encode(req)
|
||||||
|
if err != nil {
|
||||||
|
return Space{}, err
|
||||||
|
}
|
||||||
|
r := s.c.NewRequestWithBody("PUT", fmt.Sprintf("/v2/spaces/%s", s.Guid), buf)
|
||||||
|
resp, err := s.c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return Space{}, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return Space{}, fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return s.c.handleSpaceResp(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListSpacesByQuery(query url.Values) ([]Space, error) {
|
||||||
|
return c.fetchSpaces("/v2/spaces?" + query.Encode())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListSpaces() ([]Space, error) {
|
||||||
|
return c.ListSpacesByQuery(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) fetchSpaces(requestUrl string) ([]Space, error) {
|
||||||
|
var spaces []Space
|
||||||
|
for {
|
||||||
|
spaceResp, err := c.getSpaceResponse(requestUrl)
|
||||||
|
if err != nil {
|
||||||
|
return []Space{}, err
|
||||||
|
}
|
||||||
|
for _, space := range spaceResp.Resources {
|
||||||
|
spaces = append(spaces, c.mergeSpaceResource(space))
|
||||||
|
}
|
||||||
|
requestUrl = spaceResp.NextUrl
|
||||||
|
if requestUrl == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return spaces, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetSpaceByName(spaceName string, orgGuid string) (space Space, err error) {
|
||||||
|
query := url.Values{}
|
||||||
|
query.Add("q", fmt.Sprintf("organization_guid:%s", orgGuid))
|
||||||
|
query.Add("q", fmt.Sprintf("name:%s", spaceName))
|
||||||
|
spaces, err := c.ListSpacesByQuery(query)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(spaces) == 0 {
|
||||||
|
return space, fmt.Errorf("No space found with name: `%s` in org with GUID: `%s`", spaceName, orgGuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
return spaces[0], nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetSpaceByGuid(spaceGUID string) (Space, error) {
|
||||||
|
requestUrl := fmt.Sprintf("/v2/spaces/%s", spaceGUID)
|
||||||
|
r := c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return Space{}, errors.Wrap(err, "Error requesting space info")
|
||||||
|
}
|
||||||
|
return c.handleSpaceResp(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) getSpaceResponse(requestUrl string) (SpaceResponse, error) {
|
||||||
|
var spaceResp SpaceResponse
|
||||||
|
r := c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return SpaceResponse{}, errors.Wrap(err, "Error requesting spaces")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return SpaceResponse{}, errors.Wrap(err, "Error reading space request")
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(resBody, &spaceResp)
|
||||||
|
if err != nil {
|
||||||
|
return SpaceResponse{}, errors.Wrap(err, "Error unmarshalling space")
|
||||||
|
}
|
||||||
|
return spaceResp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) getSpaceRolesResponse(requestUrl string) (SpaceRoleResponse, error) {
|
||||||
|
var roleResp SpaceRoleResponse
|
||||||
|
r := c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return roleResp, errors.Wrap(err, "Error requesting space roles")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return roleResp, errors.Wrap(err, "Error reading space roles request")
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(resBody, &roleResp)
|
||||||
|
if err != nil {
|
||||||
|
return roleResp, errors.Wrap(err, "Error unmarshalling space roles")
|
||||||
|
}
|
||||||
|
return roleResp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) handleSpaceResp(resp *http.Response) (Space, error) {
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return Space{}, err
|
||||||
|
}
|
||||||
|
var spaceResource SpaceResource
|
||||||
|
err = json.Unmarshal(body, &spaceResource)
|
||||||
|
if err != nil {
|
||||||
|
return Space{}, err
|
||||||
|
}
|
||||||
|
return c.mergeSpaceResource(spaceResource), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) mergeSpaceResource(space SpaceResource) Space {
|
||||||
|
space.Entity.Guid = space.Meta.Guid
|
||||||
|
space.Entity.CreatedAt = space.Meta.CreatedAt
|
||||||
|
space.Entity.UpdatedAt = space.Meta.UpdatedAt
|
||||||
|
space.Entity.c = c
|
||||||
|
return space.Entity
|
||||||
|
}
|
||||||
|
|
||||||
|
type serviceOfferingExtra ServiceOfferingExtra
|
||||||
|
|
||||||
|
func (resource *ServiceOfferingExtra) UnmarshalJSON(rawData []byte) error {
|
||||||
|
if string(rawData) == "null" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
extra := serviceOfferingExtra{}
|
||||||
|
|
||||||
|
unquoted, err := strconv.Unquote(string(rawData))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(unquoted), &extra)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*resource = ServiceOfferingExtra(extra)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) IsolationSegmentForSpace(spaceGUID, isolationSegmentGUID string) error {
|
||||||
|
return c.updateSpaceIsolationSegment(spaceGUID, map[string]interface{}{"guid": isolationSegmentGUID})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ResetIsolationSegmentForSpace(spaceGUID string) error {
|
||||||
|
return c.updateSpaceIsolationSegment(spaceGUID, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) updateSpaceIsolationSegment(spaceGUID string, data interface{}) error {
|
||||||
|
requestURL := fmt.Sprintf("/v3/spaces/%s/relationships/isolation_segment", spaceGUID)
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
err := json.NewEncoder(buf).Encode(map[string]interface{}{"data": data})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r := c.NewRequestWithBody("PATCH", requestURL, buf)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return errors.Wrapf(err, "Error setting isolation segment for space %s, response code: %d", spaceGUID, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
76
vendor/github.com/cloudfoundry-community/go-cfclient/stacks.go
generated
vendored
Normal file
76
vendor/github.com/cloudfoundry-community/go-cfclient/stacks.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StacksResponse struct {
|
||||||
|
Count int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
NextUrl string `json:"next_url"`
|
||||||
|
Resources []StacksResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type StacksResource struct {
|
||||||
|
Meta Meta `json:"metadata"`
|
||||||
|
Entity Stack `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Stack struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListStacksByQuery(query url.Values) ([]Stack, error) {
|
||||||
|
var stacks []Stack
|
||||||
|
requestUrl := "/v2/stacks?" + query.Encode()
|
||||||
|
for {
|
||||||
|
stacksResp, err := c.getStacksResponse(requestUrl)
|
||||||
|
if err != nil {
|
||||||
|
return []Stack{}, err
|
||||||
|
}
|
||||||
|
for _, stack := range stacksResp.Resources {
|
||||||
|
stack.Entity.Guid = stack.Meta.Guid
|
||||||
|
stack.Entity.CreatedAt = stack.Meta.CreatedAt
|
||||||
|
stack.Entity.UpdatedAt = stack.Meta.UpdatedAt
|
||||||
|
stack.Entity.c = c
|
||||||
|
stacks = append(stacks, stack.Entity)
|
||||||
|
}
|
||||||
|
requestUrl = stacksResp.NextUrl
|
||||||
|
if requestUrl == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stacks, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListStacks() ([]Stack, error) {
|
||||||
|
return c.ListStacksByQuery(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) getStacksResponse(requestUrl string) (StacksResponse, error) {
|
||||||
|
var stacksResp StacksResponse
|
||||||
|
r := c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return StacksResponse{}, errors.Wrap(err, "Error requesting stacks")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return StacksResponse{}, errors.Wrap(err, "Error reading stacks body")
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(resBody, &stacksResp)
|
||||||
|
if err != nil {
|
||||||
|
return StacksResponse{}, errors.Wrap(err, "Error unmarshalling stacks")
|
||||||
|
}
|
||||||
|
return stacksResp, nil
|
||||||
|
}
|
||||||
204
vendor/github.com/cloudfoundry-community/go-cfclient/tasks.go
generated
vendored
Normal file
204
vendor/github.com/cloudfoundry-community/go-cfclient/tasks.go
generated
vendored
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TaskListResponse is the JSON response from the API.
|
||||||
|
type TaskListResponse struct {
|
||||||
|
Pagination Pagination `json:"pagination"`
|
||||||
|
Tasks []Task `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Task is a description of a task element.
|
||||||
|
type Task struct {
|
||||||
|
GUID string `json:"guid"`
|
||||||
|
SequenceID int `json:"sequence_id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Command string `json:"command"`
|
||||||
|
State string `json:"state"`
|
||||||
|
MemoryInMb int `json:"memory_in_mb"`
|
||||||
|
DiskInMb int `json:"disk_in_mb"`
|
||||||
|
Result struct {
|
||||||
|
FailureReason string `json:"failure_reason"`
|
||||||
|
} `json:"result"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
DropletGUID string `json:"droplet_guid"`
|
||||||
|
Links struct {
|
||||||
|
Self Link `json:"self"`
|
||||||
|
App Link `json:"app"`
|
||||||
|
Droplet Link `json:"droplet"`
|
||||||
|
} `json:"links"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TaskRequest is a v3 JSON object as described in:
|
||||||
|
// http://v3-apidocs.cloudfoundry.org/version/3.0.0/index.html#create-a-task
|
||||||
|
type TaskRequest struct {
|
||||||
|
Command string `json:"command"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
MemoryInMegabyte int `json:"memory_in_mb"`
|
||||||
|
DiskInMegabyte int `json:"disk_in_mb"`
|
||||||
|
DropletGUID string `json:"droplet_guid"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) makeTaskListRequestWithParams(baseUrl string, query url.Values) ([]byte, error) {
|
||||||
|
requestUrl := baseUrl + "?" + query.Encode()
|
||||||
|
req := c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error requesting tasks")
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
|
return nil, errors.Wrapf(err, "Error requesting tasks: status code not 200, it was %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return ioutil.ReadAll(resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseTaskListRespones(answer []byte) (TaskListResponse, error) {
|
||||||
|
var response TaskListResponse
|
||||||
|
err := json.Unmarshal(answer, &response)
|
||||||
|
if err != nil {
|
||||||
|
return response, errors.Wrap(err, "Error unmarshaling response %v")
|
||||||
|
}
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) handleTasksApiCall(apiUrl string, query url.Values) ([]Task, error) {
|
||||||
|
body, err := c.makeTaskListRequestWithParams(apiUrl, query)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error requesting tasks")
|
||||||
|
}
|
||||||
|
response, err := parseTaskListRespones(body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error reading tasks")
|
||||||
|
}
|
||||||
|
return response.Tasks, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListTasks returns all tasks the user has access to.
|
||||||
|
// See http://v3-apidocs.cloudfoundry.org/version/3.12.0/index.html#list-tasks
|
||||||
|
func (c *Client) ListTasks() ([]Task, error) {
|
||||||
|
return c.handleTasksApiCall("/v3/tasks", url.Values{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListTasksByQuery returns all tasks the user has access to, with query parameters.
|
||||||
|
// See http://v3-apidocs.cloudfoundry.org/version/3.12.0/index.html#list-tasks
|
||||||
|
func (c *Client) ListTasksByQuery(query url.Values) ([]Task, error) {
|
||||||
|
return c.handleTasksApiCall("/v3/tasks", query)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TasksByApp returns task structures which aligned to an app identified by the given guid.
|
||||||
|
// See: http://v3-apidocs.cloudfoundry.org/version/3.12.0/index.html#list-tasks-for-an-app
|
||||||
|
func (c *Client) TasksByApp(guid string) ([]Task, error) {
|
||||||
|
return c.TasksByAppByQuery(guid, url.Values{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// TasksByAppByQuery returns task structures which aligned to an app identified by the given guid
|
||||||
|
// and filtered by the given query parameters.
|
||||||
|
// See: http://v3-apidocs.cloudfoundry.org/version/3.12.0/index.html#list-tasks-for-an-app
|
||||||
|
func (c *Client) TasksByAppByQuery(guid string, query url.Values) ([]Task, error) {
|
||||||
|
uri := fmt.Sprintf("/v3/apps/%s/tasks", guid)
|
||||||
|
return c.handleTasksApiCall(uri, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createReader(tr TaskRequest) (io.Reader, error) {
|
||||||
|
rmap := make(map[string]string)
|
||||||
|
rmap["command"] = tr.Command
|
||||||
|
if tr.Name != "" {
|
||||||
|
rmap["name"] = tr.Name
|
||||||
|
}
|
||||||
|
// setting droplet GUID causing issues
|
||||||
|
if tr.MemoryInMegabyte != 0 {
|
||||||
|
rmap["memory_in_mb"] = fmt.Sprintf("%d", tr.MemoryInMegabyte)
|
||||||
|
}
|
||||||
|
if tr.DiskInMegabyte != 0 {
|
||||||
|
rmap["disk_in_mb"] = fmt.Sprintf("%d", tr.DiskInMegabyte)
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyReader := bytes.NewBuffer(nil)
|
||||||
|
enc := json.NewEncoder(bodyReader)
|
||||||
|
if err := enc.Encode(rmap); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error during encoding task request")
|
||||||
|
}
|
||||||
|
return bodyReader, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateTask creates a new task in CF system and returns its structure.
|
||||||
|
func (c *Client) CreateTask(tr TaskRequest) (task Task, err error) {
|
||||||
|
bodyReader, err := createReader(tr)
|
||||||
|
if err != nil {
|
||||||
|
return task, err
|
||||||
|
}
|
||||||
|
|
||||||
|
request := fmt.Sprintf("/v3/apps/%s/tasks", tr.DropletGUID)
|
||||||
|
req := c.NewRequestWithBody("POST", request, bodyReader)
|
||||||
|
|
||||||
|
resp, err := c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return task, errors.Wrap(err, "Error creating task")
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return task, errors.Wrap(err, "Error reading task after creation")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(body, &task)
|
||||||
|
if err != nil {
|
||||||
|
return task, errors.Wrap(err, "Error unmarshaling task")
|
||||||
|
}
|
||||||
|
return task, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTaskByGuid returns a task structure by requesting it with the tasks GUID.
|
||||||
|
func (c *Client) GetTaskByGuid(guid string) (task Task, err error) {
|
||||||
|
request := fmt.Sprintf("/v3/tasks/%s", guid)
|
||||||
|
req := c.NewRequest("GET", request)
|
||||||
|
|
||||||
|
resp, err := c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return task, errors.Wrap(err, "Error requesting task")
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return task, errors.Wrap(err, "Error reading task")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(body, &task)
|
||||||
|
if err != nil {
|
||||||
|
return task, errors.Wrap(err, "Error unmarshaling task")
|
||||||
|
}
|
||||||
|
return task, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) TaskByGuid(guid string) (task Task, err error) {
|
||||||
|
return c.GetTaskByGuid(guid)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TerminateTask cancels a task identified by its GUID.
|
||||||
|
func (c *Client) TerminateTask(guid string) error {
|
||||||
|
req := c.NewRequest("PUT", fmt.Sprintf("/v3/tasks/%s/cancel", guid))
|
||||||
|
resp, err := c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Error terminating task")
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != 202 {
|
||||||
|
return errors.Wrapf(err, "Failed terminating task, response status code %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
8
vendor/github.com/cloudfoundry-community/go-cfclient/types.go
generated
vendored
Normal file
8
vendor/github.com/cloudfoundry-community/go-cfclient/types.go
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
type Meta struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
Url string `json:"url"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
}
|
||||||
185
vendor/github.com/cloudfoundry-community/go-cfclient/user_provided_service_instances.go
generated
vendored
Normal file
185
vendor/github.com/cloudfoundry-community/go-cfclient/user_provided_service_instances.go
generated
vendored
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserProvidedServiceInstancesResponse struct {
|
||||||
|
Count int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
NextUrl string `json:"next_url"`
|
||||||
|
Resources []UserProvidedServiceInstanceResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserProvidedServiceInstanceResource struct {
|
||||||
|
Meta Meta `json:"metadata"`
|
||||||
|
Entity UserProvidedServiceInstance `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserProvidedServiceInstance struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
Credentials map[string]interface{} `json:"credentials"`
|
||||||
|
SpaceGuid string `json:"space_guid"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Tags []string `json:"tags"`
|
||||||
|
SpaceUrl string `json:"space_url"`
|
||||||
|
ServiceBindingsUrl string `json:"service_bindings_url"`
|
||||||
|
RoutesUrl string `json:"routes_url"`
|
||||||
|
RouteServiceUrl string `json:"route_service_url"`
|
||||||
|
SyslogDrainUrl string `json:"syslog_drain_url"`
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserProvidedServiceInstanceRequest struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Credentials map[string]interface{} `json:"credentials"`
|
||||||
|
SpaceGuid string `json:"space_guid"`
|
||||||
|
Tags []string `json:"tags"`
|
||||||
|
RouteServiceUrl string `json:"route_service_url"`
|
||||||
|
SyslogDrainUrl string `json:"syslog_drain_url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListUserProvidedServiceInstancesByQuery(query url.Values) ([]UserProvidedServiceInstance, error) {
|
||||||
|
var instances []UserProvidedServiceInstance
|
||||||
|
|
||||||
|
requestUrl := "/v2/user_provided_service_instances?" + query.Encode()
|
||||||
|
for {
|
||||||
|
var sir UserProvidedServiceInstancesResponse
|
||||||
|
r := c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error requesting user provided service instances")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error reading user provided service instances request:")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(resBody, &sir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error unmarshaling user provided service instances")
|
||||||
|
}
|
||||||
|
for _, instance := range sir.Resources {
|
||||||
|
instance.Entity.Guid = instance.Meta.Guid
|
||||||
|
instance.Entity.CreatedAt = instance.Meta.CreatedAt
|
||||||
|
instance.Entity.UpdatedAt = instance.Meta.UpdatedAt
|
||||||
|
instance.Entity.c = c
|
||||||
|
instances = append(instances, instance.Entity)
|
||||||
|
}
|
||||||
|
|
||||||
|
requestUrl = sir.NextUrl
|
||||||
|
if requestUrl == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return instances, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListUserProvidedServiceInstances() ([]UserProvidedServiceInstance, error) {
|
||||||
|
return c.ListUserProvidedServiceInstancesByQuery(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetUserProvidedServiceInstanceByGuid(guid string) (UserProvidedServiceInstance, error) {
|
||||||
|
var sir UserProvidedServiceInstanceResource
|
||||||
|
req := c.NewRequest("GET", "/v2/user_provided_service_instances/"+guid)
|
||||||
|
res, err := c.DoRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return UserProvidedServiceInstance{}, errors.Wrap(err, "Error requesting user provided service instance")
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return UserProvidedServiceInstance{}, errors.Wrap(err, "Error reading user provided service instance response")
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(data, &sir)
|
||||||
|
if err != nil {
|
||||||
|
return UserProvidedServiceInstance{}, errors.Wrap(err, "Error JSON parsing user provided service instance response")
|
||||||
|
}
|
||||||
|
sir.Entity.Guid = sir.Meta.Guid
|
||||||
|
sir.Entity.CreatedAt = sir.Meta.CreatedAt
|
||||||
|
sir.Entity.UpdatedAt = sir.Meta.UpdatedAt
|
||||||
|
sir.Entity.c = c
|
||||||
|
return sir.Entity, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) UserProvidedServiceInstanceByGuid(guid string) (UserProvidedServiceInstance, error) {
|
||||||
|
return c.GetUserProvidedServiceInstanceByGuid(guid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) CreateUserProvidedServiceInstance(req UserProvidedServiceInstanceRequest) (*UserProvidedServiceInstance, error) {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
err := json.NewEncoder(buf).Encode(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
r := c.NewRequestWithBody("POST", "/v2/user_provided_service_instances", buf)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return nil, fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.handleUserProvidedServiceInstanceResp(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DeleteUserProvidedServiceInstance(guid string) error {
|
||||||
|
resp, err := c.DoRequest(c.NewRequest("DELETE", fmt.Sprintf("/v2/user_provided_service_instances/%s", guid)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
return errors.Wrapf(err, "Error deleting user provided service instance %s, response code %d", guid, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) UpdateUserProvidedServiceInstance(guid string, req UserProvidedServiceInstanceRequest) (*UserProvidedServiceInstance, error) {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
err := json.NewEncoder(buf).Encode(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
r := c.NewRequestWithBody("PUT", fmt.Sprintf("/v2/user_provided_service_instances/%s", guid), buf)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return nil, fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return c.handleUserProvidedServiceInstanceResp(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) handleUserProvidedServiceInstanceResp(resp *http.Response) (*UserProvidedServiceInstance, error) {
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var upsResource UserProvidedServiceInstanceResource
|
||||||
|
err = json.Unmarshal(body, &upsResource)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c.mergeUserProvidedServiceInstanceResource(upsResource), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) mergeUserProvidedServiceInstanceResource(ups UserProvidedServiceInstanceResource) *UserProvidedServiceInstance {
|
||||||
|
ups.Entity.Guid = ups.Meta.Guid
|
||||||
|
ups.Entity.CreatedAt = ups.Meta.CreatedAt
|
||||||
|
ups.Entity.UpdatedAt = ups.Meta.UpdatedAt
|
||||||
|
ups.Entity.c = c
|
||||||
|
return &ups.Entity
|
||||||
|
}
|
||||||
201
vendor/github.com/cloudfoundry-community/go-cfclient/users.go
generated
vendored
Normal file
201
vendor/github.com/cloudfoundry-community/go-cfclient/users.go
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserRequest struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
DefaultSpaceGuid string `json:"default_space_guid,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Users []User
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
Admin bool `json:"admin"`
|
||||||
|
Active bool `json:"active"`
|
||||||
|
DefaultSpaceGUID string `json:"default_space_guid"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
SpacesURL string `json:"spaces_url"`
|
||||||
|
OrgsURL string `json:"organizations_url"`
|
||||||
|
ManagedOrgsURL string `json:"managed_organizations_url"`
|
||||||
|
BillingManagedOrgsURL string `json:"billing_managed_organizations_url"`
|
||||||
|
AuditedOrgsURL string `json:"audited_organizations_url"`
|
||||||
|
ManagedSpacesURL string `json:"managed_spaces_url"`
|
||||||
|
AuditedSpacesURL string `json:"audited_spaces_url"`
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserResource struct {
|
||||||
|
Meta Meta `json:"metadata"`
|
||||||
|
Entity User `json:"entity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserResponse struct {
|
||||||
|
Count int `json:"total_results"`
|
||||||
|
Pages int `json:"total_pages"`
|
||||||
|
NextUrl string `json:"next_url"`
|
||||||
|
Resources []UserResource `json:"resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserByGUID retrieves the user with the provided guid.
|
||||||
|
func (c *Client) GetUserByGUID(guid string) (User, error) {
|
||||||
|
var userRes UserResource
|
||||||
|
r := c.NewRequest("GET", "/v2/users/"+guid)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return User{}, err
|
||||||
|
}
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return User{}, err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(body, &userRes)
|
||||||
|
if err != nil {
|
||||||
|
return User{}, err
|
||||||
|
}
|
||||||
|
return c.mergeUserResource(userRes), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListUsersByQuery(query url.Values) (Users, error) {
|
||||||
|
var users []User
|
||||||
|
requestUrl := "/v2/users?" + query.Encode()
|
||||||
|
for {
|
||||||
|
userResp, err := c.getUserResponse(requestUrl)
|
||||||
|
if err != nil {
|
||||||
|
return []User{}, err
|
||||||
|
}
|
||||||
|
for _, user := range userResp.Resources {
|
||||||
|
user.Entity.Guid = user.Meta.Guid
|
||||||
|
user.Entity.CreatedAt = user.Meta.CreatedAt
|
||||||
|
user.Entity.UpdatedAt = user.Meta.UpdatedAt
|
||||||
|
user.Entity.c = c
|
||||||
|
users = append(users, user.Entity)
|
||||||
|
}
|
||||||
|
requestUrl = userResp.NextUrl
|
||||||
|
if requestUrl == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return users, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListUsers() (Users, error) {
|
||||||
|
return c.ListUsersByQuery(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListUserSpaces(userGuid string) ([]Space, error) {
|
||||||
|
return c.fetchSpaces(fmt.Sprintf("/v2/users/%s/spaces", userGuid))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListUserAuditedSpaces(userGuid string) ([]Space, error) {
|
||||||
|
return c.fetchSpaces(fmt.Sprintf("/v2/users/%s/audited_spaces", userGuid))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListUserManagedSpaces(userGuid string) ([]Space, error) {
|
||||||
|
return c.fetchSpaces(fmt.Sprintf("/v2/users/%s/managed_spaces", userGuid))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListUserOrgs(userGuid string) ([]Org, error) {
|
||||||
|
return c.fetchOrgs(fmt.Sprintf("/v2/users/%s/organizations", userGuid))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListUserManagedOrgs(userGuid string) ([]Org, error) {
|
||||||
|
return c.fetchOrgs(fmt.Sprintf("/v2/users/%s/managed_organizations", userGuid))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListUserAuditedOrgs(userGuid string) ([]Org, error) {
|
||||||
|
return c.fetchOrgs(fmt.Sprintf("/v2/users/%s/audited_organizations", userGuid))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListUserBillingManagedOrgs(userGuid string) ([]Org, error) {
|
||||||
|
return c.fetchOrgs(fmt.Sprintf("/v2/users/%s/billing_managed_organizations", userGuid))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) CreateUser(req UserRequest) (User, error) {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
err := json.NewEncoder(buf).Encode(req)
|
||||||
|
if err != nil {
|
||||||
|
return User{}, err
|
||||||
|
}
|
||||||
|
r := c.NewRequestWithBody("POST", "/v2/users", buf)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return User{}, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
return User{}, errors.Wrapf(err, "Error creating user, response code: %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return User{}, err
|
||||||
|
}
|
||||||
|
var userResource UserResource
|
||||||
|
err = json.Unmarshal(body, &userResource)
|
||||||
|
if err != nil {
|
||||||
|
return User{}, err
|
||||||
|
}
|
||||||
|
user := userResource.Entity
|
||||||
|
user.Guid = userResource.Meta.Guid
|
||||||
|
user.c = c
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DeleteUser(userGuid string) error {
|
||||||
|
resp, err := c.DoRequest(c.NewRequest("DELETE", fmt.Sprintf("/v2/users/%s", userGuid)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
return errors.Wrapf(err, "Error deleting user %s, response code: %d", userGuid, resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u Users) GetUserByUsername(username string) User {
|
||||||
|
for _, user := range u {
|
||||||
|
if user.Username == username {
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return User{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) getUserResponse(requestUrl string) (UserResponse, error) {
|
||||||
|
var userResp UserResponse
|
||||||
|
r := c.NewRequest("GET", requestUrl)
|
||||||
|
resp, err := c.DoRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return UserResponse{}, errors.Wrap(err, "Error requesting users")
|
||||||
|
}
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return UserResponse{}, errors.Wrap(err, "Error reading user request")
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(resBody, &userResp)
|
||||||
|
if err != nil {
|
||||||
|
return UserResponse{}, errors.Wrap(err, "Error unmarshalling user")
|
||||||
|
}
|
||||||
|
return userResp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) mergeUserResource(u UserResource) User {
|
||||||
|
u.Entity.Guid = u.Meta.Guid
|
||||||
|
u.Entity.CreatedAt = u.Meta.CreatedAt
|
||||||
|
u.Entity.UpdatedAt = u.Meta.UpdatedAt
|
||||||
|
u.Entity.c = c
|
||||||
|
return u.Entity
|
||||||
|
}
|
||||||
17
vendor/github.com/cloudfoundry-community/go-cfclient/v3types.go
generated
vendored
Normal file
17
vendor/github.com/cloudfoundry-community/go-cfclient/v3types.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package cfclient
|
||||||
|
|
||||||
|
// Pagination is used by the V3 apis
|
||||||
|
type Pagination struct {
|
||||||
|
TotalResults int `json:"total_results"`
|
||||||
|
TotalPages int `json:"total_pages"`
|
||||||
|
First Link `json:"first"`
|
||||||
|
Last Link `json:"last"`
|
||||||
|
Next interface{} `json:"next"`
|
||||||
|
Previous interface{} `json:"previous"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Link is a HATEOAS-style link for v3 apis
|
||||||
|
type Link struct {
|
||||||
|
Href string `json:"href"`
|
||||||
|
Method string `json:"method,omitempty"`
|
||||||
|
}
|
||||||
38
vendor/github.com/hashicorp/go-hclog/context.go
generated
vendored
Normal file
38
vendor/github.com/hashicorp/go-hclog/context.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package hclog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WithContext inserts a logger into the context and is retrievable
|
||||||
|
// with FromContext. The optional args can be set with the same syntax as
|
||||||
|
// Logger.With to set fields on the inserted logger. This will not modify
|
||||||
|
// the logger argument in-place.
|
||||||
|
func WithContext(ctx context.Context, logger Logger, args ...interface{}) context.Context {
|
||||||
|
// While we could call logger.With even with zero args, we have this
|
||||||
|
// check to avoid unnecessary allocations around creating a copy of a
|
||||||
|
// logger.
|
||||||
|
if len(args) > 0 {
|
||||||
|
logger = logger.With(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.WithValue(ctx, contextKey, logger)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromContext returns a logger from the context. This will return L()
|
||||||
|
// (the default logger) if no logger is found in the context. Therefore,
|
||||||
|
// this will never return a nil value.
|
||||||
|
func FromContext(ctx context.Context) Logger {
|
||||||
|
logger, _ := ctx.Value(contextKey).(Logger)
|
||||||
|
if logger == nil {
|
||||||
|
return L()
|
||||||
|
}
|
||||||
|
|
||||||
|
return logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unexported new type so that our context key never collides with another.
|
||||||
|
type contextKeyType struct{}
|
||||||
|
|
||||||
|
// contextKey is the key used for the context to store the logger.
|
||||||
|
var contextKey = contextKeyType{}
|
||||||
14
vendor/github.com/hashicorp/go-hclog/global.go
generated
vendored
14
vendor/github.com/hashicorp/go-hclog/global.go
generated
vendored
@@ -22,7 +22,11 @@ var (
|
|||||||
// to be used in more specific contexts.
|
// to be used in more specific contexts.
|
||||||
func Default() Logger {
|
func Default() Logger {
|
||||||
protect.Do(func() {
|
protect.Do(func() {
|
||||||
|
// If SetDefault was used before Default() was called, we need to
|
||||||
|
// detect that here.
|
||||||
|
if def == nil {
|
||||||
def = New(DefaultOptions)
|
def = New(DefaultOptions)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return def
|
return def
|
||||||
@@ -32,3 +36,13 @@ func Default() Logger {
|
|||||||
func L() Logger {
|
func L() Logger {
|
||||||
return Default()
|
return Default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetDefault changes the logger to be returned by Default()and L()
|
||||||
|
// to the one given. This allows packages to use the default logger
|
||||||
|
// and have higher level packages change it to match the execution
|
||||||
|
// environment. It returns any old default if there is one.
|
||||||
|
func SetDefault(log Logger) Logger {
|
||||||
|
old := def
|
||||||
|
def = log
|
||||||
|
return old
|
||||||
|
}
|
||||||
|
|||||||
86
vendor/github.com/hashicorp/go-hclog/intlogger.go
generated
vendored
86
vendor/github.com/hashicorp/go-hclog/intlogger.go
generated
vendored
@@ -21,6 +21,9 @@ import (
|
|||||||
// contains millisecond precision
|
// contains millisecond precision
|
||||||
const TimeFormat = "2006-01-02T15:04:05.000Z0700"
|
const TimeFormat = "2006-01-02T15:04:05.000Z0700"
|
||||||
|
|
||||||
|
// errJsonUnsupportedTypeMsg is included in log json entries, if an arg cannot be serialized to json
|
||||||
|
const errJsonUnsupportedTypeMsg = "logging contained values that don't serialize to json"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_levelToBracket = map[Level]string{
|
_levelToBracket = map[Level]string{
|
||||||
Debug: "[DEBUG]",
|
Debug: "[DEBUG]",
|
||||||
@@ -296,39 +299,7 @@ func (l *intLogger) renderSlice(v reflect.Value) string {
|
|||||||
|
|
||||||
// JSON logging function
|
// JSON logging function
|
||||||
func (l *intLogger) logJSON(t time.Time, level Level, msg string, args ...interface{}) {
|
func (l *intLogger) logJSON(t time.Time, level Level, msg string, args ...interface{}) {
|
||||||
vals := map[string]interface{}{
|
vals := l.jsonMapEntry(t, level, msg)
|
||||||
"@message": msg,
|
|
||||||
"@timestamp": t.Format("2006-01-02T15:04:05.000000Z07:00"),
|
|
||||||
}
|
|
||||||
|
|
||||||
var levelStr string
|
|
||||||
switch level {
|
|
||||||
case Error:
|
|
||||||
levelStr = "error"
|
|
||||||
case Warn:
|
|
||||||
levelStr = "warn"
|
|
||||||
case Info:
|
|
||||||
levelStr = "info"
|
|
||||||
case Debug:
|
|
||||||
levelStr = "debug"
|
|
||||||
case Trace:
|
|
||||||
levelStr = "trace"
|
|
||||||
default:
|
|
||||||
levelStr = "all"
|
|
||||||
}
|
|
||||||
|
|
||||||
vals["@level"] = levelStr
|
|
||||||
|
|
||||||
if l.name != "" {
|
|
||||||
vals["@module"] = l.name
|
|
||||||
}
|
|
||||||
|
|
||||||
if l.caller {
|
|
||||||
if _, file, line, ok := runtime.Caller(3); ok {
|
|
||||||
vals["@caller"] = fmt.Sprintf("%s:%d", file, line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
args = append(l.implied, args...)
|
args = append(l.implied, args...)
|
||||||
|
|
||||||
if args != nil && len(args) > 0 {
|
if args != nil && len(args) > 0 {
|
||||||
@@ -369,8 +340,49 @@ func (l *intLogger) logJSON(t time.Time, level Level, msg string, args ...interf
|
|||||||
|
|
||||||
err := json.NewEncoder(l.writer).Encode(vals)
|
err := json.NewEncoder(l.writer).Encode(vals)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
if _, ok := err.(*json.UnsupportedTypeError); ok {
|
||||||
|
plainVal := l.jsonMapEntry(t, level, msg)
|
||||||
|
plainVal["@warn"] = errJsonUnsupportedTypeMsg
|
||||||
|
|
||||||
|
json.NewEncoder(l.writer).Encode(plainVal)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l intLogger) jsonMapEntry(t time.Time, level Level, msg string) map[string]interface{} {
|
||||||
|
vals := map[string]interface{}{
|
||||||
|
"@message": msg,
|
||||||
|
"@timestamp": t.Format("2006-01-02T15:04:05.000000Z07:00"),
|
||||||
|
}
|
||||||
|
|
||||||
|
var levelStr string
|
||||||
|
switch level {
|
||||||
|
case Error:
|
||||||
|
levelStr = "error"
|
||||||
|
case Warn:
|
||||||
|
levelStr = "warn"
|
||||||
|
case Info:
|
||||||
|
levelStr = "info"
|
||||||
|
case Debug:
|
||||||
|
levelStr = "debug"
|
||||||
|
case Trace:
|
||||||
|
levelStr = "trace"
|
||||||
|
default:
|
||||||
|
levelStr = "all"
|
||||||
|
}
|
||||||
|
|
||||||
|
vals["@level"] = levelStr
|
||||||
|
|
||||||
|
if l.name != "" {
|
||||||
|
vals["@module"] = l.name
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.caller {
|
||||||
|
if _, file, line, ok := runtime.Caller(4); ok {
|
||||||
|
vals["@caller"] = fmt.Sprintf("%s:%d", file, line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vals
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit the message and args at DEBUG level
|
// Emit the message and args at DEBUG level
|
||||||
@@ -507,5 +519,9 @@ func (l *intLogger) StandardLogger(opts *StandardLoggerOptions) *log.Logger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *intLogger) StandardWriter(opts *StandardLoggerOptions) io.Writer {
|
func (l *intLogger) StandardWriter(opts *StandardLoggerOptions) io.Writer {
|
||||||
return &stdlogAdapter{l, opts.InferLevels}
|
return &stdlogAdapter{
|
||||||
|
log: l,
|
||||||
|
inferLevels: opts.InferLevels,
|
||||||
|
forceLevel: opts.ForceLevel,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
6
vendor/github.com/hashicorp/go-hclog/logger.go
generated
vendored
6
vendor/github.com/hashicorp/go-hclog/logger.go
generated
vendored
@@ -143,6 +143,12 @@ type StandardLoggerOptions struct {
|
|||||||
// This supports the strings like [ERROR], [ERR] [TRACE], [WARN], [INFO],
|
// This supports the strings like [ERROR], [ERR] [TRACE], [WARN], [INFO],
|
||||||
// [DEBUG] and strip it off before reapplying it.
|
// [DEBUG] and strip it off before reapplying it.
|
||||||
InferLevels bool
|
InferLevels bool
|
||||||
|
|
||||||
|
// ForceLevel is used to force all output from the standard logger to be at
|
||||||
|
// the specified level. Similar to InferLevels, this will strip any level
|
||||||
|
// prefix contained in the logged string before applying the forced level.
|
||||||
|
// If set, this override InferLevels.
|
||||||
|
ForceLevel Level
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoggerOptions can be used to configure a new logger.
|
// LoggerOptions can be used to configure a new logger.
|
||||||
|
|||||||
23
vendor/github.com/hashicorp/go-hclog/stdlog.go
generated
vendored
23
vendor/github.com/hashicorp/go-hclog/stdlog.go
generated
vendored
@@ -11,6 +11,7 @@ import (
|
|||||||
type stdlogAdapter struct {
|
type stdlogAdapter struct {
|
||||||
log Logger
|
log Logger
|
||||||
inferLevels bool
|
inferLevels bool
|
||||||
|
forceLevel Level
|
||||||
}
|
}
|
||||||
|
|
||||||
// Take the data, infer the levels if configured, and send it through
|
// Take the data, infer the levels if configured, and send it through
|
||||||
@@ -18,7 +19,27 @@ type stdlogAdapter struct {
|
|||||||
func (s *stdlogAdapter) Write(data []byte) (int, error) {
|
func (s *stdlogAdapter) Write(data []byte) (int, error) {
|
||||||
str := string(bytes.TrimRight(data, " \t\n"))
|
str := string(bytes.TrimRight(data, " \t\n"))
|
||||||
|
|
||||||
if s.inferLevels {
|
if s.forceLevel != NoLevel {
|
||||||
|
// Use pickLevel to strip log levels included in the line since we are
|
||||||
|
// forcing the level
|
||||||
|
_, str := s.pickLevel(str)
|
||||||
|
|
||||||
|
// Log at the forced level
|
||||||
|
switch s.forceLevel {
|
||||||
|
case Trace:
|
||||||
|
s.log.Trace(str)
|
||||||
|
case Debug:
|
||||||
|
s.log.Debug(str)
|
||||||
|
case Info:
|
||||||
|
s.log.Info(str)
|
||||||
|
case Warn:
|
||||||
|
s.log.Warn(str)
|
||||||
|
case Error:
|
||||||
|
s.log.Error(str)
|
||||||
|
default:
|
||||||
|
s.log.Info(str)
|
||||||
|
}
|
||||||
|
} else if s.inferLevels {
|
||||||
level, str := s.pickLevel(str)
|
level, str := s.pickLevel(str)
|
||||||
switch level {
|
switch level {
|
||||||
case Trace:
|
case Trace:
|
||||||
|
|||||||
25
vendor/github.com/hashicorp/vault-plugin-auth-pcf/.gitignore
generated
vendored
Normal file
25
vendor/github.com/hashicorp/vault-plugin-auth-pcf/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# Binaries for programs and plugins
|
||||||
|
*.exe
|
||||||
|
*.exe~
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Test binary, build with `go test -c`
|
||||||
|
*.test
|
||||||
|
|
||||||
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
|
*.out
|
||||||
|
|
||||||
|
# Jetbrains
|
||||||
|
.idea*
|
||||||
|
|
||||||
|
# Binaries
|
||||||
|
cmd/vault-plugin-auth-pcf/vault-plugin-auth-pcf
|
||||||
|
cmd/verify/verify
|
||||||
|
|
||||||
|
pkg*
|
||||||
|
bin*
|
||||||
|
|
||||||
|
# Ignore fake certificates generated for tests
|
||||||
|
testdata/fake-certificates*
|
||||||
373
vendor/github.com/hashicorp/vault-plugin-auth-pcf/LICENSE
generated
vendored
Normal file
373
vendor/github.com/hashicorp/vault-plugin-auth-pcf/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,373 @@
|
|||||||
|
Mozilla Public License Version 2.0
|
||||||
|
==================================
|
||||||
|
|
||||||
|
1. Definitions
|
||||||
|
--------------
|
||||||
|
|
||||||
|
1.1. "Contributor"
|
||||||
|
means each individual or legal entity that creates, contributes to
|
||||||
|
the creation of, or owns Covered Software.
|
||||||
|
|
||||||
|
1.2. "Contributor Version"
|
||||||
|
means the combination of the Contributions of others (if any) used
|
||||||
|
by a Contributor and that particular Contributor's Contribution.
|
||||||
|
|
||||||
|
1.3. "Contribution"
|
||||||
|
means Covered Software of a particular Contributor.
|
||||||
|
|
||||||
|
1.4. "Covered Software"
|
||||||
|
means Source Code Form to which the initial Contributor has attached
|
||||||
|
the notice in Exhibit A, the Executable Form of such Source Code
|
||||||
|
Form, and Modifications of such Source Code Form, in each case
|
||||||
|
including portions thereof.
|
||||||
|
|
||||||
|
1.5. "Incompatible With Secondary Licenses"
|
||||||
|
means
|
||||||
|
|
||||||
|
(a) that the initial Contributor has attached the notice described
|
||||||
|
in Exhibit B to the Covered Software; or
|
||||||
|
|
||||||
|
(b) that the Covered Software was made available under the terms of
|
||||||
|
version 1.1 or earlier of the License, but not also under the
|
||||||
|
terms of a Secondary License.
|
||||||
|
|
||||||
|
1.6. "Executable Form"
|
||||||
|
means any form of the work other than Source Code Form.
|
||||||
|
|
||||||
|
1.7. "Larger Work"
|
||||||
|
means a work that combines Covered Software with other material, in
|
||||||
|
a separate file or files, that is not Covered Software.
|
||||||
|
|
||||||
|
1.8. "License"
|
||||||
|
means this document.
|
||||||
|
|
||||||
|
1.9. "Licensable"
|
||||||
|
means having the right to grant, to the maximum extent possible,
|
||||||
|
whether at the time of the initial grant or subsequently, any and
|
||||||
|
all of the rights conveyed by this License.
|
||||||
|
|
||||||
|
1.10. "Modifications"
|
||||||
|
means any of the following:
|
||||||
|
|
||||||
|
(a) any file in Source Code Form that results from an addition to,
|
||||||
|
deletion from, or modification of the contents of Covered
|
||||||
|
Software; or
|
||||||
|
|
||||||
|
(b) any new file in Source Code Form that contains any Covered
|
||||||
|
Software.
|
||||||
|
|
||||||
|
1.11. "Patent Claims" of a Contributor
|
||||||
|
means any patent claim(s), including without limitation, method,
|
||||||
|
process, and apparatus claims, in any patent Licensable by such
|
||||||
|
Contributor that would be infringed, but for the grant of the
|
||||||
|
License, by the making, using, selling, offering for sale, having
|
||||||
|
made, import, or transfer of either its Contributions or its
|
||||||
|
Contributor Version.
|
||||||
|
|
||||||
|
1.12. "Secondary License"
|
||||||
|
means either the GNU General Public License, Version 2.0, the GNU
|
||||||
|
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||||
|
Public License, Version 3.0, or any later versions of those
|
||||||
|
licenses.
|
||||||
|
|
||||||
|
1.13. "Source Code Form"
|
||||||
|
means the form of the work preferred for making modifications.
|
||||||
|
|
||||||
|
1.14. "You" (or "Your")
|
||||||
|
means an individual or a legal entity exercising rights under this
|
||||||
|
License. For legal entities, "You" includes any entity that
|
||||||
|
controls, is controlled by, or is under common control with You. For
|
||||||
|
purposes of this definition, "control" means (a) the power, direct
|
||||||
|
or indirect, to cause the direction or management of such entity,
|
||||||
|
whether by contract or otherwise, or (b) ownership of more than
|
||||||
|
fifty percent (50%) of the outstanding shares or beneficial
|
||||||
|
ownership of such entity.
|
||||||
|
|
||||||
|
2. License Grants and Conditions
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
2.1. Grants
|
||||||
|
|
||||||
|
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||||
|
non-exclusive license:
|
||||||
|
|
||||||
|
(a) under intellectual property rights (other than patent or trademark)
|
||||||
|
Licensable by such Contributor to use, reproduce, make available,
|
||||||
|
modify, display, perform, distribute, and otherwise exploit its
|
||||||
|
Contributions, either on an unmodified basis, with Modifications, or
|
||||||
|
as part of a Larger Work; and
|
||||||
|
|
||||||
|
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||||
|
for sale, have made, import, and otherwise transfer either its
|
||||||
|
Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
2.2. Effective Date
|
||||||
|
|
||||||
|
The licenses granted in Section 2.1 with respect to any Contribution
|
||||||
|
become effective for each Contribution on the date the Contributor first
|
||||||
|
distributes such Contribution.
|
||||||
|
|
||||||
|
2.3. Limitations on Grant Scope
|
||||||
|
|
||||||
|
The licenses granted in this Section 2 are the only rights granted under
|
||||||
|
this License. No additional rights or licenses will be implied from the
|
||||||
|
distribution or licensing of Covered Software under this License.
|
||||||
|
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||||
|
Contributor:
|
||||||
|
|
||||||
|
(a) for any code that a Contributor has removed from Covered Software;
|
||||||
|
or
|
||||||
|
|
||||||
|
(b) for infringements caused by: (i) Your and any other third party's
|
||||||
|
modifications of Covered Software, or (ii) the combination of its
|
||||||
|
Contributions with other software (except as part of its Contributor
|
||||||
|
Version); or
|
||||||
|
|
||||||
|
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||||
|
its Contributions.
|
||||||
|
|
||||||
|
This License does not grant any rights in the trademarks, service marks,
|
||||||
|
or logos of any Contributor (except as may be necessary to comply with
|
||||||
|
the notice requirements in Section 3.4).
|
||||||
|
|
||||||
|
2.4. Subsequent Licenses
|
||||||
|
|
||||||
|
No Contributor makes additional grants as a result of Your choice to
|
||||||
|
distribute the Covered Software under a subsequent version of this
|
||||||
|
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||||
|
permitted under the terms of Section 3.3).
|
||||||
|
|
||||||
|
2.5. Representation
|
||||||
|
|
||||||
|
Each Contributor represents that the Contributor believes its
|
||||||
|
Contributions are its original creation(s) or it has sufficient rights
|
||||||
|
to grant the rights to its Contributions conveyed by this License.
|
||||||
|
|
||||||
|
2.6. Fair Use
|
||||||
|
|
||||||
|
This License is not intended to limit any rights You have under
|
||||||
|
applicable copyright doctrines of fair use, fair dealing, or other
|
||||||
|
equivalents.
|
||||||
|
|
||||||
|
2.7. Conditions
|
||||||
|
|
||||||
|
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||||
|
in Section 2.1.
|
||||||
|
|
||||||
|
3. Responsibilities
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
3.1. Distribution of Source Form
|
||||||
|
|
||||||
|
All distribution of Covered Software in Source Code Form, including any
|
||||||
|
Modifications that You create or to which You contribute, must be under
|
||||||
|
the terms of this License. You must inform recipients that the Source
|
||||||
|
Code Form of the Covered Software is governed by the terms of this
|
||||||
|
License, and how they can obtain a copy of this License. You may not
|
||||||
|
attempt to alter or restrict the recipients' rights in the Source Code
|
||||||
|
Form.
|
||||||
|
|
||||||
|
3.2. Distribution of Executable Form
|
||||||
|
|
||||||
|
If You distribute Covered Software in Executable Form then:
|
||||||
|
|
||||||
|
(a) such Covered Software must also be made available in Source Code
|
||||||
|
Form, as described in Section 3.1, and You must inform recipients of
|
||||||
|
the Executable Form how they can obtain a copy of such Source Code
|
||||||
|
Form by reasonable means in a timely manner, at a charge no more
|
||||||
|
than the cost of distribution to the recipient; and
|
||||||
|
|
||||||
|
(b) You may distribute such Executable Form under the terms of this
|
||||||
|
License, or sublicense it under different terms, provided that the
|
||||||
|
license for the Executable Form does not attempt to limit or alter
|
||||||
|
the recipients' rights in the Source Code Form under this License.
|
||||||
|
|
||||||
|
3.3. Distribution of a Larger Work
|
||||||
|
|
||||||
|
You may create and distribute a Larger Work under terms of Your choice,
|
||||||
|
provided that You also comply with the requirements of this License for
|
||||||
|
the Covered Software. If the Larger Work is a combination of Covered
|
||||||
|
Software with a work governed by one or more Secondary Licenses, and the
|
||||||
|
Covered Software is not Incompatible With Secondary Licenses, this
|
||||||
|
License permits You to additionally distribute such Covered Software
|
||||||
|
under the terms of such Secondary License(s), so that the recipient of
|
||||||
|
the Larger Work may, at their option, further distribute the Covered
|
||||||
|
Software under the terms of either this License or such Secondary
|
||||||
|
License(s).
|
||||||
|
|
||||||
|
3.4. Notices
|
||||||
|
|
||||||
|
You may not remove or alter the substance of any license notices
|
||||||
|
(including copyright notices, patent notices, disclaimers of warranty,
|
||||||
|
or limitations of liability) contained within the Source Code Form of
|
||||||
|
the Covered Software, except that You may alter any license notices to
|
||||||
|
the extent required to remedy known factual inaccuracies.
|
||||||
|
|
||||||
|
3.5. Application of Additional Terms
|
||||||
|
|
||||||
|
You may choose to offer, and to charge a fee for, warranty, support,
|
||||||
|
indemnity or liability obligations to one or more recipients of Covered
|
||||||
|
Software. However, You may do so only on Your own behalf, and not on
|
||||||
|
behalf of any Contributor. You must make it absolutely clear that any
|
||||||
|
such warranty, support, indemnity, or liability obligation is offered by
|
||||||
|
You alone, and You hereby agree to indemnify every Contributor for any
|
||||||
|
liability incurred by such Contributor as a result of warranty, support,
|
||||||
|
indemnity or liability terms You offer. You may include additional
|
||||||
|
disclaimers of warranty and limitations of liability specific to any
|
||||||
|
jurisdiction.
|
||||||
|
|
||||||
|
4. Inability to Comply Due to Statute or Regulation
|
||||||
|
---------------------------------------------------
|
||||||
|
|
||||||
|
If it is impossible for You to comply with any of the terms of this
|
||||||
|
License with respect to some or all of the Covered Software due to
|
||||||
|
statute, judicial order, or regulation then You must: (a) comply with
|
||||||
|
the terms of this License to the maximum extent possible; and (b)
|
||||||
|
describe the limitations and the code they affect. Such description must
|
||||||
|
be placed in a text file included with all distributions of the Covered
|
||||||
|
Software under this License. Except to the extent prohibited by statute
|
||||||
|
or regulation, such description must be sufficiently detailed for a
|
||||||
|
recipient of ordinary skill to be able to understand it.
|
||||||
|
|
||||||
|
5. Termination
|
||||||
|
--------------
|
||||||
|
|
||||||
|
5.1. The rights granted under this License will terminate automatically
|
||||||
|
if You fail to comply with any of its terms. However, if You become
|
||||||
|
compliant, then the rights granted under this License from a particular
|
||||||
|
Contributor are reinstated (a) provisionally, unless and until such
|
||||||
|
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||||
|
ongoing basis, if such Contributor fails to notify You of the
|
||||||
|
non-compliance by some reasonable means prior to 60 days after You have
|
||||||
|
come back into compliance. Moreover, Your grants from a particular
|
||||||
|
Contributor are reinstated on an ongoing basis if such Contributor
|
||||||
|
notifies You of the non-compliance by some reasonable means, this is the
|
||||||
|
first time You have received notice of non-compliance with this License
|
||||||
|
from such Contributor, and You become compliant prior to 30 days after
|
||||||
|
Your receipt of the notice.
|
||||||
|
|
||||||
|
5.2. If You initiate litigation against any entity by asserting a patent
|
||||||
|
infringement claim (excluding declaratory judgment actions,
|
||||||
|
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||||
|
directly or indirectly infringes any patent, then the rights granted to
|
||||||
|
You by any and all Contributors for the Covered Software under Section
|
||||||
|
2.1 of this License shall terminate.
|
||||||
|
|
||||||
|
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||||
|
end user license agreements (excluding distributors and resellers) which
|
||||||
|
have been validly granted by You or Your distributors under this License
|
||||||
|
prior to termination shall survive termination.
|
||||||
|
|
||||||
|
************************************************************************
|
||||||
|
* *
|
||||||
|
* 6. Disclaimer of Warranty *
|
||||||
|
* ------------------------- *
|
||||||
|
* *
|
||||||
|
* Covered Software is provided under this License on an "as is" *
|
||||||
|
* basis, without warranty of any kind, either expressed, implied, or *
|
||||||
|
* statutory, including, without limitation, warranties that the *
|
||||||
|
* Covered Software is free of defects, merchantable, fit for a *
|
||||||
|
* particular purpose or non-infringing. The entire risk as to the *
|
||||||
|
* quality and performance of the Covered Software is with You. *
|
||||||
|
* Should any Covered Software prove defective in any respect, You *
|
||||||
|
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||||
|
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||||
|
* essential part of this License. No use of any Covered Software is *
|
||||||
|
* authorized under this License except under this disclaimer. *
|
||||||
|
* *
|
||||||
|
************************************************************************
|
||||||
|
|
||||||
|
************************************************************************
|
||||||
|
* *
|
||||||
|
* 7. Limitation of Liability *
|
||||||
|
* -------------------------- *
|
||||||
|
* *
|
||||||
|
* Under no circumstances and under no legal theory, whether tort *
|
||||||
|
* (including negligence), contract, or otherwise, shall any *
|
||||||
|
* Contributor, or anyone who distributes Covered Software as *
|
||||||
|
* permitted above, be liable to You for any direct, indirect, *
|
||||||
|
* special, incidental, or consequential damages of any character *
|
||||||
|
* including, without limitation, damages for lost profits, loss of *
|
||||||
|
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||||
|
* and all other commercial damages or losses, even if such party *
|
||||||
|
* shall have been informed of the possibility of such damages. This *
|
||||||
|
* limitation of liability shall not apply to liability for death or *
|
||||||
|
* personal injury resulting from such party's negligence to the *
|
||||||
|
* extent applicable law prohibits such limitation. Some *
|
||||||
|
* jurisdictions do not allow the exclusion or limitation of *
|
||||||
|
* incidental or consequential damages, so this exclusion and *
|
||||||
|
* limitation may not apply to You. *
|
||||||
|
* *
|
||||||
|
************************************************************************
|
||||||
|
|
||||||
|
8. Litigation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Any litigation relating to this License may be brought only in the
|
||||||
|
courts of a jurisdiction where the defendant maintains its principal
|
||||||
|
place of business and such litigation shall be governed by laws of that
|
||||||
|
jurisdiction, without reference to its conflict-of-law provisions.
|
||||||
|
Nothing in this Section shall prevent a party's ability to bring
|
||||||
|
cross-claims or counter-claims.
|
||||||
|
|
||||||
|
9. Miscellaneous
|
||||||
|
----------------
|
||||||
|
|
||||||
|
This License represents the complete agreement concerning the subject
|
||||||
|
matter hereof. If any provision of this License is held to be
|
||||||
|
unenforceable, such provision shall be reformed only to the extent
|
||||||
|
necessary to make it enforceable. Any law or regulation which provides
|
||||||
|
that the language of a contract shall be construed against the drafter
|
||||||
|
shall not be used to construe this License against a Contributor.
|
||||||
|
|
||||||
|
10. Versions of the License
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
10.1. New Versions
|
||||||
|
|
||||||
|
Mozilla Foundation is the license steward. Except as provided in Section
|
||||||
|
10.3, no one other than the license steward has the right to modify or
|
||||||
|
publish new versions of this License. Each version will be given a
|
||||||
|
distinguishing version number.
|
||||||
|
|
||||||
|
10.2. Effect of New Versions
|
||||||
|
|
||||||
|
You may distribute the Covered Software under the terms of the version
|
||||||
|
of the License under which You originally received the Covered Software,
|
||||||
|
or under the terms of any subsequent version published by the license
|
||||||
|
steward.
|
||||||
|
|
||||||
|
10.3. Modified Versions
|
||||||
|
|
||||||
|
If you create software not governed by this License, and you want to
|
||||||
|
create a new license for such software, you may create and use a
|
||||||
|
modified version of this License if you rename the license and remove
|
||||||
|
any references to the name of the license steward (except to note that
|
||||||
|
such modified license differs from this License).
|
||||||
|
|
||||||
|
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||||
|
Licenses
|
||||||
|
|
||||||
|
If You choose to distribute Source Code Form that is Incompatible With
|
||||||
|
Secondary Licenses under the terms of this version of the License, the
|
||||||
|
notice described in Exhibit B of this License must be attached.
|
||||||
|
|
||||||
|
Exhibit A - Source Code Form License Notice
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
If it is not possible or desirable to put the notice in a particular
|
||||||
|
file, then You may include the notice in a location (such as a LICENSE
|
||||||
|
file in a relevant directory) where a recipient would be likely to look
|
||||||
|
for such a notice.
|
||||||
|
|
||||||
|
You may add additional accurate notices of copyright ownership.
|
||||||
|
|
||||||
|
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||||
|
---------------------------------------------------------
|
||||||
|
|
||||||
|
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
|
defined by the Mozilla Public License, v. 2.0.
|
||||||
60
vendor/github.com/hashicorp/vault-plugin-auth-pcf/Makefile
generated
vendored
Normal file
60
vendor/github.com/hashicorp/vault-plugin-auth-pcf/Makefile
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
TOOL?=vault-plugin-auth-pcf
|
||||||
|
TEST?=$$(go list ./... | grep -v /vendor/ | grep -v teamcity)
|
||||||
|
VETARGS?=-asmdecl -atomic -bool -buildtags -copylocks -methods -nilfunc -printf -rangeloops -shift -structtags -unsafeptr
|
||||||
|
EXTERNAL_TOOLS=\
|
||||||
|
github.com/mitchellh/gox
|
||||||
|
BUILD_TAGS?=${TOOL}
|
||||||
|
GOFMT_FILES?=$$(find . -name '*.go' | grep -v vendor)
|
||||||
|
|
||||||
|
# bin generates the releaseable binaries for this plugin
|
||||||
|
bin: fmtcheck generate
|
||||||
|
@CGO_ENABLED=0 BUILD_TAGS='$(BUILD_TAGS)' sh -c "'$(CURDIR)/scripts/build.sh'"
|
||||||
|
|
||||||
|
default: dev
|
||||||
|
|
||||||
|
# dev creates binaries for testing Vault locally. These are put
|
||||||
|
# into ./bin/ as well as $GOPATH/bin.
|
||||||
|
dev: fmtcheck generate
|
||||||
|
@CGO_ENABLED=0 BUILD_TAGS='$(BUILD_TAGS)' VAULT_DEV_BUILD=1 sh -c "'$(CURDIR)/scripts/build.sh'"
|
||||||
|
|
||||||
|
# testshort runs the quick unit tests and vets the code
|
||||||
|
testshort: fmtcheck generate
|
||||||
|
CGO_ENABLED=0 VAULT_TOKEN= VAULT_ACC= go test -short -tags='$(BUILD_TAGS)' $(TEST) $(TESTARGS) -count=1 -timeout=20m -parallel=4
|
||||||
|
|
||||||
|
# test runs the unit tests and vets the code
|
||||||
|
test: gencerts fmtcheck generate
|
||||||
|
CGO_ENABLED=0 VAULT_TOKEN= VAULT_ACC= go test ./... -v -tags='$(BUILD_TAGS)' $(TEST) $(TESTARGS) -count=1 -timeout=20m -parallel=4
|
||||||
|
|
||||||
|
testcompile: fmtcheck generate
|
||||||
|
@for pkg in $(TEST) ; do \
|
||||||
|
go test -v -c -tags='$(BUILD_TAGS)' $$pkg -parallel=4 ; \
|
||||||
|
done
|
||||||
|
|
||||||
|
# generate runs `go generate` to build the dynamically generated
|
||||||
|
# source files.
|
||||||
|
generate:
|
||||||
|
go generate $(go list ./... | grep -v /vendor/)
|
||||||
|
|
||||||
|
# bootstrap the build by downloading additional tools
|
||||||
|
bootstrap:
|
||||||
|
@for tool in $(EXTERNAL_TOOLS) ; do \
|
||||||
|
echo "Installing/Updating $$tool" ; \
|
||||||
|
go get -u $$tool; \
|
||||||
|
done
|
||||||
|
|
||||||
|
fmtcheck:
|
||||||
|
@sh -c "'$(CURDIR)/scripts/gofmtcheck.sh'"
|
||||||
|
|
||||||
|
gencerts:
|
||||||
|
@sh -c "'$(CURDIR)/scripts/generate-test-certs.sh'"
|
||||||
|
|
||||||
|
fmt:
|
||||||
|
gofmt -w $(GOFMT_FILES)
|
||||||
|
|
||||||
|
proto:
|
||||||
|
protoc *.proto --go_out=plugins=grpc:.
|
||||||
|
|
||||||
|
tools:
|
||||||
|
go install ./...
|
||||||
|
|
||||||
|
.PHONY: bin default generate test vet bootstrap fmt fmtcheck
|
||||||
228
vendor/github.com/hashicorp/vault-plugin-auth-pcf/README.md
generated
vendored
Normal file
228
vendor/github.com/hashicorp/vault-plugin-auth-pcf/README.md
generated
vendored
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
# vault-plugin-auth-pcf
|
||||||
|
|
||||||
|
This plugin leverages PCF's [App and Container Identity Assurance](https://content.pivotal.io/blog/new-in-pcf-2-1-app-container-identity-assurance-via-automatic-cert-rotation)
|
||||||
|
for authenticating to Vault.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
- `$ git clone git@github.com:hashicorp/vault-plugin-auth-pcf.git`
|
||||||
|
- `$ cd vault-plugin-auth-pcf`
|
||||||
|
- `$ PCF_HOME=$(pwd)`
|
||||||
|
- `$ make test`
|
||||||
|
- `$ make tools`
|
||||||
|
|
||||||
|
`$ make test` is run above to generate valid fake certificates in your `testdata/fake-certificates` folder.
|
||||||
|
`$ make tools` is run above to install a number of tools that have been placed here in the `cmd` directory
|
||||||
|
to make your life easier. Running the command will place them in your `$GOPATH/bin` directory.
|
||||||
|
|
||||||
|
## Sample Usage
|
||||||
|
|
||||||
|
Please note that this example uses `generate-signature`, a tool installed through `$ make tools`.
|
||||||
|
|
||||||
|
First, enable the PCF auth engine.
|
||||||
|
```
|
||||||
|
$ vault auth enable vault-plugin-auth-pcf
|
||||||
|
```
|
||||||
|
|
||||||
|
Next, configure the plugin. In the `config` call below, the `certificates` configured is intended to be the CA
|
||||||
|
certificate that has been configured as the `diego.executor.instance_identity_ca_cert` in your environment. For
|
||||||
|
instructions on configuring this, see PCF's
|
||||||
|
[Enabling Instance Identity](https://docs.cloudfoundry.org/adminguide/instance-identity.html).
|
||||||
|
|
||||||
|
In the CF Dev environment the default API address is `https://api.dev.cfdev.sh`. The default username and password
|
||||||
|
are `admin`, `admin`. In a production environment, these attributes will vary.
|
||||||
|
```
|
||||||
|
$ vault write auth/vault-plugin-auth-pcf/config \
|
||||||
|
certificates=@$PCF_HOME/testdata/fake-certificates/ca.crt \
|
||||||
|
pcf_api_addr=http://127.0.0.1:33671 \
|
||||||
|
pcf_username=username \
|
||||||
|
pcf_password=password
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, add a role that will be used to grant specific Vault policies to those logging in with it. When a constraint like
|
||||||
|
`bound_application_ids` is added, then the application ID on the cert used for logging in _must_ be one of the role's
|
||||||
|
application IDs. However, if `bound_application_ids` is omitted, then _any_ application ID will match. We recommend
|
||||||
|
configuring as many bound parameters as possible.
|
||||||
|
|
||||||
|
Also, by default, the IP address on the certificate presented at login must match that of the caller. However, if
|
||||||
|
your callers tend to be proxied, this may not work for you. If that's the case, set `disable_ip_matching` to true.
|
||||||
|
```
|
||||||
|
$ vault write auth/vault-plugin-auth-pcf/roles/test-role \
|
||||||
|
bound_application_ids=2d3e834a-3a25-4591-974c-fa5626d5d0a1 \
|
||||||
|
bound_space_ids=3d2eba6b-ef19-44d5-91dd-1975b0db5cc9 \
|
||||||
|
bound_organization_ids=34a878d0-c2f9-4521-ba73-a9f664e82c7bf \
|
||||||
|
bound_instance_ids=1bf2e7f6-2d1d-41ec-501c-c70 \
|
||||||
|
policies=foo-policies \
|
||||||
|
ttl=86400s \
|
||||||
|
max_ttl=86400s \
|
||||||
|
period=86400s
|
||||||
|
```
|
||||||
|
|
||||||
|
Logging in is intended to be performed using your `CF_INSTANCE_CERT` and `CF_INSTANCE_KEY`. This is an example of how
|
||||||
|
it can be done.
|
||||||
|
```
|
||||||
|
$ export CF_INSTANCE_CERT=$PCF_HOME/testdata/fake-certificates/instance.crt
|
||||||
|
$ export CF_INSTANCE_KEY=$PCF_HOME/testdata/fake-certificates/instance.key
|
||||||
|
$ export SIGNING_TIME=$(date -u)
|
||||||
|
$ export ROLE='test-role'
|
||||||
|
$ vault write auth/vault-plugin-auth-pcf/login \
|
||||||
|
role=$ROLE \
|
||||||
|
certificate=@$CF_INSTANCE_CERT \
|
||||||
|
signing-time="$SIGNING_TIME" \
|
||||||
|
signature=$(generate-signature)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Updating the CA Certificate
|
||||||
|
|
||||||
|
In PCF, most CA certificates expire after 4 years. However, it's possible to configure your own CA certificate for the
|
||||||
|
instance identity service, and its expiration date could vary. Either way, sometimes CA certificates expire and it may
|
||||||
|
be necessary to have multiple configured so the beginning date of once commences when another expires.
|
||||||
|
|
||||||
|
To configure multiple certificates, simply update the config to include the current one and future one.
|
||||||
|
```
|
||||||
|
$ CURRENT=$(cat /path/to/current-ca.crt)
|
||||||
|
$ FUTURE=$(cat /path/to/future-ca.crt)
|
||||||
|
$ vault write auth/vault-plugin-auth-pcf/config certificates="$CURRENT,$FUTURE"
|
||||||
|
```
|
||||||
|
|
||||||
|
All other configured values will remain untouched; however, the previous value for `certificates` will be overwritten
|
||||||
|
with the new one you've provided.
|
||||||
|
|
||||||
|
Providing a future CA certificate before the current one expires can protect you from having a downtime while the service
|
||||||
|
is switching over from the old to the new. If a client certificate was issued by _any_ CA certificate you've configured,
|
||||||
|
login will succeed.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### verify-certs
|
||||||
|
|
||||||
|
This tool, installed by `make tools`, is for verifying that your CA certificate, client certificate, and client
|
||||||
|
key are all properly related to each other and will pass verification if used by this auth engine. If you're
|
||||||
|
debugging authentication problems that may be related to your certificates, it's a fantastic tool to use.
|
||||||
|
|
||||||
|
```
|
||||||
|
verify-certs -ca-cert=local/path/to/ca.crt -instance-cert=local/path/to/instance.crt -instance-key=local/path/to/instance.key
|
||||||
|
```
|
||||||
|
The `ca-cert` should be the cert that was used to issue the given client certificate. In the CF Dev environment,
|
||||||
|
it can be obtained via `$ bosh int --path /diego_instance_identity_ca ~/.cfdev/state/bosh/creds.yml`. In a prod
|
||||||
|
environment, it should be available through the Ops Manager API.
|
||||||
|
|
||||||
|
The `instance-cert` given should be the value for the `CF_INSTANCE_CERT` variable in the PCF environment you're
|
||||||
|
using, and the `instance-key` should be the value for the `CF_INSTANCE_KEY`.
|
||||||
|
|
||||||
|
The tool does take the _local path to_ these certificates, so you'll need to gather them and place them on your
|
||||||
|
local machine to verify they all will work together.
|
||||||
|
|
||||||
|
### generate-signature
|
||||||
|
|
||||||
|
This tool, installed by `make tools`, is for generating a valid signature to be used for signing into Vault via PCF.
|
||||||
|
|
||||||
|
It can be used as a standalone tool for generating a signature like so:
|
||||||
|
```
|
||||||
|
export CF_INSTANCE_CERT=path/to/instance.crt
|
||||||
|
export CF_INSTANCE_KEY=path/to/instance.key
|
||||||
|
export SIGNING_TIME=$(date -u)
|
||||||
|
export ROLE='test-role'
|
||||||
|
generate-signature
|
||||||
|
```
|
||||||
|
|
||||||
|
It can also be used for signing into Vault like so:
|
||||||
|
```
|
||||||
|
export CF_INSTANCE_CERT=path/to/instance.crt
|
||||||
|
export CF_INSTANCE_KEY=path/to/instance.key
|
||||||
|
export SIGNING_TIME=$(date -u)
|
||||||
|
export ROLE='test-role'
|
||||||
|
|
||||||
|
vault write auth/vault-plugin-auth-pcf/login \
|
||||||
|
role=$ROLE \
|
||||||
|
certificate=$CF_INSTANCE_CERT \
|
||||||
|
signing-time=SIGNING_TIME \
|
||||||
|
signature=$(generate-signature)
|
||||||
|
```
|
||||||
|
If the tool is being run in a PCF environment already containing the `CF_INSTANCE_CERT` and `CF_INSTANCE_KEY`, those
|
||||||
|
variables obviously won't need to be manually set before the tool is used and can just be pulled as they are.
|
||||||
|
|
||||||
|
## Developing
|
||||||
|
|
||||||
|
### mock-pcf-server
|
||||||
|
|
||||||
|
This tool, installed by `make tools`, is for use in development. It lets you run a mocked PCF server for use in local
|
||||||
|
testing, with output that can be used as the `pcf_api_addr`, `pcf_username`, and `pcf_password` in your config.
|
||||||
|
|
||||||
|
Example use:
|
||||||
|
```
|
||||||
|
$ mock-pcf-server
|
||||||
|
running at http://127.0.0.1:33671
|
||||||
|
username is username
|
||||||
|
password is password
|
||||||
|
```
|
||||||
|
|
||||||
|
Simply hit CTRL+C to stop the test server.
|
||||||
|
|
||||||
|
### Implementing the Signature Algorithm in Other Languages
|
||||||
|
|
||||||
|
The signing algorithm used by this plugin is viewable in `signatures/version1.go`. There is also a test
|
||||||
|
called `TestSignature` in the same package that outputs a viewable signing string, hash of it, and
|
||||||
|
resulting signature. The signature will be different every time the test is run because some
|
||||||
|
of the input to the final signature includes cryptographically random material. This means that no matter
|
||||||
|
what you do, your final signature won't match any signatures shown; the important thing, however, is that
|
||||||
|
it can be verified as having been signed by the private key that's associated with the given client
|
||||||
|
certificate.
|
||||||
|
|
||||||
|
To develop your own version of the signing algorithm in a different language, we recommend you duplicate
|
||||||
|
the inputs to `TestSignature`, duplicate its signing string and hash, and duplicate the signing algorithm used.
|
||||||
|
|
||||||
|
### Quick Start
|
||||||
|
|
||||||
|
```
|
||||||
|
# After cloning the repo, generate fake certs, a test binary, and install the tools.
|
||||||
|
make test
|
||||||
|
make dev
|
||||||
|
make tools
|
||||||
|
|
||||||
|
# In one shell window, run Vault with the plugin available in the catalog.
|
||||||
|
vault server -dev -dev-root-token-id=root -dev-plugin-dir=$PCF_HOME/bin -log-level=debug
|
||||||
|
|
||||||
|
# In another shell window, run a mock of the PCF API so the plugin's client calls won't fail.
|
||||||
|
mock-pcf-server
|
||||||
|
|
||||||
|
# In another shell window, execute the following commands to exercise each endpoint.
|
||||||
|
export VAULT_ADDR=http://localhost:8200
|
||||||
|
export VAULT_TOKEN=root
|
||||||
|
export MOCK_PCF_SERVER_ADDR='something' # ex. http://127.0.0.1:32937
|
||||||
|
|
||||||
|
vault auth enable vault-plugin-auth-pcf
|
||||||
|
|
||||||
|
vault write auth/vault-plugin-auth-pcf/config \
|
||||||
|
certificates=@$PCF_HOME/testdata/fake-certificates/ca.crt \
|
||||||
|
pcf_api_addr=$MOCK_PCF_SERVER_ADDR \
|
||||||
|
pcf_username=username \
|
||||||
|
pcf_password=password
|
||||||
|
|
||||||
|
vault write auth/vault-plugin-auth-pcf/roles/test-role \
|
||||||
|
bound_application_ids=2d3e834a-3a25-4591-974c-fa5626d5d0a1 \
|
||||||
|
bound_space_ids=3d2eba6b-ef19-44d5-91dd-1975b0db5cc9 \
|
||||||
|
bound_organization_ids=34a878d0-c2f9-4521-ba73-a9f664e82c7bf \
|
||||||
|
bound_instance_ids=1bf2e7f6-2d1d-41ec-501c-c70 \
|
||||||
|
policies=foo,policies \
|
||||||
|
disable_ip_matching=true \
|
||||||
|
ttl=86400s \
|
||||||
|
max_ttl=86400s \
|
||||||
|
period=86400s
|
||||||
|
|
||||||
|
export CF_INSTANCE_CERT=$PCF_HOME/testdata/fake-certificates/instance.crt
|
||||||
|
export CF_INSTANCE_KEY=$PCF_HOME/testdata/fake-certificates/instance.key
|
||||||
|
export SIGNING_TIME=$(date -u)
|
||||||
|
export ROLE='test-role'
|
||||||
|
vault write auth/vault-plugin-auth-pcf/login \
|
||||||
|
role=$ROLE \
|
||||||
|
certificate=@$CF_INSTANCE_CERT \
|
||||||
|
signing_time="$SIGNING_TIME" \
|
||||||
|
signature=$(generate-signature)
|
||||||
|
|
||||||
|
vault token renew <token>
|
||||||
|
|
||||||
|
CURRENT=$(cat $PCF_HOME/testdata/fake-certificates/ca.crt)
|
||||||
|
FUTURE=$(cat $PCF_HOME/testdata/fake-certificates/ca.crt)
|
||||||
|
vault write auth/vault-plugin-auth-pcf/config certificates="$CURRENT,$FUTURE"
|
||||||
|
```
|
||||||
52
vendor/github.com/hashicorp/vault-plugin-auth-pcf/backend.go
generated
vendored
Normal file
52
vendor/github.com/hashicorp/vault-plugin-auth-pcf/backend.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
package pcf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/hashicorp/go-hclog"
|
||||||
|
"github.com/hashicorp/vault/sdk/framework"
|
||||||
|
"github.com/hashicorp/vault/sdk/logical"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// These env vars are used frequently to pull the client certificate and private key
|
||||||
|
// from PCF containers; thus are placed here for ease of discovery and use from
|
||||||
|
// outside packages.
|
||||||
|
EnvVarInstanceCertificate = "CF_INSTANCE_CERT"
|
||||||
|
EnvVarInstanceKey = "CF_INSTANCE_KEY"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) {
|
||||||
|
b := &backend{
|
||||||
|
logger: hclog.Default(),
|
||||||
|
}
|
||||||
|
b.Backend = &framework.Backend{
|
||||||
|
AuthRenew: b.pathLoginRenew,
|
||||||
|
Help: backendHelp,
|
||||||
|
PathsSpecial: &logical.Paths{
|
||||||
|
SealWrapStorage: []string{"config"},
|
||||||
|
Unauthenticated: []string{"login"},
|
||||||
|
},
|
||||||
|
Paths: []*framework.Path{
|
||||||
|
b.pathConfig(),
|
||||||
|
b.pathListRoles(),
|
||||||
|
b.pathRoles(),
|
||||||
|
b.pathLogin(),
|
||||||
|
},
|
||||||
|
BackendType: logical.TypeCredential,
|
||||||
|
}
|
||||||
|
if err := b.Setup(ctx, conf); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type backend struct {
|
||||||
|
*framework.Backend
|
||||||
|
logger hclog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
const backendHelp = `
|
||||||
|
The PCF auth backend supports logging in using PCF's identity service.
|
||||||
|
Once a CA certificate is configured, and Vault is configured to consume
|
||||||
|
PCF's API, PCF's instance identity credentials can be used to authenticate.'
|
||||||
|
`
|
||||||
115
vendor/github.com/hashicorp/vault-plugin-auth-pcf/cli.go
generated
vendored
Normal file
115
vendor/github.com/hashicorp/vault-plugin-auth-pcf/cli.go
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
package pcf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/vault-plugin-auth-pcf/signatures"
|
||||||
|
"github.com/hashicorp/vault/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CLIHandler struct{}
|
||||||
|
|
||||||
|
func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (*api.Secret, error) {
|
||||||
|
mount, ok := m["mount"]
|
||||||
|
if !ok {
|
||||||
|
mount = "pcf"
|
||||||
|
}
|
||||||
|
|
||||||
|
role := m["role"]
|
||||||
|
if role == "" {
|
||||||
|
return nil, errors.New(`"role" is required`)
|
||||||
|
}
|
||||||
|
|
||||||
|
pathToInstanceCert := m["cf_instance_cert"]
|
||||||
|
if pathToInstanceCert == "" {
|
||||||
|
pathToInstanceCert = os.Getenv(EnvVarInstanceCertificate)
|
||||||
|
}
|
||||||
|
if pathToInstanceCert == "" {
|
||||||
|
return nil, errors.New(`"cf_instance_cert" is required`)
|
||||||
|
}
|
||||||
|
|
||||||
|
pathToInstanceKey := m["cf_instance_key"]
|
||||||
|
if pathToInstanceKey == "" {
|
||||||
|
pathToInstanceKey = os.Getenv(EnvVarInstanceKey)
|
||||||
|
}
|
||||||
|
if pathToInstanceKey == "" {
|
||||||
|
return nil, errors.New(`"cf_instance_key" is required`)
|
||||||
|
}
|
||||||
|
|
||||||
|
certBytes, err := ioutil.ReadFile(pathToInstanceCert)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
certificate := string(certBytes)
|
||||||
|
|
||||||
|
signingTime := time.Now().UTC()
|
||||||
|
signatureData := &signatures.SignatureData{
|
||||||
|
SigningTime: signingTime,
|
||||||
|
Role: role,
|
||||||
|
Certificate: certificate,
|
||||||
|
}
|
||||||
|
signature, err := signatures.Sign(pathToInstanceKey, signatureData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
loginData := map[string]interface{}{
|
||||||
|
"role": role,
|
||||||
|
"certificate": certificate,
|
||||||
|
"signing_time": signingTime.Format(signatures.TimeFormat),
|
||||||
|
"signature": signature,
|
||||||
|
}
|
||||||
|
|
||||||
|
path := fmt.Sprintf("auth/%s/login", mount)
|
||||||
|
|
||||||
|
secret, err := c.Logical().Write(path, loginData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if secret == nil {
|
||||||
|
return nil, errors.New("empty response from credential provider")
|
||||||
|
}
|
||||||
|
return secret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *CLIHandler) Help() string {
|
||||||
|
help := `
|
||||||
|
Usage: vault login -method=pcf [CONFIG K=V...]
|
||||||
|
|
||||||
|
The PCF auth method allows users to authenticate using PCF's instance identity service.
|
||||||
|
|
||||||
|
The PCF credentials may be specified explicitly via the command line:
|
||||||
|
|
||||||
|
$ vault login -method=pcf role=...
|
||||||
|
|
||||||
|
This will automatically pull from the CF_INSTANCE_CERT and CF_INSTANCE_KEY values
|
||||||
|
in your local environment. If they're not available or you wish to override them,
|
||||||
|
they may also be supplied explicitly:
|
||||||
|
|
||||||
|
$ vault login -method=pcf role=... cf_instance_cert=... cf_instance_key=...
|
||||||
|
|
||||||
|
Configuration:
|
||||||
|
|
||||||
|
cf_instance_cert=<string>
|
||||||
|
Explicit value to use for the path to the PCF instance certificate.
|
||||||
|
|
||||||
|
cf_instance_key=<string>
|
||||||
|
Explicit value to use for the path to the PCF instance key.
|
||||||
|
|
||||||
|
mount=<string>
|
||||||
|
Path where the PCF credential method is mounted. This is usually provided
|
||||||
|
via the -path flag in the "vault login" command, but it can be specified
|
||||||
|
here as well. If specified here, it takes precedence over the value for
|
||||||
|
-path. The default value is "pcf".
|
||||||
|
|
||||||
|
role=<string>
|
||||||
|
Name of the role to request a token against
|
||||||
|
`
|
||||||
|
|
||||||
|
return strings.TrimSpace(help)
|
||||||
|
}
|
||||||
14
vendor/github.com/hashicorp/vault-plugin-auth-pcf/go.mod
generated
vendored
Normal file
14
vendor/github.com/hashicorp/vault-plugin-auth-pcf/go.mod
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
module github.com/hashicorp/vault-plugin-auth-pcf
|
||||||
|
|
||||||
|
go 1.12
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381
|
||||||
|
github.com/hashicorp/go-hclog v0.9.2
|
||||||
|
github.com/hashicorp/go-multierror v1.0.0
|
||||||
|
github.com/hashicorp/go-sockaddr v1.0.2
|
||||||
|
github.com/hashicorp/go-uuid v1.0.1
|
||||||
|
github.com/hashicorp/vault/api v1.0.2
|
||||||
|
github.com/hashicorp/vault/sdk v0.1.11
|
||||||
|
github.com/pkg/errors v0.8.1
|
||||||
|
)
|
||||||
168
vendor/github.com/hashicorp/vault-plugin-auth-pcf/go.sum
generated
vendored
Normal file
168
vendor/github.com/hashicorp/vault-plugin-auth-pcf/go.sum
generated
vendored
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f h1:UrKzEwTgeiff9vxdrfdqxibzpWjxLnuXDI5m6z3GJAk=
|
||||||
|
code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f/go.mod h1:sk5LnIjB/nIEU7yP5sDQExVm62wu0pBh3yrElngUisI=
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc=
|
||||||
|
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||||
|
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||||
|
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 h1:BUAU3CGlLvorLI26FmByPp2eC2qla6E1Tw+scpcg/to=
|
||||||
|
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
|
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381 h1:rdRS5BT13Iae9ssvcslol66gfOOXjaLYwqerEn/cl9s=
|
||||||
|
github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381/go.mod h1:e5+USP2j8Le2M0Jo3qKPFnNhuo1wueU4nWHCXBOfQ14=
|
||||||
|
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
|
||||||
|
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/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
|
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
|
github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
|
||||||
|
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
|
||||||
|
github.com/go-test/deep v1.0.1/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||||
|
github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||||
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||||
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||||
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||||
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||||
|
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
|
||||||
|
github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||||
|
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
|
||||||
|
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||||
|
github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0=
|
||||||
|
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||||
|
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
|
||||||
|
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||||
|
github.com/hashicorp/go-plugin v1.0.0 h1:/gQ1sNR8/LHpoxKRQq4PmLBuacfZb4tC93e9B30o/7c=
|
||||||
|
github.com/hashicorp/go-plugin v1.0.0/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.5.3 h1:QlWt0KvWT0lq8MFppF9tsJGF+ynG7ztc2KIPhzRGk7s=
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
|
||||||
|
github.com/hashicorp/go-rootcerts v1.0.0 h1:Rqb66Oo1X/eSV1x66xbDccZjhJigjg0+e82kpwzSwCI=
|
||||||
|
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||||
|
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
|
||||||
|
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0=
|
||||||
|
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
|
github.com/hashicorp/vault/api v1.0.2 h1:/V9fULvLwt58vme/6Rkt/p/GtlresQv+Z9E6dgdANhs=
|
||||||
|
github.com/hashicorp/vault/api v1.0.2/go.mod h1:AV/+M5VPDpB90arloVX0rVDUIHkONiwz5Uza9HRtpUE=
|
||||||
|
github.com/hashicorp/vault/sdk v0.1.8/go.mod h1:tHZfc6St71twLizWNHvnnbiGFo1aq0eD2jGPLtP8kAU=
|
||||||
|
github.com/hashicorp/vault/sdk v0.1.11 h1:15dSaIT8p1Yq4Ac5OnlRGBdI5Ml/cqS84ObdM23kcA0=
|
||||||
|
github.com/hashicorp/vault/sdk v0.1.11/go.mod h1:XF2Bod+ahPWGARnyFq5LfkOZwWwvveR5ptYwJLqK0ZI=
|
||||||
|
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
||||||
|
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ=
|
||||||
|
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
||||||
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
|
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11/go.mod h1:Ah2dBMoxZEqk118as2T4u4fjfXarE0pPnMJaArZQZsI=
|
||||||
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
|
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
|
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||||
|
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||||
|
github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0=
|
||||||
|
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
|
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||||
|
github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
|
||||||
|
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||||
|
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||||
|
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||||
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
|
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||||
|
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
|
||||||
|
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||||
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
|
github.com/oxtoacart/bpool v0.0.0-20150712133111-4e1c5567d7c2/go.mod h1:L3UMQOThbttwfYRNFOWLLVXMhk5Lkio4GGOtw5UrxS0=
|
||||||
|
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
|
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
|
||||||
|
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
|
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||||
|
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
|
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
|
||||||
|
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180725160413-e900ae048470/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
|
github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190130055435-99b60b757ec1 h1:VeAkjQVzKLmu+JnFcK96TPbkuaTIqwGGAzQ9hgwPjVg=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190130055435-99b60b757ec1/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/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-20190403152447-81d4e9dc473e h1:nFYrTHrdrAOpShe27kaFHjsqYSEQ0KWqdWLu3xuZJts=
|
||||||
|
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db h1:6/JqlYfC1CCaLnGceQTI+sDGhC9UBSPAsBqI0Gun6kU=
|
||||||
|
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
|
||||||
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107 h1:xtNn7qFlagY2mQNFHMSRPjT2RkOV4OXM7P5TVy9xATo=
|
||||||
|
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||||
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.19.1 h1:TrBcJ1yqAl1G++wO39nD/qtgpsW9/1+QGrluyMGEYgM=
|
||||||
|
google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
|
gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4=
|
||||||
|
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
56
vendor/github.com/hashicorp/vault-plugin-auth-pcf/models/configuration.go
generated
vendored
Normal file
56
vendor/github.com/hashicorp/vault-plugin-auth-pcf/models/configuration.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/x509"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewConfiguration is the way a Configuration is intended to be obtained. It ensures the
|
||||||
|
// given certificates are valid and prepares a CA certificate pool to be used for client
|
||||||
|
// certificate verification.
|
||||||
|
func NewConfiguration(certificates []string, pcfAPIAddr, pcfUsername, pcfPassword string) (*Configuration, error) {
|
||||||
|
config := &Configuration{
|
||||||
|
Certificates: certificates,
|
||||||
|
PCFAPIAddr: pcfAPIAddr,
|
||||||
|
PCFUsername: pcfUsername,
|
||||||
|
PCFPassword: pcfPassword,
|
||||||
|
}
|
||||||
|
pool := x509.NewCertPool()
|
||||||
|
for _, certificate := range certificates {
|
||||||
|
if ok := pool.AppendCertsFromPEM([]byte(certificate)); !ok {
|
||||||
|
return nil, fmt.Errorf("couldn't append CA certificate: %s", certificate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config.verifyOpts = &x509.VerifyOptions{Roots: pool}
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configuration is not intended to by directly instantiated; please use NewConfiguration.
|
||||||
|
type Configuration struct {
|
||||||
|
// Certificates are the CA certificates that should be used for verifying client certificates.
|
||||||
|
Certificates []string `json:"certificates"`
|
||||||
|
|
||||||
|
// PCFAPIAddr is the address of PCF's API, ex: "https://api.dev.cfdev.sh" or "http://127.0.0.1:33671"
|
||||||
|
PCFAPIAddr string `json:"pcf_api_addr"`
|
||||||
|
|
||||||
|
// The username for the PCF API.
|
||||||
|
PCFUsername string `json:"pcf_username"`
|
||||||
|
|
||||||
|
// The password for the PCF API.
|
||||||
|
PCFPassword string `json:"pcf_password"`
|
||||||
|
|
||||||
|
// verifyOpts is intentionally lower-cased so it won't be stored in JSON.
|
||||||
|
// Instead, this struct is expected to be created from NewConfiguration
|
||||||
|
// so that it'll populate this field.
|
||||||
|
verifyOpts *x509.VerifyOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyOpts returns the options that can be used for verifying client certificates,
|
||||||
|
// including the CA certificate pool.
|
||||||
|
func (c *Configuration) VerifyOpts() (x509.VerifyOptions, error) {
|
||||||
|
if c.verifyOpts == nil {
|
||||||
|
return x509.VerifyOptions{}, errors.New("verify options are unset")
|
||||||
|
}
|
||||||
|
return *c.verifyOpts, nil
|
||||||
|
}
|
||||||
98
vendor/github.com/hashicorp/vault-plugin-auth-pcf/models/pcf_cert.go
generated
vendored
Normal file
98
vendor/github.com/hashicorp/vault-plugin-auth-pcf/models/pcf_cert.go
generated
vendored
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/x509"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewPCFCertificateFromx509 converts a x509 certificate to a valid, well-formed PCF certificate,
|
||||||
|
// erroring if this isn't possible.
|
||||||
|
func NewPCFCertificateFromx509(certificate *x509.Certificate) (*PCFCertificate, error) {
|
||||||
|
if len(certificate.IPAddresses) != 1 {
|
||||||
|
return nil, fmt.Errorf("valid PCF certs have one IP address, but this has %s", certificate.IPAddresses)
|
||||||
|
}
|
||||||
|
|
||||||
|
pcfCert := &PCFCertificate{
|
||||||
|
InstanceID: certificate.Subject.CommonName,
|
||||||
|
IPAddress: certificate.IPAddresses[0],
|
||||||
|
}
|
||||||
|
|
||||||
|
spaces := 0
|
||||||
|
orgs := 0
|
||||||
|
apps := 0
|
||||||
|
for _, ou := range certificate.Subject.OrganizationalUnit {
|
||||||
|
if strings.HasPrefix(ou, "space:") {
|
||||||
|
pcfCert.SpaceID = strings.Split(ou, "space:")[1]
|
||||||
|
spaces++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(ou, "organization:") {
|
||||||
|
pcfCert.OrgID = strings.Split(ou, "organization:")[1]
|
||||||
|
orgs++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(ou, "app:") {
|
||||||
|
pcfCert.AppID = strings.Split(ou, "app:")[1]
|
||||||
|
apps++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if spaces > 1 {
|
||||||
|
return nil, fmt.Errorf("expected 1 space but received %d", spaces)
|
||||||
|
}
|
||||||
|
if orgs > 1 {
|
||||||
|
return nil, fmt.Errorf("expected 1 org but received %d", orgs)
|
||||||
|
}
|
||||||
|
if apps > 1 {
|
||||||
|
return nil, fmt.Errorf("expected 1 app but received %d", apps)
|
||||||
|
}
|
||||||
|
if err := pcfCert.validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return pcfCert, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPCFCertificateFromx509 converts the given fields to a valid, well-formed PCF certificate,
|
||||||
|
// erroring if this isn't possible.
|
||||||
|
func NewPCFCertificate(instanceID, orgID, spaceID, appID, ipAddress string) (*PCFCertificate, error) {
|
||||||
|
pcfCert := &PCFCertificate{
|
||||||
|
InstanceID: instanceID,
|
||||||
|
OrgID: orgID,
|
||||||
|
SpaceID: spaceID,
|
||||||
|
AppID: appID,
|
||||||
|
IPAddress: net.ParseIP(ipAddress),
|
||||||
|
}
|
||||||
|
if err := pcfCert.validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return pcfCert, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PCFCertificate isn't intended to be instantiated directly; but rather through one of the New
|
||||||
|
// methods, which contain logic validating that the expected fields exist.
|
||||||
|
type PCFCertificate struct {
|
||||||
|
InstanceID, OrgID, SpaceID, AppID string
|
||||||
|
IPAddress net.IP
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PCFCertificate) validate() error {
|
||||||
|
if c.InstanceID == "" {
|
||||||
|
return errors.New("no instance ID on given certificate")
|
||||||
|
}
|
||||||
|
if c.AppID == "" {
|
||||||
|
return errors.New("no app ID on given certificate")
|
||||||
|
}
|
||||||
|
if c.OrgID == "" {
|
||||||
|
return errors.New("no org ID on given certificate")
|
||||||
|
}
|
||||||
|
if c.SpaceID == "" {
|
||||||
|
return errors.New("no space ID on given certificate")
|
||||||
|
}
|
||||||
|
if c.IPAddress.IsUnspecified() {
|
||||||
|
return errors.New("ip address is unspecified")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
21
vendor/github.com/hashicorp/vault-plugin-auth-pcf/models/role.go
generated
vendored
Normal file
21
vendor/github.com/hashicorp/vault-plugin-auth-pcf/models/role.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/go-sockaddr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RoleEntry is a role as it's reflected in Vault's storage system.
|
||||||
|
type RoleEntry struct {
|
||||||
|
BoundAppIDs []string `json:"bound_application_ids"`
|
||||||
|
BoundSpaceIDs []string `json:"bound_space_ids"`
|
||||||
|
BoundOrgIDs []string `json:"bound_organization_ids"`
|
||||||
|
BoundInstanceIDs []string `json:"bound_instance_ids"`
|
||||||
|
BoundCIDRs []*sockaddr.SockAddrMarshaler `json:"bound_cidrs"`
|
||||||
|
Policies []string `json:"policies"`
|
||||||
|
DisableIPMatching bool `json:"disable_ip_matching"`
|
||||||
|
TTL time.Duration `json:"ttl"`
|
||||||
|
MaxTTL time.Duration `json:"max_ttl"`
|
||||||
|
Period time.Duration `json:"period"`
|
||||||
|
}
|
||||||
215
vendor/github.com/hashicorp/vault-plugin-auth-pcf/path_config.go
generated
vendored
Normal file
215
vendor/github.com/hashicorp/vault-plugin-auth-pcf/path_config.go
generated
vendored
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
package pcf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/cloudfoundry-community/go-cfclient"
|
||||||
|
"github.com/hashicorp/vault-plugin-auth-pcf/models"
|
||||||
|
"github.com/hashicorp/vault/sdk/framework"
|
||||||
|
"github.com/hashicorp/vault/sdk/logical"
|
||||||
|
)
|
||||||
|
|
||||||
|
const configStorageKey = "config"
|
||||||
|
|
||||||
|
func (b *backend) pathConfig() *framework.Path {
|
||||||
|
return &framework.Path{
|
||||||
|
Pattern: "config",
|
||||||
|
Fields: map[string]*framework.FieldSchema{
|
||||||
|
"certificates": {
|
||||||
|
Required: true,
|
||||||
|
Type: framework.TypeStringSlice,
|
||||||
|
Description: "The PEM-format CA certificates.",
|
||||||
|
},
|
||||||
|
"pcf_api_addr": {
|
||||||
|
Required: true,
|
||||||
|
Type: framework.TypeString,
|
||||||
|
DisplayName: "PCF API Address",
|
||||||
|
DisplayValue: "https://api.10.244.0.34.xip.io",
|
||||||
|
Description: "PCF’s API address.",
|
||||||
|
},
|
||||||
|
"pcf_username": {
|
||||||
|
Required: true,
|
||||||
|
Type: framework.TypeString,
|
||||||
|
DisplayName: "PCF API Username",
|
||||||
|
DisplayValue: "admin",
|
||||||
|
Description: "The username for PCF’s API.",
|
||||||
|
},
|
||||||
|
"pcf_password": {
|
||||||
|
Required: true,
|
||||||
|
Type: framework.TypeString,
|
||||||
|
DisplayName: "PCF API Password",
|
||||||
|
DisplayValue: "admin",
|
||||||
|
Description: "The password for PCF’s API.",
|
||||||
|
DisplaySensitive: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Operations: map[logical.Operation]framework.OperationHandler{
|
||||||
|
logical.CreateOperation: &framework.PathOperation{
|
||||||
|
Callback: b.operationConfigCreateUpdate,
|
||||||
|
},
|
||||||
|
logical.UpdateOperation: &framework.PathOperation{
|
||||||
|
Callback: b.operationConfigCreateUpdate,
|
||||||
|
},
|
||||||
|
logical.ReadOperation: &framework.PathOperation{
|
||||||
|
Callback: b.operationConfigRead,
|
||||||
|
},
|
||||||
|
logical.DeleteOperation: &framework.PathOperation{
|
||||||
|
Callback: b.operationConfigDelete,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
HelpSynopsis: pathConfigSyn,
|
||||||
|
HelpDescription: pathConfigDesc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *backend) operationConfigCreateUpdate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||||
|
config, err := config(ctx, req.Storage)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if config == nil {
|
||||||
|
// They're creating a config.
|
||||||
|
certificates := data.Get("certificates").([]string)
|
||||||
|
if len(certificates) == 0 {
|
||||||
|
return logical.ErrorResponse("'certificates' is required"), nil
|
||||||
|
}
|
||||||
|
pcfApiAddr := data.Get("pcf_api_addr").(string)
|
||||||
|
if pcfApiAddr == "" {
|
||||||
|
return logical.ErrorResponse("'pcf_api_addr' is required"), nil
|
||||||
|
}
|
||||||
|
pcfUsername := data.Get("pcf_username").(string)
|
||||||
|
if pcfUsername == "" {
|
||||||
|
return logical.ErrorResponse("'pcf_username' is required"), nil
|
||||||
|
}
|
||||||
|
pcfPassword := data.Get("pcf_password").(string)
|
||||||
|
if pcfPassword == "" {
|
||||||
|
return logical.ErrorResponse("'pcf_password' is required"), nil
|
||||||
|
}
|
||||||
|
config, err = models.NewConfiguration(certificates, pcfApiAddr, pcfUsername, pcfPassword)
|
||||||
|
if err != nil {
|
||||||
|
return logical.ErrorResponse(err.Error()), nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// They're updating a config. Only update the fields that have been sent in the call.
|
||||||
|
if raw, ok := data.GetOk("certificates"); ok {
|
||||||
|
switch v := raw.(type) {
|
||||||
|
case []interface{}:
|
||||||
|
certificates := make([]string, len(v))
|
||||||
|
for _, certificateIfc := range v {
|
||||||
|
certificate, ok := certificateIfc.(string)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
certificates = append(certificates, certificate)
|
||||||
|
}
|
||||||
|
config.Certificates = certificates
|
||||||
|
case string:
|
||||||
|
config.Certificates = []string{v}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if raw, ok := data.GetOk("pcf_api_addr"); ok {
|
||||||
|
config.PCFAPIAddr = raw.(string)
|
||||||
|
}
|
||||||
|
if raw, ok := data.GetOk("pcf_username"); ok {
|
||||||
|
config.PCFUsername = raw.(string)
|
||||||
|
}
|
||||||
|
if raw, ok := data.GetOk("pcf_password"); ok {
|
||||||
|
config.PCFPassword = raw.(string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// To give early and explicit feedback, make sure the config works by executing a test call
|
||||||
|
// and checking that the API version is supported. If they don't have API v2 running, we would
|
||||||
|
// probably expect a timeout of some sort below because it's first called in the NewClient
|
||||||
|
// method.
|
||||||
|
client, err := cfclient.NewClient(&cfclient.Config{
|
||||||
|
ApiAddress: config.PCFAPIAddr,
|
||||||
|
Username: config.PCFUsername,
|
||||||
|
Password: config.PCFPassword,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to establish an initial connection to the PCF API: %s", err)
|
||||||
|
}
|
||||||
|
info, err := client.GetInfo()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !strings.HasPrefix(info.APIVersion, "2.") {
|
||||||
|
return nil, fmt.Errorf("the PCF auth plugin only supports version 2.X.X of the PCF API")
|
||||||
|
}
|
||||||
|
|
||||||
|
entry, err := logical.StorageEntryJSON(configStorageKey, config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := req.Storage.Put(ctx, entry); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *backend) operationConfigRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||||
|
config, err := config(ctx, req.Storage)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if config == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return &logical.Response{
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
"certificates": config.Certificates,
|
||||||
|
"pcf_api_addr": config.PCFAPIAddr,
|
||||||
|
"pcf_username": config.PCFUsername,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *backend) operationConfigDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||||
|
if err := req.Storage.Delete(ctx, configStorageKey); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// storedConfig may return nil without error if the user doesn't currently have a config.
|
||||||
|
func config(ctx context.Context, storage logical.Storage) (*models.Configuration, error) {
|
||||||
|
entry, err := storage.Get(ctx, configStorageKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if entry == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
configMap := make(map[string]interface{})
|
||||||
|
if err := entry.DecodeJSON(&configMap); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var certificates []string
|
||||||
|
certificatesIfc := configMap["certificates"].([]interface{})
|
||||||
|
for _, certificateIfc := range certificatesIfc {
|
||||||
|
certificates = append(certificates, certificateIfc.(string))
|
||||||
|
}
|
||||||
|
config, err := models.NewConfiguration(
|
||||||
|
certificates,
|
||||||
|
configMap["pcf_api_addr"].(string),
|
||||||
|
configMap["pcf_username"].(string),
|
||||||
|
configMap["pcf_password"].(string),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const pathConfigSyn = `
|
||||||
|
Provide Vault with the CA certificate used to issue all client certificates.
|
||||||
|
`
|
||||||
|
|
||||||
|
const pathConfigDesc = `
|
||||||
|
When a login is attempted using a PCF client certificate, Vault will verify
|
||||||
|
that the client certificate was issued by the CA certificate configured here.
|
||||||
|
Only those passing this check will be able to gain authorization.
|
||||||
|
`
|
||||||
396
vendor/github.com/hashicorp/vault-plugin-auth-pcf/path_login.go
generated
vendored
Normal file
396
vendor/github.com/hashicorp/vault-plugin-auth-pcf/path_login.go
generated
vendored
Normal file
@@ -0,0 +1,396 @@
|
|||||||
|
package pcf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/hashicorp/vault/sdk/helper/strutil"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/cloudfoundry-community/go-cfclient"
|
||||||
|
"github.com/hashicorp/vault-plugin-auth-pcf/models"
|
||||||
|
"github.com/hashicorp/vault-plugin-auth-pcf/signatures"
|
||||||
|
"github.com/hashicorp/vault-plugin-auth-pcf/util"
|
||||||
|
"github.com/hashicorp/vault/sdk/framework"
|
||||||
|
"github.com/hashicorp/vault/sdk/helper/cidrutil"
|
||||||
|
"github.com/hashicorp/vault/sdk/logical"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (b *backend) pathLogin() *framework.Path {
|
||||||
|
return &framework.Path{
|
||||||
|
Pattern: "login",
|
||||||
|
Fields: map[string]*framework.FieldSchema{
|
||||||
|
"role": {
|
||||||
|
Required: true,
|
||||||
|
Type: framework.TypeString,
|
||||||
|
DisplayName: "Role Name",
|
||||||
|
DisplayValue: "internally-defined-role",
|
||||||
|
Description: "The name of the role to authenticate against.",
|
||||||
|
},
|
||||||
|
"certificate": {
|
||||||
|
Required: true,
|
||||||
|
Type: framework.TypeString,
|
||||||
|
DisplayName: "Client Certificate",
|
||||||
|
Description: "The full client certificate available at the CF_INSTANCE_CERT path on the PCF instance.",
|
||||||
|
},
|
||||||
|
"signing_time": {
|
||||||
|
Required: true,
|
||||||
|
Type: framework.TypeString,
|
||||||
|
DisplayName: "Signing Time",
|
||||||
|
DisplayValue: "2006-01-02T15:04:05Z",
|
||||||
|
Description: "The date and time used to construct the signature.",
|
||||||
|
},
|
||||||
|
"signature": {
|
||||||
|
Required: true,
|
||||||
|
Type: framework.TypeString,
|
||||||
|
DisplayName: "Signature",
|
||||||
|
Description: "The signature generated by the client certificate's private key.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Operations: map[logical.Operation]framework.OperationHandler{
|
||||||
|
logical.UpdateOperation: &framework.PathOperation{
|
||||||
|
Callback: b.operationLoginUpdate,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
HelpSynopsis: pathLoginSyn,
|
||||||
|
HelpDescription: pathLoginDesc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// operationLoginUpdate is called by those wanting to gain access to Vault.
|
||||||
|
// They present a client certificate that should have been issued by the pre-configured
|
||||||
|
// Certificate Authority, and a signature that should have been signed by the client cert's
|
||||||
|
// private key. If this holds true, there are additional checks verifying everything looks
|
||||||
|
// good before authentication is given.
|
||||||
|
func (b *backend) operationLoginUpdate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||||
|
// Grab the time immediately for checking against the request's signingTime.
|
||||||
|
timeReceived := time.Now().UTC()
|
||||||
|
|
||||||
|
roleName := data.Get("role").(string)
|
||||||
|
if roleName == "" {
|
||||||
|
return logical.ErrorResponse("'role-name' is required"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
signature := data.Get("signature").(string)
|
||||||
|
if signature == "" {
|
||||||
|
return logical.ErrorResponse("'signature' is required"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
clientCertificate := data.Get("certificate").(string)
|
||||||
|
if clientCertificate == "" {
|
||||||
|
return logical.ErrorResponse("'certificate' is required"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
signingTimeRaw := data.Get("signing_time").(string)
|
||||||
|
if signingTimeRaw == "" {
|
||||||
|
return logical.ErrorResponse("'signing_time' is required"), nil
|
||||||
|
}
|
||||||
|
signingTime, err := parseTime(signingTimeRaw)
|
||||||
|
if err != nil {
|
||||||
|
return logical.ErrorResponse(err.Error()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the time it was signed is no more than 5 minutes in the past
|
||||||
|
// or 30 seconds in the future. This is a guard against some replay attacks.
|
||||||
|
fiveMinutesAgo := timeReceived.Add(time.Minute * time.Duration(-5))
|
||||||
|
thirtySecondsFromNow := timeReceived.Add(time.Second * time.Duration(30))
|
||||||
|
if signingTime.Before(fiveMinutesAgo) {
|
||||||
|
return logical.ErrorResponse(fmt.Sprintf("request is too old; signed at %s but received request at %s; raw signing time is %s", signingTime, timeReceived, signingTimeRaw)), nil
|
||||||
|
}
|
||||||
|
if signingTime.After(thirtySecondsFromNow) {
|
||||||
|
return logical.ErrorResponse(fmt.Sprintf("request is too far in the future; signed at %s but received request at %s; raw signing time is %s", signingTime, timeReceived, signingTimeRaw)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the private key used to create the signature matches our client
|
||||||
|
// certificate, and that it signed the same data as is presented in the body.
|
||||||
|
// This offers some protection against MITM attacks.
|
||||||
|
matchingCert, err := signatures.Verify(signature, &signatures.SignatureData{
|
||||||
|
SigningTime: signingTime,
|
||||||
|
Role: roleName,
|
||||||
|
Certificate: clientCertificate,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return logical.ErrorResponse(err.Error()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the matching certificate was actually issued by the CA configured.
|
||||||
|
// This protects against self-generated client certificates.
|
||||||
|
config, err := config(ctx, req.Storage)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if config == nil {
|
||||||
|
return nil, errors.New("no CA is configured for verifying client certificates")
|
||||||
|
}
|
||||||
|
verifyOpts, err := config.VerifyOpts()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if _, err := matchingCert.Verify(verifyOpts); err != nil {
|
||||||
|
return logical.ErrorResponse(err.Error()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read PCF's identity fields from the certificate.
|
||||||
|
pcfCert, err := models.NewPCFCertificateFromx509(matchingCert)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the pcf certificate meets the role's constraints.
|
||||||
|
role, err := getRole(ctx, req.Storage, roleName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if role == nil {
|
||||||
|
return nil, errors.New("no matching role")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := b.validate(config, role, pcfCert, req.Connection.RemoteAddr); err != nil {
|
||||||
|
return logical.ErrorResponse(err.Error()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everything checks out.
|
||||||
|
return &logical.Response{
|
||||||
|
Auth: &logical.Auth{
|
||||||
|
Period: role.Period,
|
||||||
|
Policies: role.Policies,
|
||||||
|
InternalData: map[string]interface{}{
|
||||||
|
"role": roleName,
|
||||||
|
"instance_id": pcfCert.InstanceID,
|
||||||
|
"ip_address": pcfCert.IPAddress.String(),
|
||||||
|
},
|
||||||
|
DisplayName: pcfCert.InstanceID,
|
||||||
|
LeaseOptions: logical.LeaseOptions{
|
||||||
|
Renewable: true,
|
||||||
|
TTL: role.TTL,
|
||||||
|
MaxTTL: role.MaxTTL,
|
||||||
|
},
|
||||||
|
Alias: &logical.Alias{
|
||||||
|
Name: pcfCert.AppID,
|
||||||
|
Metadata: map[string]string{
|
||||||
|
"org_id": pcfCert.OrgID,
|
||||||
|
"app_id": pcfCert.AppID,
|
||||||
|
"space_id": pcfCert.SpaceID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
BoundCIDRs: role.BoundCIDRs,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *backend) pathLoginRenew(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||||
|
config, err := config(ctx, req.Storage)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if config == nil {
|
||||||
|
return nil, errors.New("no configuration is available for reaching the PCF API")
|
||||||
|
}
|
||||||
|
|
||||||
|
roleName, err := getOrErr("role", req.Auth.InternalData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
role, err := getRole(ctx, req.Storage, roleName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if role == nil {
|
||||||
|
return nil, errors.New("no matching role")
|
||||||
|
}
|
||||||
|
|
||||||
|
instanceID, err := getOrErr("instance_id", req.Auth.InternalData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ipAddr, err := getOrErr("ip_address", req.Auth.InternalData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
orgID, err := getOrErr("org_id", req.Auth.Alias.Metadata)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
spaceID, err := getOrErr("space_id", req.Auth.Alias.Metadata)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
appID, err := getOrErr("app_id", req.Auth.Alias.Metadata)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reconstruct the certificate and ensure it still meets all constraints.
|
||||||
|
pcfCert, err := models.NewPCFCertificate(
|
||||||
|
instanceID,
|
||||||
|
orgID,
|
||||||
|
spaceID,
|
||||||
|
appID,
|
||||||
|
ipAddr,
|
||||||
|
)
|
||||||
|
if err := b.validate(config, role, pcfCert, req.Connection.RemoteAddr); err != nil {
|
||||||
|
return logical.ErrorResponse(err.Error()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &logical.Response{Auth: req.Auth}
|
||||||
|
resp.Auth.TTL = role.TTL
|
||||||
|
resp.Auth.MaxTTL = role.MaxTTL
|
||||||
|
resp.Auth.Period = role.Period
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *backend) validate(config *models.Configuration, role *models.RoleEntry, pcfCert *models.PCFCertificate, reqConnRemoteAddr string) error {
|
||||||
|
if !role.DisableIPMatching {
|
||||||
|
if !matchesIPAddress(reqConnRemoteAddr, pcfCert.IPAddress) {
|
||||||
|
return errors.New("no matching IP address")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !meetsBoundConstraints(pcfCert.InstanceID, role.BoundInstanceIDs) {
|
||||||
|
return fmt.Errorf("instance ID %s doesn't match role constraints of %s", pcfCert.InstanceID, role.BoundInstanceIDs)
|
||||||
|
}
|
||||||
|
if !meetsBoundConstraints(pcfCert.AppID, role.BoundAppIDs) {
|
||||||
|
return fmt.Errorf("app ID %s doesn't match role constraints of %s", pcfCert.AppID, role.BoundAppIDs)
|
||||||
|
}
|
||||||
|
if !meetsBoundConstraints(pcfCert.OrgID, role.BoundOrgIDs) {
|
||||||
|
return fmt.Errorf("org ID %s doesn't match role constraints of %s", pcfCert.OrgID, role.BoundOrgIDs)
|
||||||
|
}
|
||||||
|
if !meetsBoundConstraints(pcfCert.SpaceID, role.BoundSpaceIDs) {
|
||||||
|
return fmt.Errorf("space ID %s doesn't match role constraints of %s", pcfCert.SpaceID, role.BoundSpaceIDs)
|
||||||
|
}
|
||||||
|
if !cidrutil.RemoteAddrIsOk(reqConnRemoteAddr, role.BoundCIDRs) {
|
||||||
|
return fmt.Errorf("remote address %s doesn't match role constraints of %s", reqConnRemoteAddr, role.BoundCIDRs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the PCF API to ensure everything still exists and to verify whatever we can.
|
||||||
|
client, err := cfclient.NewClient(&cfclient.Config{
|
||||||
|
ApiAddress: config.PCFAPIAddr,
|
||||||
|
Username: config.PCFUsername,
|
||||||
|
Password: config.PCFPassword,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check everything we can using the instance ID.
|
||||||
|
serviceInstance, err := client.GetServiceInstanceByGuid(pcfCert.InstanceID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if serviceInstance.Guid != pcfCert.InstanceID {
|
||||||
|
return fmt.Errorf("cert instance ID %s doesn't match API's expected one of %s", pcfCert.InstanceID, serviceInstance.Guid)
|
||||||
|
}
|
||||||
|
if serviceInstance.SpaceGuid != pcfCert.SpaceID {
|
||||||
|
return fmt.Errorf("cert space ID %s doesn't match API's expected one of %s", pcfCert.SpaceID, serviceInstance.SpaceGuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check everything we can using the app ID.
|
||||||
|
app, err := client.AppByGuid(pcfCert.AppID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if app.Guid != pcfCert.AppID {
|
||||||
|
return fmt.Errorf("cert app ID %s doesn't match API's expected one of %s", pcfCert.AppID, app.Guid)
|
||||||
|
}
|
||||||
|
if app.SpaceGuid != pcfCert.SpaceID {
|
||||||
|
return fmt.Errorf("cert space ID %s doesn't match API's expected one of %s", pcfCert.SpaceID, app.SpaceGuid)
|
||||||
|
}
|
||||||
|
if app.Instances <= 0 {
|
||||||
|
return errors.New("app doesn't have any live instances")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check everything we can using the org ID.
|
||||||
|
org, err := client.GetOrgByGuid(pcfCert.OrgID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if org.Guid != pcfCert.OrgID {
|
||||||
|
return fmt.Errorf("cert org ID %s doesn't match API's expected one of %s", pcfCert.OrgID, org.Guid)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check everything we can using the space ID.
|
||||||
|
space, err := client.GetSpaceByGuid(pcfCert.SpaceID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if space.Guid != pcfCert.SpaceID {
|
||||||
|
return fmt.Errorf("cert space ID %s doesn't match API's expected one of %s", pcfCert.SpaceID, space.Guid)
|
||||||
|
}
|
||||||
|
if space.OrganizationGuid != pcfCert.OrgID {
|
||||||
|
return fmt.Errorf("cert org ID %s doesn't match API's expected one of %s", pcfCert.OrgID, space.OrganizationGuid)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func meetsBoundConstraints(certValue string, constraints []string) bool {
|
||||||
|
if len(constraints) == 0 {
|
||||||
|
// There are no restrictions, so everything passes this check.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// Check whether we have a match.
|
||||||
|
return strutil.StrListContains(constraints, certValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func matchesIPAddress(remoteAddr string, certIP net.IP) bool {
|
||||||
|
// Some remote addresses may arrive like "10.255.181.105/32"
|
||||||
|
// but the certificate will only have the IP address without
|
||||||
|
// the subnet mask, so that's what we want to match against.
|
||||||
|
// For those wanting to also match the subnet, use bound_cidrs.
|
||||||
|
parts := strings.Split(remoteAddr, "/")
|
||||||
|
reqIPAddr := net.ParseIP(parts[0])
|
||||||
|
if certIP.Equal(reqIPAddr) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try parsing this as ISO 8601 AND the way that is default provided by Bash to make it easier to give via the CLI as well.
|
||||||
|
func parseTime(signingTime string) (time.Time, error) {
|
||||||
|
if signingTime, err := time.Parse(signatures.TimeFormat, signingTime); err == nil {
|
||||||
|
return signingTime, nil
|
||||||
|
}
|
||||||
|
if signingTime, err := time.Parse(util.BashTimeFormat, signingTime); err == nil {
|
||||||
|
return signingTime, nil
|
||||||
|
}
|
||||||
|
return time.Time{}, fmt.Errorf("couldn't parse %s", signingTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getOrErr is a convenience method for pulling a string from a map.
|
||||||
|
func getOrErr(fieldName string, from interface{}) (string, error) {
|
||||||
|
switch givenMap := from.(type) {
|
||||||
|
case map[string]interface{}:
|
||||||
|
vIfc, ok := givenMap[fieldName]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("unable to retrieve %q during renewal", fieldName)
|
||||||
|
}
|
||||||
|
v, ok := vIfc.(string)
|
||||||
|
if v == "" {
|
||||||
|
return "", fmt.Errorf("unable to retrieve %q during renewal, not a string", fieldName)
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
case map[string]string:
|
||||||
|
v, ok := givenMap[fieldName]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("unable to retrieve %q during renewal", fieldName)
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
default:
|
||||||
|
return "", fmt.Errorf("unrecognized type for structure containing %s", fieldName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const pathLoginSyn = `
|
||||||
|
Authenticates an entity with Vault.
|
||||||
|
`
|
||||||
|
|
||||||
|
const pathLoginDesc = `
|
||||||
|
Authenticate PCF entities using a client certificate issued by the
|
||||||
|
configured Certificate Authority, and signed by a client key belonging
|
||||||
|
to the client certificate.
|
||||||
|
`
|
||||||
275
vendor/github.com/hashicorp/vault-plugin-auth-pcf/path_roles.go
generated
vendored
Normal file
275
vendor/github.com/hashicorp/vault-plugin-auth-pcf/path_roles.go
generated
vendored
Normal file
@@ -0,0 +1,275 @@
|
|||||||
|
package pcf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/vault-plugin-auth-pcf/models"
|
||||||
|
"github.com/hashicorp/vault/sdk/framework"
|
||||||
|
"github.com/hashicorp/vault/sdk/helper/parseutil"
|
||||||
|
"github.com/hashicorp/vault/sdk/logical"
|
||||||
|
)
|
||||||
|
|
||||||
|
const roleStoragePrefix = "roles/"
|
||||||
|
|
||||||
|
func (b *backend) pathListRoles() *framework.Path {
|
||||||
|
return &framework.Path{
|
||||||
|
Pattern: "roles/?$",
|
||||||
|
Operations: map[logical.Operation]framework.OperationHandler{
|
||||||
|
logical.ListOperation: &framework.PathOperation{
|
||||||
|
Callback: b.operationRolesList,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
HelpSynopsis: pathListRolesHelpSyn,
|
||||||
|
HelpDescription: pathListRolesHelpDesc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *backend) operationRolesList(ctx context.Context, req *logical.Request, _ *framework.FieldData) (*logical.Response, error) {
|
||||||
|
entries, err := req.Storage.List(ctx, roleStoragePrefix)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return logical.ListResponse(entries), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *backend) pathRoles() *framework.Path {
|
||||||
|
return &framework.Path{
|
||||||
|
Pattern: "roles/" + framework.GenericNameRegex("role"),
|
||||||
|
Fields: map[string]*framework.FieldSchema{
|
||||||
|
"role": {
|
||||||
|
Type: framework.TypeLowerCaseString,
|
||||||
|
Required: true,
|
||||||
|
Description: "The name of the role.",
|
||||||
|
},
|
||||||
|
"bound_application_ids": {
|
||||||
|
Type: framework.TypeCommaStringSlice,
|
||||||
|
DisplayName: "Bound Application IDs",
|
||||||
|
DisplayValue: "6b814521-5f08-4b1a-8c4e-fbe7c5f3a169",
|
||||||
|
Description: "Require that the client certificate presented has at least one of these app IDs.",
|
||||||
|
},
|
||||||
|
"bound_space_ids": {
|
||||||
|
Type: framework.TypeCommaStringSlice,
|
||||||
|
DisplayName: "Bound Space IDs",
|
||||||
|
DisplayValue: "3d2eba6b-ef19-44d5-91dd-1975b0db5cc9",
|
||||||
|
Description: "Require that the client certificate presented has at least one of these space IDs.",
|
||||||
|
},
|
||||||
|
"bound_organization_ids": {
|
||||||
|
Type: framework.TypeCommaStringSlice,
|
||||||
|
DisplayName: "Bound Organization IDs",
|
||||||
|
DisplayValue: "34a878d0-c2f9-4521-ba73-a9f664e82c7b",
|
||||||
|
Description: "Require that the client certificate presented has at least one of these org IDs.",
|
||||||
|
},
|
||||||
|
"bound_instance_ids": {
|
||||||
|
Type: framework.TypeCommaStringSlice,
|
||||||
|
DisplayName: "Bound Instance IDs",
|
||||||
|
DisplayValue: "8a886b31-ccf7-480d-54d8-cc28",
|
||||||
|
Description: "Require that the client certificate presented has at least one of these instance IDs.",
|
||||||
|
},
|
||||||
|
"bound_cidrs": {
|
||||||
|
Type: framework.TypeCommaStringSlice,
|
||||||
|
DisplayName: "Bound CIDRs",
|
||||||
|
DisplayValue: "192.168.100.14/24",
|
||||||
|
Description: `Comma separated string or list of CIDR blocks. If set, specifies the blocks of
|
||||||
|
IP addresses which can perform the login operation.`,
|
||||||
|
},
|
||||||
|
"policies": {
|
||||||
|
Type: framework.TypeCommaStringSlice,
|
||||||
|
Default: "default",
|
||||||
|
DisplayName: "Policies",
|
||||||
|
DisplayValue: "default",
|
||||||
|
Description: "Comma separated list of policies on the role.",
|
||||||
|
},
|
||||||
|
"disable_ip_matching": {
|
||||||
|
Type: framework.TypeBool,
|
||||||
|
Default: false,
|
||||||
|
DisplayName: "Disable IP Address Matching",
|
||||||
|
DisplayValue: "false",
|
||||||
|
Description: `If set to true, disables the default behavior that logging in must be performed from
|
||||||
|
an acceptable IP address described by the certificate presented.`,
|
||||||
|
},
|
||||||
|
"ttl": {
|
||||||
|
Type: framework.TypeDurationSecond,
|
||||||
|
Description: `Duration in seconds after which the issued token should expire. Defaults
|
||||||
|
to 0, in which case the value will fallback to the system/mount defaults.`,
|
||||||
|
},
|
||||||
|
"max_ttl": {
|
||||||
|
Type: framework.TypeDurationSecond,
|
||||||
|
Description: "The maximum allowed lifetime of tokens issued using this role.",
|
||||||
|
},
|
||||||
|
"period": {
|
||||||
|
Type: framework.TypeDurationSecond,
|
||||||
|
Default: 0,
|
||||||
|
DisplayName: "Period",
|
||||||
|
Description: `If set, indicates that the token generated using this role
|
||||||
|
should never expire. The token should be renewed within the
|
||||||
|
duration specified by this value. At each renewal, the token's
|
||||||
|
TTL will be set to the value of this parameter.`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ExistenceCheck: b.operationRolesExistenceCheck,
|
||||||
|
Operations: map[logical.Operation]framework.OperationHandler{
|
||||||
|
logical.CreateOperation: &framework.PathOperation{
|
||||||
|
Callback: b.operationRolesCreateUpdate,
|
||||||
|
},
|
||||||
|
logical.UpdateOperation: &framework.PathOperation{
|
||||||
|
Callback: b.operationRolesCreateUpdate,
|
||||||
|
},
|
||||||
|
logical.ReadOperation: &framework.PathOperation{
|
||||||
|
Callback: b.operationRolesRead,
|
||||||
|
},
|
||||||
|
logical.DeleteOperation: &framework.PathOperation{
|
||||||
|
Callback: b.operationRolesDelete,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
HelpSynopsis: pathRolesHelpSyn,
|
||||||
|
HelpDescription: pathRolesHelpDesc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *backend) operationRolesExistenceCheck(ctx context.Context, req *logical.Request, data *framework.FieldData) (bool, error) {
|
||||||
|
entry, err := req.Storage.Get(ctx, roleStoragePrefix+data.Get("role").(string))
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return entry != nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *backend) operationRolesCreateUpdate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||||
|
roleName := data.Get("role").(string)
|
||||||
|
|
||||||
|
role := &models.RoleEntry{}
|
||||||
|
if req.Operation == logical.UpdateOperation {
|
||||||
|
storedRole, err := getRole(ctx, req.Storage, roleName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if storedRole != nil {
|
||||||
|
role = storedRole
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if raw, ok := data.GetOk("bound_application_ids"); ok {
|
||||||
|
role.BoundAppIDs = raw.([]string)
|
||||||
|
}
|
||||||
|
if raw, ok := data.GetOk("bound_space_ids"); ok {
|
||||||
|
role.BoundSpaceIDs = raw.([]string)
|
||||||
|
}
|
||||||
|
if raw, ok := data.GetOk("bound_organization_ids"); ok {
|
||||||
|
role.BoundOrgIDs = raw.([]string)
|
||||||
|
}
|
||||||
|
if raw, ok := data.GetOk("bound_instance_ids"); ok {
|
||||||
|
role.BoundInstanceIDs = raw.([]string)
|
||||||
|
}
|
||||||
|
if raw, ok := data.GetOk("bound_cidrs"); ok {
|
||||||
|
parsedCIDRs, err := parseutil.ParseAddrs(raw)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
role.BoundCIDRs = parsedCIDRs
|
||||||
|
}
|
||||||
|
if raw, ok := data.GetOk("policies"); ok {
|
||||||
|
role.Policies = raw.([]string)
|
||||||
|
}
|
||||||
|
if raw, ok := data.GetOk("disable_ip_matching"); ok {
|
||||||
|
role.DisableIPMatching = raw.(bool)
|
||||||
|
}
|
||||||
|
if raw, ok := data.GetOk("ttl"); ok {
|
||||||
|
role.TTL = time.Duration(raw.(int)) * time.Second
|
||||||
|
}
|
||||||
|
if raw, ok := data.GetOk("max_ttl"); ok {
|
||||||
|
role.MaxTTL = time.Duration(raw.(int)) * time.Second
|
||||||
|
}
|
||||||
|
if raw, ok := data.GetOk("period"); ok {
|
||||||
|
role.Period = time.Duration(raw.(int)) * time.Second
|
||||||
|
}
|
||||||
|
|
||||||
|
if role.MaxTTL > 0 && role.TTL > role.MaxTTL {
|
||||||
|
return logical.ErrorResponse("ttl exceeds max_ttl"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
entry, err := logical.StorageEntryJSON(roleStoragePrefix+roleName, role)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := req.Storage.Put(ctx, entry); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if role.TTL > b.System().MaxLeaseTTL() {
|
||||||
|
resp := &logical.Response{}
|
||||||
|
resp.AddWarning(fmt.Sprintf("ttl of %d exceeds the system max ttl of %d, the latter will be used during login", role.TTL, b.System().MaxLeaseTTL()))
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *backend) operationRolesRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||||
|
roleName := data.Get("role").(string)
|
||||||
|
role, err := getRole(ctx, req.Storage, roleName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if role == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
cidrs := make([]string, len(role.BoundCIDRs))
|
||||||
|
for i, cidr := range role.BoundCIDRs {
|
||||||
|
cidrs[i] = cidr.String()
|
||||||
|
}
|
||||||
|
return &logical.Response{
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
"bound_application_ids": role.BoundAppIDs,
|
||||||
|
"bound_space_ids": role.BoundSpaceIDs,
|
||||||
|
"bound_organization_ids": role.BoundOrgIDs,
|
||||||
|
"bound_instance_ids": role.BoundInstanceIDs,
|
||||||
|
"bound_cidrs": cidrs,
|
||||||
|
"policies": role.Policies,
|
||||||
|
"disable_ip_matching": role.DisableIPMatching,
|
||||||
|
"ttl": role.TTL / time.Second,
|
||||||
|
"max_ttl": role.MaxTTL / time.Second,
|
||||||
|
"period": role.Period / time.Second,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *backend) operationRolesDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||||
|
roleName := data.Get("role").(string)
|
||||||
|
if err := req.Storage.Delete(ctx, roleStoragePrefix+roleName); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRole(ctx context.Context, storage logical.Storage, roleName string) (*models.RoleEntry, error) {
|
||||||
|
r := &models.RoleEntry{}
|
||||||
|
entry, err := storage.Get(ctx, roleStoragePrefix+roleName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if entry == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if err := entry.DecodeJSON(r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const pathListRolesHelpSyn = "List the existing roles in this backend."
|
||||||
|
|
||||||
|
const pathListRolesHelpDesc = "Roles will be listed by the role name."
|
||||||
|
|
||||||
|
const pathRolesHelpSyn = `
|
||||||
|
Read, write and reference policies and roles that tokens can be made for.
|
||||||
|
`
|
||||||
|
|
||||||
|
const pathRolesHelpDesc = `
|
||||||
|
This path allows you to read and write roles that are used to
|
||||||
|
create Vault tokens.
|
||||||
|
Once configured, credentials will be able to be obtained using this role name
|
||||||
|
if the caller can successfully provide a client certificate, and sign it
|
||||||
|
using a valid secret key. The client certificate provided must have been issued
|
||||||
|
by the configured certficate authority. Its parameters must also match anything
|
||||||
|
you've listed as "bound".
|
||||||
|
`
|
||||||
137
vendor/github.com/hashicorp/vault-plugin-auth-pcf/signatures/version1.go
generated
vendored
Normal file
137
vendor/github.com/hashicorp/vault-plugin-auth-pcf/signatures/version1.go
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
package signatures
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/sha256"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/pem"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/go-multierror"
|
||||||
|
)
|
||||||
|
|
||||||
|
const TimeFormat = "2006-01-02T15:04:05Z"
|
||||||
|
|
||||||
|
type SignatureData struct {
|
||||||
|
SigningTime time.Time
|
||||||
|
Role string
|
||||||
|
Certificate string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SignatureData) hash() []byte {
|
||||||
|
sum := sha256.Sum256([]byte(s.toSign()))
|
||||||
|
return sum[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SignatureData) toSign() string {
|
||||||
|
toHash := ""
|
||||||
|
for _, field := range []string{s.SigningTime.UTC().Format(TimeFormat), s.Certificate, s.Role} {
|
||||||
|
toHash += field
|
||||||
|
}
|
||||||
|
return toHash
|
||||||
|
}
|
||||||
|
|
||||||
|
func Sign(pathToPrivateKey string, signatureData *SignatureData) (string, error) {
|
||||||
|
if signatureData == nil {
|
||||||
|
return "", errors.New("signatureData must be provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
keyBytes, err := ioutil.ReadFile(pathToPrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
block, _ := pem.Decode(keyBytes)
|
||||||
|
if block == nil {
|
||||||
|
return "", fmt.Errorf("unable to decode RSA private key from %s", keyBytes)
|
||||||
|
}
|
||||||
|
rsaPrivateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
signatureBytes, err := rsa.SignPSS(rand.Reader, rsaPrivateKey, crypto.SHA256, signatureData.hash(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return base64.URLEncoding.EncodeToString(signatureBytes), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify ensures that a given signature was created by one of the private keys
|
||||||
|
// matching one of the given client certificates. It is possible for a client
|
||||||
|
// certificate string given by PCF to contain multiple certificates within its
|
||||||
|
// body, hence the looping. The matching certificate is returned and should be
|
||||||
|
// further checked to ensure it contains the app, space, and org ID, and CN;
|
||||||
|
// otherwise it would be possible to match against an injected client certificate
|
||||||
|
// to gain authentication.
|
||||||
|
func Verify(signature string, signatureData *SignatureData) (*x509.Certificate, error) {
|
||||||
|
if signatureData == nil {
|
||||||
|
return nil, errors.New("signatureData must be provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the CA certificate to verify the signature we've received.
|
||||||
|
signatureBytes, err := base64.URLEncoding.DecodeString(signature)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
certBytes := []byte(signatureData.Certificate)
|
||||||
|
var block *pem.Block
|
||||||
|
var result error
|
||||||
|
for {
|
||||||
|
block, certBytes = pem.Decode(certBytes)
|
||||||
|
if block == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
clientCerts, err := x509.ParseCertificates(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
result = multierror.Append(result, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, clientCert := range clientCerts {
|
||||||
|
publicKey, ok := clientCert.PublicKey.(*rsa.PublicKey)
|
||||||
|
if !ok {
|
||||||
|
result = multierror.Append(result, fmt.Errorf("not an rsa public key, it's a %t", clientCert.PublicKey))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := rsa.VerifyPSS(publicKey, crypto.SHA256, signatureData.hash(), signatureBytes, nil); err != nil {
|
||||||
|
result = multierror.Append(result, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Success
|
||||||
|
return clientCert, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if result == nil {
|
||||||
|
return nil, fmt.Errorf("no matching client certificate found for %s in %s", signature, signatureData.Certificate)
|
||||||
|
}
|
||||||
|
return nil, result
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsIssuer(pathToCACert string, clientCert *x509.Certificate) (bool, error) {
|
||||||
|
caCertBytes, err := ioutil.ReadFile(pathToCACert)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pool := x509.NewCertPool()
|
||||||
|
if ok := pool.AppendCertsFromPEM(caCertBytes); !ok {
|
||||||
|
return false, errors.New("couldn't append CA certificates")
|
||||||
|
}
|
||||||
|
|
||||||
|
verifyOpts := x509.VerifyOptions{
|
||||||
|
Roots: pool,
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := clientCert.Verify(verifyOpts); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
// Success
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
237
vendor/github.com/hashicorp/vault-plugin-auth-pcf/testing/certificates/generate.go
generated
vendored
Normal file
237
vendor/github.com/hashicorp/vault-plugin-auth-pcf/testing/certificates/generate.go
generated
vendored
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
package certificates
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/x509"
|
||||||
|
"crypto/x509/pkix"
|
||||||
|
"encoding/pem"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"math/big"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/go-multierror"
|
||||||
|
"github.com/hashicorp/go-uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Generate is a convenience method for testing. It creates a group of test certificates with the
|
||||||
|
// client certificate reflecting the given values. Close() should be called when done to immediately
|
||||||
|
// delete the three temporary files it has created.
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
//
|
||||||
|
// testCerts, err := certificates.Generate(...)
|
||||||
|
// if err != nil {
|
||||||
|
// ...
|
||||||
|
// }
|
||||||
|
// defer func(){
|
||||||
|
// if err := testCerts.Close(); err != nil {
|
||||||
|
// ...
|
||||||
|
// }
|
||||||
|
// }()
|
||||||
|
//
|
||||||
|
func Generate(instanceID, orgID, spaceID, appID, ipAddress string) (*TestCertificates, error) {
|
||||||
|
caCert, instanceCert, instanceKey, err := generate(instanceID, orgID, spaceID, appID, ipAddress)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep a list of paths we've created so that if we fail along the way,
|
||||||
|
// we can attempt to clean them up.
|
||||||
|
var paths []string
|
||||||
|
pathToCACertificate, err := makePathTo(caCert)
|
||||||
|
if err != nil {
|
||||||
|
// No path was successfully created, so we don't need to cleanup here.
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
paths = append(paths, pathToCACertificate)
|
||||||
|
|
||||||
|
pathToInstanceCertificate, err := makePathTo(instanceCert)
|
||||||
|
if err != nil {
|
||||||
|
if cleanupErr := cleanup(paths); cleanupErr != nil {
|
||||||
|
return nil, multierror.Append(err, cleanupErr)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
paths = append(paths, pathToInstanceCertificate)
|
||||||
|
|
||||||
|
pathToInstanceKey, err := makePathTo(instanceKey)
|
||||||
|
if err != nil {
|
||||||
|
if cleanupErr := cleanup(paths); cleanupErr != nil {
|
||||||
|
return nil, multierror.Append(err, cleanupErr)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
paths = append(paths, pathToInstanceKey)
|
||||||
|
|
||||||
|
// Provide a function to be called at the end cleaning up our temporary files.
|
||||||
|
cleanup := func() error {
|
||||||
|
return cleanup(paths)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &TestCertificates{
|
||||||
|
CACertificate: caCert,
|
||||||
|
InstanceCertificate: instanceCert,
|
||||||
|
InstanceKey: instanceKey,
|
||||||
|
PathToCACertificate: pathToCACertificate,
|
||||||
|
PathToInstanceCertificate: pathToInstanceCertificate,
|
||||||
|
PathToInstanceKey: pathToInstanceKey,
|
||||||
|
cleanup: cleanup,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestCertificates struct {
|
||||||
|
CACertificate string
|
||||||
|
InstanceCertificate string
|
||||||
|
InstanceKey string
|
||||||
|
|
||||||
|
PathToCACertificate string
|
||||||
|
PathToInstanceCertificate string
|
||||||
|
PathToInstanceKey string
|
||||||
|
|
||||||
|
// cleanup contains a function that has a path to all the temporary files we made,
|
||||||
|
// and deletes them. They're all in the /tmp folder so they'll disappear on the next
|
||||||
|
// system restart anyways, but in case of repeated tests, it's best to leave nothing
|
||||||
|
// behind if possible.
|
||||||
|
cleanup func() error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *TestCertificates) Close() error {
|
||||||
|
return e.cleanup()
|
||||||
|
}
|
||||||
|
|
||||||
|
func generate(instanceID, orgID, spaceID, appID, ipAddress string) (caCert, instanceCert, instanceKey string, err error) {
|
||||||
|
caPrivateKey, err := rsa.GenerateKey(rand.Reader, 4096)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", "", err
|
||||||
|
}
|
||||||
|
template := x509.Certificate{
|
||||||
|
SerialNumber: big.NewInt(1),
|
||||||
|
Subject: pkix.Name{
|
||||||
|
Country: []string{"US"},
|
||||||
|
Province: []string{"CA"},
|
||||||
|
Organization: []string{"Testing, Inc."},
|
||||||
|
CommonName: "test-CA",
|
||||||
|
},
|
||||||
|
NotBefore: time.Now(),
|
||||||
|
NotAfter: time.Now().Add(time.Hour * 24 * 180),
|
||||||
|
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
|
||||||
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||||
|
BasicConstraintsValid: true,
|
||||||
|
IsCA: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(caPrivateKey), caPrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", "", err
|
||||||
|
}
|
||||||
|
out := &bytes.Buffer{}
|
||||||
|
pem.Encode(out, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
|
||||||
|
caCert = out.String()
|
||||||
|
out.Reset()
|
||||||
|
|
||||||
|
block, certBytes := pem.Decode([]byte(caCert))
|
||||||
|
if block == nil {
|
||||||
|
return "", "", "", errors.New("block shouldn't be nil")
|
||||||
|
}
|
||||||
|
if len(certBytes) > 0 {
|
||||||
|
return "", "", "", errors.New("there shouldn't be more bytes")
|
||||||
|
}
|
||||||
|
ca509cert, err := x509.ParseCertificate(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
template = x509.Certificate{
|
||||||
|
SerialNumber: big.NewInt(1),
|
||||||
|
Subject: pkix.Name{
|
||||||
|
Country: []string{"US"},
|
||||||
|
Province: []string{"CA"},
|
||||||
|
Organization: []string{"Cloud Foundry"},
|
||||||
|
OrganizationalUnit: []string{
|
||||||
|
fmt.Sprintf("organization:%s", orgID),
|
||||||
|
fmt.Sprintf("space:%s", spaceID),
|
||||||
|
fmt.Sprintf("app:%s", appID),
|
||||||
|
},
|
||||||
|
CommonName: instanceID,
|
||||||
|
},
|
||||||
|
NotBefore: time.Now(),
|
||||||
|
NotAfter: time.Now().Add(time.Hour * 24 * 180),
|
||||||
|
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||||
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||||
|
BasicConstraintsValid: true,
|
||||||
|
IsCA: false,
|
||||||
|
IPAddresses: []net.IP{net.ParseIP(ipAddress)},
|
||||||
|
}
|
||||||
|
|
||||||
|
clientPrivateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
derBytes, err = x509.CreateCertificate(rand.Reader, &template, ca509cert, publicKey(clientPrivateKey), caPrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
pem.Encode(out, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
|
||||||
|
instanceCert = out.String()
|
||||||
|
out.Reset()
|
||||||
|
|
||||||
|
pem.Encode(out, pemBlockForKey(clientPrivateKey))
|
||||||
|
instanceKey = out.String()
|
||||||
|
out.Reset()
|
||||||
|
|
||||||
|
return caCert, instanceCert, instanceKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func makePathTo(certOrKey string) (string, error) {
|
||||||
|
u, err := uuid.GenerateUUID()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
tmpFile, err := ioutil.TempFile("", u)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if _, err := tmpFile.Write([]byte(certOrKey)); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if err := tmpFile.Close(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return tmpFile.Name(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func publicKey(priv interface{}) interface{} {
|
||||||
|
switch k := priv.(type) {
|
||||||
|
case *rsa.PrivateKey:
|
||||||
|
return &k.PublicKey
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func pemBlockForKey(priv interface{}) *pem.Block {
|
||||||
|
switch k := priv.(type) {
|
||||||
|
case *rsa.PrivateKey:
|
||||||
|
return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanup(paths []string) error {
|
||||||
|
var result error
|
||||||
|
for i := 0; i < len(paths); i++ {
|
||||||
|
if err := os.Remove(paths[i]); err != nil {
|
||||||
|
result = multierror.Append(result, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
292
vendor/github.com/hashicorp/vault-plugin-auth-pcf/testing/pcf/mock.go
generated
vendored
Normal file
292
vendor/github.com/hashicorp/vault-plugin-auth-pcf/testing/pcf/mock.go
generated
vendored
Normal file
@@ -0,0 +1,292 @@
|
|||||||
|
package pcf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/hashicorp/go-hclog"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
AuthUsername = "username"
|
||||||
|
AuthPassword = "password"
|
||||||
|
|
||||||
|
FoundServiceGUID = "1bf2e7f6-2d1d-41ec-501c-c70"
|
||||||
|
FoundAppGUID = "2d3e834a-3a25-4591-974c-fa5626d5d0a1"
|
||||||
|
FoundOrgGUID = "34a878d0-c2f9-4521-ba73-a9f664e82c7bf"
|
||||||
|
FoundSpaceGUID = "3d2eba6b-ef19-44d5-91dd-1975b0db5cc9"
|
||||||
|
|
||||||
|
UnfoundServiceGUID = "service-id-unfound"
|
||||||
|
UnfoundAppGUID = "app-id-unfound"
|
||||||
|
UnfoundOrgID = "org-id-unfound"
|
||||||
|
UnfoundSpaceGUID = "space-id-unfound"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
testServerUrl = ""
|
||||||
|
logger = hclog.Default()
|
||||||
|
)
|
||||||
|
|
||||||
|
func MockServer(loud bool) *httptest.Server {
|
||||||
|
testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
if loud {
|
||||||
|
logger.Info(fmt.Sprintf("%+v", r))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Below, 200's are returned by default, but are included anyways for explicitness.
|
||||||
|
pathFields := strings.Split(r.URL.EscapedPath(), "/")
|
||||||
|
lastPathField := pathFields[len(pathFields)-1]
|
||||||
|
switch lastPathField {
|
||||||
|
case "token":
|
||||||
|
w.Header().Add("Content-Type", "application/json;charset=UTF-8")
|
||||||
|
w.WriteHeader(200)
|
||||||
|
w.Write([]byte(tokenResponse))
|
||||||
|
|
||||||
|
case "info":
|
||||||
|
w.WriteHeader(200)
|
||||||
|
w.Write([]byte(strings.Replace(infoResponse, "{{TEST_URL}}", testServerUrl, -1)))
|
||||||
|
|
||||||
|
case FoundServiceGUID:
|
||||||
|
w.WriteHeader(200)
|
||||||
|
w.Write([]byte(serviceInstanceResponse))
|
||||||
|
|
||||||
|
case UnfoundServiceGUID:
|
||||||
|
w.WriteHeader(404)
|
||||||
|
w.Write([]byte(unfoundServiceInstanceResponse))
|
||||||
|
|
||||||
|
case FoundAppGUID:
|
||||||
|
w.WriteHeader(200)
|
||||||
|
w.Write([]byte(appResponse))
|
||||||
|
|
||||||
|
case UnfoundAppGUID:
|
||||||
|
w.WriteHeader(404)
|
||||||
|
w.Write([]byte(unfoundAppResponse))
|
||||||
|
|
||||||
|
case FoundOrgGUID:
|
||||||
|
w.WriteHeader(200)
|
||||||
|
w.Write([]byte(orgResponse))
|
||||||
|
|
||||||
|
case UnfoundOrgID:
|
||||||
|
w.WriteHeader(404)
|
||||||
|
w.Write([]byte(unfoundOrgResponse))
|
||||||
|
|
||||||
|
case FoundSpaceGUID:
|
||||||
|
w.WriteHeader(200)
|
||||||
|
w.Write([]byte(spaceResponse))
|
||||||
|
|
||||||
|
case UnfoundSpaceGUID:
|
||||||
|
w.WriteHeader(404)
|
||||||
|
w.Write([]byte(unfoundSpaceResponse))
|
||||||
|
|
||||||
|
default:
|
||||||
|
w.WriteHeader(400)
|
||||||
|
w.Write([]byte(fmt.Sprintf("unexpected object identifier: %s", lastPathField)))
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
testServerUrl = testServer.URL
|
||||||
|
return testServer
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
tokenResponse = `{
|
||||||
|
"access_token": "eyJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vdWFhLmRldi5jZmRldi5zaC90b2tlbl9rZXlzIiwia2lkIjoia2V5LTEiLCJ0eXAiOiJKV1QifQ.eyJqdGkiOiIxM2NiMzAyYjFjNjY0MDdkOWY3MDM2YzJjMmUxZDEyMCIsInN1YiI6IjYxMWM3ZWVhLWZmZDAtNGU5OC04MmYwLWY0YjU0YWZmNmRjYiIsInNjb3BlIjpbImNsaWVudHMucmVhZCIsIm9wZW5pZCIsInJvdXRpbmcucm91dGVyX2dyb3Vwcy53cml0ZSIsInNjaW0ucmVhZCIsImNsb3VkX2NvbnRyb2xsZXIuYWRtaW4iLCJ1YWEudXNlciIsInJvdXRpbmcucm91dGVyX2dyb3Vwcy5yZWFkIiwiY2xvdWRfY29udHJvbGxlci5yZWFkIiwicGFzc3dvcmQud3JpdGUiLCJjbG91ZF9jb250cm9sbGVyLndyaXRlIiwibmV0d29yay5hZG1pbiIsImRvcHBsZXIuZmlyZWhvc2UiLCJzY2ltLndyaXRlIl0sImNsaWVudF9pZCI6ImNmIiwiY2lkIjoiY2YiLCJhenAiOiJjZiIsImdyYW50X3R5cGUiOiJwYXNzd29yZCIsInVzZXJfaWQiOiI2MTFjN2VlYS1mZmQwLTRlOTgtODJmMC1mNGI1NGFmZjZkY2IiLCJvcmlnaW4iOiJ1YWEiLCJ1c2VyX25hbWUiOiJhZG1pbiIsImVtYWlsIjoiYWRtaW4iLCJhdXRoX3RpbWUiOjE1NTgzNzUwODksInJldl9zaWciOiIxOTA1YTEzOSIsImlhdCI6MTU1ODM3NTA4OSwiZXhwIjoxNTU4Mzc1Njg5LCJpc3MiOiJodHRwczovL3VhYS5kZXYuY2ZkZXYuc2gvb2F1dGgvdG9rZW4iLCJ6aWQiOiJ1YWEiLCJhdWQiOlsic2NpbSIsImNsb3VkX2NvbnRyb2xsZXIiLCJwYXNzd29yZCIsImNmIiwiY2xpZW50cyIsInVhYSIsIm9wZW5pZCIsImRvcHBsZXIiLCJyb3V0aW5nLnJvdXRlcl9ncm91cHMiLCJuZXR3b3JrIl19.KSdNhoQSTCh_3zJPLvxeAhEyAfVTvHN1mKprHqfDJJ79WaaEsUM-mLO68QWPvBgON5dx8dOE8GaQw--xpqpqNwncb7MN8jmz_lZxgw-6oOf_O-bYJmGsaxX-ETlMLKvuqUljSC5KvB16zBkRtAP2IhQsMOV-PGdx2Lz4CqBkzALHL4MUlnaaI6Z1O-zMVhFFunpmY-mYZqaHNw_35cNohieehq1TrrqVdHCiNkNVYi7LQPS93Ow8VC6I3GFNzNr6EAjmHu9tEq3sTKAfsBg8zEWjB_25cpiWW5gL-dPhZd4KSgp3wOh1K4kpWw7NKpLnPxf7mcRH4IgNDZPJqkqAjA",
|
||||||
|
"token_type": "bearer",
|
||||||
|
"id_token": "eyJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vdWFhLmRldi5jZmRldi5zaC90b2tlbl9rZXlzIiwia2lkIjoia2V5LTEiLCJ0eXAiOiJKV1QifQ.eyJzdWIiOiI2MTFjN2VlYS1mZmQwLTRlOTgtODJmMC1mNGI1NGFmZjZkY2IiLCJhdWQiOlsiY2YiXSwiaXNzIjoiaHR0cHM6Ly91YWEuZGV2LmNmZGV2LnNoL29hdXRoL3Rva2VuIiwiZXhwIjoxNTU4Mzc1Njg5LCJpYXQiOjE1NTgzNzUwODksImFtciI6WyJwd2QiXSwiYXpwIjoiY2YiLCJzY29wZSI6WyJvcGVuaWQiXSwiZW1haWwiOiJhZG1pbiIsInppZCI6InVhYSIsIm9yaWdpbiI6InVhYSIsImp0aSI6IjEzY2IzMDJiMWM2NjQwN2Q5ZjcwMzZjMmMyZTFkMTIwIiwicHJldmlvdXNfbG9nb25fdGltZSI6MTU1ODM3NDk0NTEyMCwiZW1haWxfdmVyaWZpZWQiOnRydWUsImNsaWVudF9pZCI6ImNmIiwiY2lkIjoiY2YiLCJncmFudF90eXBlIjoicGFzc3dvcmQiLCJ1c2VyX25hbWUiOiJhZG1pbiIsInJldl9zaWciOiIxOTA1YTEzOSIsInVzZXJfaWQiOiI2MTFjN2VlYS1mZmQwLTRlOTgtODJmMC1mNGI1NGFmZjZkY2IiLCJhdXRoX3RpbWUiOjE1NTgzNzUwODl9.eOv9O17i1naYiycCwlXFu2Xh2xjBRNBagq61AX1y2Upb7ek42VFaAi92PAZN9rmcU9i3trvERen0Hv7aIottLM7U-MTKMBnHXjqr1fY5oWyWxGruWsM0T9RBu4g9dbs8hyqIh_be9KdiL4PSybChV7-RspF1kMa58OUvpgQbQhgOMMWKKODYVXeeY8z241octX_ST-5tZv_josk12sworPQbZCwA5QbUjmCNSc_fHg9xe4Ra_Wecq3hmmspHrHW8gTc6ggoWUzxbbCKo1rF2PIVHzJ_61cLaHBepax9DvhCYnSJtDjlG5lPy41dxc01dOAD-JLEaV-CigtrWntFUXQ",
|
||||||
|
"refresh_token": "eyJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vdWFhLmRldi5jZmRldi5zaC90b2tlbl9rZXlzIiwia2lkIjoia2V5LTEiLCJ0eXAiOiJKV1QifQ.eyJqdGkiOiIwOTRlYWQ0ZThiYWM0Nzk1ODJmMDI2ZmMwMjUwNTA2Yy1yIiwic3ViIjoiNjExYzdlZWEtZmZkMC00ZTk4LTgyZjAtZjRiNTRhZmY2ZGNiIiwiaWF0IjoxNTU4Mzc1MDg5LCJleHAiOjE1NjA5NjcwODksImNpZCI6ImNmIiwiY2xpZW50X2lkIjoiY2YiLCJpc3MiOiJodHRwczovL3VhYS5kZXYuY2ZkZXYuc2gvb2F1dGgvdG9rZW4iLCJ6aWQiOiJ1YWEiLCJhdWQiOlsic2NpbSIsImNsb3VkX2NvbnRyb2xsZXIiLCJwYXNzd29yZCIsImNmIiwiY2xpZW50cyIsInVhYSIsIm9wZW5pZCIsImRvcHBsZXIiLCJyb3V0aW5nLnJvdXRlcl9ncm91cHMiLCJuZXR3b3JrIl0sImdyYW50ZWRfc2NvcGVzIjpbImNsaWVudHMucmVhZCIsIm9wZW5pZCIsInJvdXRpbmcucm91dGVyX2dyb3Vwcy53cml0ZSIsInNjaW0ucmVhZCIsImNsb3VkX2NvbnRyb2xsZXIuYWRtaW4iLCJ1YWEudXNlciIsInJvdXRpbmcucm91dGVyX2dyb3Vwcy5yZWFkIiwiY2xvdWRfY29udHJvbGxlci5yZWFkIiwicGFzc3dvcmQud3JpdGUiLCJjbG91ZF9jb250cm9sbGVyLndyaXRlIiwibmV0d29yay5hZG1pbiIsImRvcHBsZXIuZmlyZWhvc2UiLCJzY2ltLndyaXRlIl0sImFtciI6WyJwd2QiXSwiYXV0aF90aW1lIjoxNTU4Mzc1MDg5LCJncmFudF90eXBlIjoicGFzc3dvcmQiLCJ1c2VyX25hbWUiOiJhZG1pbiIsIm9yaWdpbiI6InVhYSIsInVzZXJfaWQiOiI2MTFjN2VlYS1mZmQwLTRlOTgtODJmMC1mNGI1NGFmZjZkY2IiLCJyZXZfc2lnIjoiMTkwNWExMzkifQ.LFkoBtAWGL1x1bUo0ak16f-NeWpBS6NZspVwzaVhBv4xg7qxDryUayE5M2BQOGMb4tZLOU2cYyO2uu4li70u0LgJk7k3OZ0-hxKvjX4sJcoiLlJFCEsFzq_yG6iUFnA2w2kA70IQtACvAAHO--Jz0L1QGA8ebt20z7Rup0FufyDJFFevhbppzYb6AfghhnrB-yZbZU9rPq4Q8DWDTN0nMOBn05CA52NRKoj2157JXLRimEG7SZW6dhXUhdjbCvSz1WKiG6fS3fHK5ncqyQtuSqLfI0Naq1v77wfSzbvc0MB-IM4CPYc-ODhWbHFoV1z8kV6dWXm2ng7OyZe3u3A7Fw",
|
||||||
|
"expires_in": 599,
|
||||||
|
"scope": "clients.read openid routing.router_groups.write scim.read cloud_controller.admin uaa.user routing.router_groups.read cloud_controller.read password.write cloud_controller.write network.admin doppler.firehose scim.write",
|
||||||
|
"jti": "13cb302b1c66407d9f7036c2c2e1d120"
|
||||||
|
}`
|
||||||
|
|
||||||
|
infoResponse = `{
|
||||||
|
"name": "",
|
||||||
|
"build": "",
|
||||||
|
"support": "",
|
||||||
|
"version": 0,
|
||||||
|
"description": "",
|
||||||
|
"authorization_endpoint": "https://login.dev.cfdev.sh",
|
||||||
|
"token_endpoint": "{{TEST_URL}}",
|
||||||
|
"min_cli_version": null,
|
||||||
|
"min_recommended_cli_version": null,
|
||||||
|
"app_ssh_endpoint": "ssh.dev.cfdev.sh:2222",
|
||||||
|
"app_ssh_host_key_fingerprint": "96:4d:89:2d:39:18:bc:16:e1:d3:d8:44:f8:16:af:85",
|
||||||
|
"app_ssh_oauth_client": "ssh-proxy",
|
||||||
|
"doppler_logging_endpoint": "wss://doppler.dev.cfdev.sh:443",
|
||||||
|
"api_version": "2.133.0",
|
||||||
|
"osbapi_version": "2.14",
|
||||||
|
"routing_endpoint": "https://api.dev.cfdev.sh/routing",
|
||||||
|
"user": "611c7eea-ffd0-4e98-82f0-f4b54aff6dcb"
|
||||||
|
}`
|
||||||
|
|
||||||
|
serviceInstanceResponse = `{
|
||||||
|
"metadata": {
|
||||||
|
"guid": "1bf2e7f6-2d1d-41ec-501c-c70",
|
||||||
|
"url": "/v2/service_instances/1bf2e7f6-2d1d-41ec-501c-c70",
|
||||||
|
"created_at": "2016-06-08T16:41:29Z",
|
||||||
|
"updated_at": "2016-06-08T16:41:26Z"
|
||||||
|
},
|
||||||
|
"entity": {
|
||||||
|
"name": "name-1508",
|
||||||
|
"credentials": {
|
||||||
|
"creds-key-38": "creds-val-38"
|
||||||
|
},
|
||||||
|
"service_guid": "a14baddf-1ccc-5299-0152-ab9s49de4422",
|
||||||
|
"service_plan_guid": "779d2df0-9cdd-48e8-9781-ea05301cedb1",
|
||||||
|
"space_guid": "3d2eba6b-ef19-44d5-91dd-1975b0db5cc9",
|
||||||
|
"gateway_data": null,
|
||||||
|
"dashboard_url": null,
|
||||||
|
"type": "managed_service_instance",
|
||||||
|
"last_operation": {
|
||||||
|
"type": "create",
|
||||||
|
"state": "succeeded",
|
||||||
|
"description": "service broker-provided description",
|
||||||
|
"updated_at": "2016-06-08T16:41:29Z",
|
||||||
|
"created_at": "2016-06-08T16:41:29Z"
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"accounting",
|
||||||
|
"mongodb"
|
||||||
|
],
|
||||||
|
"space_url": "/v2/spaces/3d2eba6b-ef19-44d5-91dd-1975b0db5cc9",
|
||||||
|
"service_url": "/v2/services/a14baddf-1ccc-5299-0152-ab9s49de4422",
|
||||||
|
"service_plan_url": "/v2/service_plans/779d2df0-9cdd-48e8-9781-ea05301cedb1",
|
||||||
|
"service_bindings_url": "/v2/service_instances/1bf2e7f6-2d1d-41ec-501c-c70/service_bindings",
|
||||||
|
"service_keys_url": "/v2/service_instances/1bf2e7f6-2d1d-41ec-501c-c70/service_keys",
|
||||||
|
"routes_url": "/v2/service_instances/1bf2e7f6-2d1d-41ec-501c-c70/routes",
|
||||||
|
"shared_from_url": "/v2/service_instances/1bf2e7f6-2d1d-41ec-501c-c70/shared_from",
|
||||||
|
"shared_to_url": "/v2/service_instances/1bf2e7f6-2d1d-41ec-501c-c70/shared_to",
|
||||||
|
"service_instance_parameters_url": "/v2/service_instances/1bf2e7f6-2d1d-41ec-501c-c70/parameters"
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
unfoundServiceInstanceResponse = `{
|
||||||
|
"description": "The service instance could not be found: service-id-unfound",
|
||||||
|
"error_code": "CF-ServiceInstanceNotFound",
|
||||||
|
"code": 60004
|
||||||
|
}`
|
||||||
|
|
||||||
|
appResponse = `{
|
||||||
|
"metadata": {
|
||||||
|
"guid": "2d3e834a-3a25-4591-974c-fa5626d5d0a1",
|
||||||
|
"url": "/v2/apps/2d3e834a-3a25-4591-974c-fa5626d5d0a1",
|
||||||
|
"created_at": "2016-06-08T16:41:44Z",
|
||||||
|
"updated_at": "2016-06-08T16:41:44Z"
|
||||||
|
},
|
||||||
|
"entity": {
|
||||||
|
"name": "name-2401",
|
||||||
|
"production": false,
|
||||||
|
"space_guid": "3d2eba6b-ef19-44d5-91dd-1975b0db5cc9",
|
||||||
|
"stack_guid": "7e03186d-a438-4285-b3b7-c426532e1df2",
|
||||||
|
"buildpack": null,
|
||||||
|
"detected_buildpack": null,
|
||||||
|
"detected_buildpack_guid": null,
|
||||||
|
"environment_json": null,
|
||||||
|
"memory": 1024,
|
||||||
|
"instances": 1,
|
||||||
|
"disk_quota": 1024,
|
||||||
|
"state": "STOPPED",
|
||||||
|
"version": "df19a7ea-2003-4ecb-a909-e630e43f2719",
|
||||||
|
"command": null,
|
||||||
|
"console": false,
|
||||||
|
"debug": null,
|
||||||
|
"staging_task_id": null,
|
||||||
|
"package_state": "PENDING",
|
||||||
|
"health_check_http_endpoint": "",
|
||||||
|
"health_check_type": "port",
|
||||||
|
"health_check_timeout": null,
|
||||||
|
"staging_failed_reason": null,
|
||||||
|
"staging_failed_description": null,
|
||||||
|
"diego": false,
|
||||||
|
"docker_image": null,
|
||||||
|
"docker_credentials": {
|
||||||
|
"username": null,
|
||||||
|
"password": null
|
||||||
|
},
|
||||||
|
"package_updated_at": "2016-06-08T16:41:45Z",
|
||||||
|
"detected_start_command": "",
|
||||||
|
"enable_ssh": true,
|
||||||
|
"ports": null,
|
||||||
|
"space_url": "/v2/spaces/3d2eba6b-ef19-44d5-91dd-1975b0db5cc9",
|
||||||
|
"stack_url": "/v2/stacks/7e03186d-a438-4285-b3b7-c426532e1df2",
|
||||||
|
"routes_url": "/v2/apps/2d3e834a-3a25-4591-974c-fa5626d5d0a1/routes",
|
||||||
|
"events_url": "/v2/apps/2d3e834a-3a25-4591-974c-fa5626d5d0a1/events",
|
||||||
|
"service_bindings_url": "/v2/apps/2d3e834a-3a25-4591-974c-fa5626d5d0a1/service_bindings",
|
||||||
|
"route_mappings_url": "/v2/apps/2d3e834a-3a25-4591-974c-fa5626d5d0a1/route_mappings"
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
unfoundAppResponse = `{
|
||||||
|
"description": "The app could not be found: app-id-unfound",
|
||||||
|
"error_code": "CF-AppNotFound",
|
||||||
|
"code": 100004
|
||||||
|
}`
|
||||||
|
|
||||||
|
orgResponse = `{
|
||||||
|
"metadata": {
|
||||||
|
"guid": "34a878d0-c2f9-4521-ba73-a9f664e82c7bf",
|
||||||
|
"url": "/v2/organizations/34a878d0-c2f9-4521-ba73-a9f664e82c7bf",
|
||||||
|
"created_at": "2019-05-17T22:49:40Z",
|
||||||
|
"updated_at": "2019-05-17T22:49:40Z"
|
||||||
|
},
|
||||||
|
"entity": {
|
||||||
|
"name": "system",
|
||||||
|
"billing_enabled": false,
|
||||||
|
"quota_definition_guid": "b172ff20-ae6d-4a13-a554-dc22f3844fb0",
|
||||||
|
"status": "active",
|
||||||
|
"default_isolation_segment_guid": null,
|
||||||
|
"quota_definition_url": "/v2/quota_definitions/b172ff20-ae6d-4a13-a554-dc22f3844fb0",
|
||||||
|
"spaces_url": "/v2/organizations/34a878d0-c2f9-4521-ba73-a9f664e82c7bf/spaces",
|
||||||
|
"domains_url": "/v2/organizations/34a878d0-c2f9-4521-ba73-a9f664e82c7bf/domains",
|
||||||
|
"private_domains_url": "/v2/organizations/34a878d0-c2f9-4521-ba73-a9f664e82c7bf/private_domains",
|
||||||
|
"users_url": "/v2/organizations/34a878d0-c2f9-4521-ba73-a9f664e82c7bf/users",
|
||||||
|
"managers_url": "/v2/organizations/34a878d0-c2f9-4521-ba73-a9f664e82c7bf/managers",
|
||||||
|
"billing_managers_url": "/v2/organizations/34a878d0-c2f9-4521-ba73-a9f664e82c7bf/billing_managers",
|
||||||
|
"auditors_url": "/v2/organizations/34a878d0-c2f9-4521-ba73-a9f664e82c7bf/auditors",
|
||||||
|
"app_events_url": "/v2/organizations/34a878d0-c2f9-4521-ba73-a9f664e82c7bf/app_events",
|
||||||
|
"space_quota_definitions_url": "/v2/organizations/34a878d0-c2f9-4521-ba73-a9f664e82c7bf/space_quota_definitions"
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
unfoundOrgResponse = `{
|
||||||
|
"description": "The organization could not be found: org-id-unfound",
|
||||||
|
"error_code": "CF-OrganizationNotFound",
|
||||||
|
"code": 30003
|
||||||
|
}`
|
||||||
|
|
||||||
|
spaceResponse = `{
|
||||||
|
"metadata": {
|
||||||
|
"guid": "3d2eba6b-ef19-44d5-91dd-1975b0db5cc9",
|
||||||
|
"url": "/v2/spaces/3d2eba6b-ef19-44d5-91dd-1975b0db5cc9",
|
||||||
|
"created_at": "2019-05-17T22:53:30Z",
|
||||||
|
"updated_at": "2019-05-17T22:53:30Z"
|
||||||
|
},
|
||||||
|
"entity": {
|
||||||
|
"name": "cfdev-space",
|
||||||
|
"organization_guid": "34a878d0-c2f9-4521-ba73-a9f664e82c7bf",
|
||||||
|
"space_quota_definition_guid": null,
|
||||||
|
"isolation_segment_guid": null,
|
||||||
|
"allow_ssh": true,
|
||||||
|
"organization_url": "/v2/organizations/34a878d0-c2f9-4521-ba73-a9f664e82c7bf",
|
||||||
|
"developers_url": "/v2/spaces/3d2eba6b-ef19-44d5-91dd-1975b0db5cc9/developers",
|
||||||
|
"managers_url": "/v2/spaces/3d2eba6b-ef19-44d5-91dd-1975b0db5cc9/managers",
|
||||||
|
"auditors_url": "/v2/spaces/3d2eba6b-ef19-44d5-91dd-1975b0db5cc9/auditors",
|
||||||
|
"apps_url": "/v2/spaces/3d2eba6b-ef19-44d5-91dd-1975b0db5cc9/apps",
|
||||||
|
"routes_url": "/v2/spaces/3d2eba6b-ef19-44d5-91dd-1975b0db5cc9/routes",
|
||||||
|
"domains_url": "/v2/spaces/3d2eba6b-ef19-44d5-91dd-1975b0db5cc9/domains",
|
||||||
|
"service_instances_url": "/v2/spaces/3d2eba6b-ef19-44d5-91dd-1975b0db5cc9/service_instances",
|
||||||
|
"app_events_url": "/v2/spaces/3d2eba6b-ef19-44d5-91dd-1975b0db5cc9/app_events",
|
||||||
|
"events_url": "/v2/spaces/3d2eba6b-ef19-44d5-91dd-1975b0db5cc9/events",
|
||||||
|
"security_groups_url": "/v2/spaces/3d2eba6b-ef19-44d5-91dd-1975b0db5cc9/security_groups",
|
||||||
|
"staging_security_groups_url": "/v2/spaces/3d2eba6b-ef19-44d5-91dd-1975b0db5cc9/staging_security_groups"
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
unfoundSpaceResponse = `{
|
||||||
|
"description": "The app space could not be found: space-id-unfound",
|
||||||
|
"error_code": "CF-SpaceNotFound",
|
||||||
|
"code": 40004
|
||||||
|
}`
|
||||||
|
)
|
||||||
3
vendor/github.com/hashicorp/vault-plugin-auth-pcf/util/util.go
generated
vendored
Normal file
3
vendor/github.com/hashicorp/vault-plugin-auth-pcf/util/util.go
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
const BashTimeFormat = "Mon Jan 2 15:04:05 MST 2006"
|
||||||
120
vendor/golang.org/x/oauth2/clientcredentials/clientcredentials.go
generated
vendored
Normal file
120
vendor/golang.org/x/oauth2/clientcredentials/clientcredentials.go
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package clientcredentials implements the OAuth2.0 "client credentials" token flow,
|
||||||
|
// also known as the "two-legged OAuth 2.0".
|
||||||
|
//
|
||||||
|
// This should be used when the client is acting on its own behalf or when the client
|
||||||
|
// is the resource owner. It may also be used when requesting access to protected
|
||||||
|
// resources based on an authorization previously arranged with the authorization
|
||||||
|
// server.
|
||||||
|
//
|
||||||
|
// See https://tools.ietf.org/html/rfc6749#section-4.4
|
||||||
|
package clientcredentials // import "golang.org/x/oauth2/clientcredentials"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
"golang.org/x/oauth2/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config describes a 2-legged OAuth2 flow, with both the
|
||||||
|
// client application information and the server's endpoint URLs.
|
||||||
|
type Config struct {
|
||||||
|
// ClientID is the application's ID.
|
||||||
|
ClientID string
|
||||||
|
|
||||||
|
// ClientSecret is the application's secret.
|
||||||
|
ClientSecret string
|
||||||
|
|
||||||
|
// TokenURL is the resource server's token endpoint
|
||||||
|
// URL. This is a constant specific to each server.
|
||||||
|
TokenURL string
|
||||||
|
|
||||||
|
// Scope specifies optional requested permissions.
|
||||||
|
Scopes []string
|
||||||
|
|
||||||
|
// EndpointParams specifies additional parameters for requests to the token endpoint.
|
||||||
|
EndpointParams url.Values
|
||||||
|
|
||||||
|
// AuthStyle optionally specifies how the endpoint wants the
|
||||||
|
// client ID & client secret sent. The zero value means to
|
||||||
|
// auto-detect.
|
||||||
|
AuthStyle oauth2.AuthStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token uses client credentials to retrieve a token.
|
||||||
|
//
|
||||||
|
// The provided context optionally controls which HTTP client is used. See the oauth2.HTTPClient variable.
|
||||||
|
func (c *Config) Token(ctx context.Context) (*oauth2.Token, error) {
|
||||||
|
return c.TokenSource(ctx).Token()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client returns an HTTP client using the provided token.
|
||||||
|
// The token will auto-refresh as necessary.
|
||||||
|
//
|
||||||
|
// The provided context optionally controls which HTTP client
|
||||||
|
// is returned. See the oauth2.HTTPClient variable.
|
||||||
|
//
|
||||||
|
// The returned Client and its Transport should not be modified.
|
||||||
|
func (c *Config) Client(ctx context.Context) *http.Client {
|
||||||
|
return oauth2.NewClient(ctx, c.TokenSource(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TokenSource returns a TokenSource that returns t until t expires,
|
||||||
|
// automatically refreshing it as necessary using the provided context and the
|
||||||
|
// client ID and client secret.
|
||||||
|
//
|
||||||
|
// Most users will use Config.Client instead.
|
||||||
|
func (c *Config) TokenSource(ctx context.Context) oauth2.TokenSource {
|
||||||
|
source := &tokenSource{
|
||||||
|
ctx: ctx,
|
||||||
|
conf: c,
|
||||||
|
}
|
||||||
|
return oauth2.ReuseTokenSource(nil, source)
|
||||||
|
}
|
||||||
|
|
||||||
|
type tokenSource struct {
|
||||||
|
ctx context.Context
|
||||||
|
conf *Config
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token refreshes the token by using a new client credentials request.
|
||||||
|
// tokens received this way do not include a refresh token
|
||||||
|
func (c *tokenSource) Token() (*oauth2.Token, error) {
|
||||||
|
v := url.Values{
|
||||||
|
"grant_type": {"client_credentials"},
|
||||||
|
}
|
||||||
|
if len(c.conf.Scopes) > 0 {
|
||||||
|
v.Set("scope", strings.Join(c.conf.Scopes, " "))
|
||||||
|
}
|
||||||
|
for k, p := range c.conf.EndpointParams {
|
||||||
|
// Allow grant_type to be overridden to allow interoperability with
|
||||||
|
// non-compliant implementations.
|
||||||
|
if _, ok := v[k]; ok && k != "grant_type" {
|
||||||
|
return nil, fmt.Errorf("oauth2: cannot overwrite parameter %q", k)
|
||||||
|
}
|
||||||
|
v[k] = p
|
||||||
|
}
|
||||||
|
|
||||||
|
tk, err := internal.RetrieveToken(c.ctx, c.conf.ClientID, c.conf.ClientSecret, c.conf.TokenURL, v, internal.AuthStyle(c.conf.AuthStyle))
|
||||||
|
if err != nil {
|
||||||
|
if rErr, ok := err.(*internal.RetrieveError); ok {
|
||||||
|
return nil, (*oauth2.RetrieveError)(rErr)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
t := &oauth2.Token{
|
||||||
|
AccessToken: tk.AccessToken,
|
||||||
|
TokenType: tk.TokenType,
|
||||||
|
RefreshToken: tk.RefreshToken,
|
||||||
|
Expiry: tk.Expiry,
|
||||||
|
}
|
||||||
|
return t.WithExtra(tk.Raw), nil
|
||||||
|
}
|
||||||
18
vendor/modules.txt
vendored
18
vendor/modules.txt
vendored
@@ -13,6 +13,8 @@ cloud.google.com/go/internal/protostruct
|
|||||||
cloud.google.com/go/internal/testutil
|
cloud.google.com/go/internal/testutil
|
||||||
cloud.google.com/go/spanner/internal/backoff
|
cloud.google.com/go/spanner/internal/backoff
|
||||||
cloud.google.com/go/compute/metadata
|
cloud.google.com/go/compute/metadata
|
||||||
|
# code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f
|
||||||
|
code.cloudfoundry.org/gofileutils/fileutils
|
||||||
# contrib.go.opencensus.io/exporter/ocagent v0.4.12
|
# contrib.go.opencensus.io/exporter/ocagent v0.4.12
|
||||||
contrib.go.opencensus.io/exporter/ocagent
|
contrib.go.opencensus.io/exporter/ocagent
|
||||||
# github.com/Azure/azure-sdk-for-go v27.1.0+incompatible
|
# github.com/Azure/azure-sdk-for-go v27.1.0+incompatible
|
||||||
@@ -40,6 +42,8 @@ github.com/Azure/go-autorest/autorest/azure/cli
|
|||||||
github.com/DataDog/datadog-go/statsd
|
github.com/DataDog/datadog-go/statsd
|
||||||
# github.com/Jeffail/gabs v1.1.1
|
# github.com/Jeffail/gabs v1.1.1
|
||||||
github.com/Jeffail/gabs
|
github.com/Jeffail/gabs
|
||||||
|
# github.com/Masterminds/semver v1.4.2
|
||||||
|
github.com/Masterminds/semver
|
||||||
# github.com/Microsoft/go-winio v0.4.12
|
# github.com/Microsoft/go-winio v0.4.12
|
||||||
github.com/Microsoft/go-winio
|
github.com/Microsoft/go-winio
|
||||||
# github.com/NYTimes/gziphandler v1.1.1
|
# github.com/NYTimes/gziphandler v1.1.1
|
||||||
@@ -168,6 +172,8 @@ github.com/circonus-labs/circonus-gometrics/checkmgr
|
|||||||
github.com/circonus-labs/circonus-gometrics/api/config
|
github.com/circonus-labs/circonus-gometrics/api/config
|
||||||
# github.com/circonus-labs/circonusllhist v0.1.3
|
# github.com/circonus-labs/circonusllhist v0.1.3
|
||||||
github.com/circonus-labs/circonusllhist
|
github.com/circonus-labs/circonusllhist
|
||||||
|
# github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381
|
||||||
|
github.com/cloudfoundry-community/go-cfclient
|
||||||
# github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c
|
# github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c
|
||||||
github.com/cockroachdb/cockroach-go/crdb
|
github.com/cockroachdb/cockroach-go/crdb
|
||||||
# github.com/containerd/continuity v0.0.0-20181203112020-004b46473808
|
# github.com/containerd/continuity v0.0.0-20181203112020-004b46473808
|
||||||
@@ -273,7 +279,7 @@ github.com/hashicorp/errwrap
|
|||||||
github.com/hashicorp/go-cleanhttp
|
github.com/hashicorp/go-cleanhttp
|
||||||
# github.com/hashicorp/go-gcp-common v0.5.0
|
# github.com/hashicorp/go-gcp-common v0.5.0
|
||||||
github.com/hashicorp/go-gcp-common/gcputil
|
github.com/hashicorp/go-gcp-common/gcputil
|
||||||
# github.com/hashicorp/go-hclog v0.8.0
|
# github.com/hashicorp/go-hclog v0.9.2
|
||||||
github.com/hashicorp/go-hclog
|
github.com/hashicorp/go-hclog
|
||||||
# github.com/hashicorp/go-immutable-radix v1.0.0
|
# github.com/hashicorp/go-immutable-radix v1.0.0
|
||||||
github.com/hashicorp/go-immutable-radix
|
github.com/hashicorp/go-immutable-radix
|
||||||
@@ -329,6 +335,13 @@ github.com/hashicorp/vault-plugin-auth-gcp/plugin/cache
|
|||||||
github.com/hashicorp/vault-plugin-auth-jwt
|
github.com/hashicorp/vault-plugin-auth-jwt
|
||||||
# github.com/hashicorp/vault-plugin-auth-kubernetes v0.5.1
|
# github.com/hashicorp/vault-plugin-auth-kubernetes v0.5.1
|
||||||
github.com/hashicorp/vault-plugin-auth-kubernetes
|
github.com/hashicorp/vault-plugin-auth-kubernetes
|
||||||
|
# github.com/hashicorp/vault-plugin-auth-pcf v0.0.0-20190605234735-619218abcd26
|
||||||
|
github.com/hashicorp/vault-plugin-auth-pcf
|
||||||
|
github.com/hashicorp/vault-plugin-auth-pcf/signatures
|
||||||
|
github.com/hashicorp/vault-plugin-auth-pcf/models
|
||||||
|
github.com/hashicorp/vault-plugin-auth-pcf/util
|
||||||
|
github.com/hashicorp/vault-plugin-auth-pcf/testing/certificates
|
||||||
|
github.com/hashicorp/vault-plugin-auth-pcf/testing/pcf
|
||||||
# github.com/hashicorp/vault-plugin-secrets-ad v0.5.1
|
# github.com/hashicorp/vault-plugin-secrets-ad v0.5.1
|
||||||
github.com/hashicorp/vault-plugin-secrets-ad/plugin
|
github.com/hashicorp/vault-plugin-secrets-ad/plugin
|
||||||
github.com/hashicorp/vault-plugin-secrets-ad/plugin/client
|
github.com/hashicorp/vault-plugin-secrets-ad/plugin/client
|
||||||
@@ -346,7 +359,7 @@ github.com/hashicorp/vault-plugin-secrets-gcp/plugin/util
|
|||||||
github.com/hashicorp/vault-plugin-secrets-gcpkms
|
github.com/hashicorp/vault-plugin-secrets-gcpkms
|
||||||
# github.com/hashicorp/vault-plugin-secrets-kv v0.5.2-0.20190416155133-fd495225dea0
|
# github.com/hashicorp/vault-plugin-secrets-kv v0.5.2-0.20190416155133-fd495225dea0
|
||||||
github.com/hashicorp/vault-plugin-secrets-kv
|
github.com/hashicorp/vault-plugin-secrets-kv
|
||||||
# github.com/hashicorp/vault/api v1.0.1 => ./api
|
# github.com/hashicorp/vault/api v1.0.2 => ./api
|
||||||
github.com/hashicorp/vault/api
|
github.com/hashicorp/vault/api
|
||||||
# github.com/hashicorp/vault/sdk v0.1.11 => ./sdk
|
# github.com/hashicorp/vault/sdk v0.1.11 => ./sdk
|
||||||
github.com/hashicorp/vault/sdk/helper/salt
|
github.com/hashicorp/vault/sdk/helper/salt
|
||||||
@@ -640,6 +653,7 @@ golang.org/x/oauth2/internal
|
|||||||
golang.org/x/oauth2/google
|
golang.org/x/oauth2/google
|
||||||
golang.org/x/oauth2/jwt
|
golang.org/x/oauth2/jwt
|
||||||
golang.org/x/oauth2/jws
|
golang.org/x/oauth2/jws
|
||||||
|
golang.org/x/oauth2/clientcredentials
|
||||||
# golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6
|
# golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6
|
||||||
golang.org/x/sync/semaphore
|
golang.org/x/sync/semaphore
|
||||||
# golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e
|
# golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e
|
||||||
|
|||||||
Reference in New Issue
Block a user