Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
weieigao committed Dec 8, 2020
2 parents 3d3e209 + f775014 commit 43e1b80
Show file tree
Hide file tree
Showing 13 changed files with 623 additions and 26 deletions.
42 changes: 33 additions & 9 deletions bluemix/configuration/core_config/bx_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,15 @@ func (r raw) Unmarshal(bytes []byte) error {

type BXConfigData struct {
APIEndpoint string
IsPrivate bool
ConsoleEndpoint string
ConsolePrivateEndpoint string
CloudType string
CloudName string
Region string
RegionID string
IAMEndpoint string
IAMPrivateEndpoint string
IAMToken string
IAMRefreshToken string
Account models.Account
Expand All @@ -43,7 +46,7 @@ type BXConfigData struct {
Trace string
ColorEnabled string
HTTPTimeout int
CLIInfoEndpoint string
CLIInfoEndpoint string // overwrite the cli info endpoint
CheckCLIVersionDisabled bool
UsageStatsDisabled bool // deprecated: use UsageStatsEnabled
UsageStatsEnabled bool
Expand Down Expand Up @@ -154,6 +157,13 @@ func (c *bxConfig) APIEndpoint() (endpoint string) {
return
}

func (c *bxConfig) IsPrivateEndpointEnabled() (isPrivate bool) {
c.read(func() {
isPrivate = c.data.IsPrivate
})
return
}

func (c *bxConfig) HasAPIEndpoint() bool {
return c.APIEndpoint() != ""
}
Expand All @@ -165,9 +175,10 @@ func (c *bxConfig) IsSSLDisabled() (disabled bool) {
return
}

func (c *bxConfig) ConsoleEndpoint() (endpoint string) {
func (c *bxConfig) ConsoleEndpoints() (endpoints models.Endpoints) {
c.read(func() {
endpoint = c.data.ConsoleEndpoint
endpoints.PublicEndpoint = c.data.ConsoleEndpoint
endpoints.PrivateEndpoint = c.data.ConsolePrivateEndpoint
})
return
}
Expand Down Expand Up @@ -201,9 +212,10 @@ func (c *bxConfig) CloudType() (ctype string) {
return
}

func (c *bxConfig) IAMEndpoint() (endpoint string) {
func (c *bxConfig) IAMEndpoints() (endpoints models.Endpoints) {
c.read(func() {
endpoint = c.data.IAMEndpoint
endpoints.PublicEndpoint = c.data.IAMEndpoint
endpoints.PrivateEndpoint = c.data.IAMPrivateEndpoint
})
return
}
Expand Down Expand Up @@ -419,9 +431,16 @@ func (c *bxConfig) SetAPIEndpoint(endpoint string) {
})
}

func (c *bxConfig) SetConsoleEndpoint(endpoint string) {
func (c *bxConfig) SetPrivateEndpointEnabled(isPrivate bool) {
c.write(func() {
c.data.IsPrivate = isPrivate
})
}

func (c *bxConfig) SetConsoleEndpoints(endpoint models.Endpoints) {
c.write(func() {
c.data.ConsoleEndpoint = endpoint
c.data.ConsoleEndpoint = endpoint.PublicEndpoint
c.data.ConsolePrivateEndpoint = endpoint.PrivateEndpoint
})
}

Expand All @@ -432,9 +451,10 @@ func (c *bxConfig) SetRegion(region models.Region) {
})
}

func (c *bxConfig) SetIAMEndpoint(endpoint string) {
func (c *bxConfig) SetIAMEndpoints(endpoints models.Endpoints) {
c.write(func() {
c.data.IAMEndpoint = endpoint
c.data.IAMEndpoint = endpoints.PublicEndpoint
c.data.IAMPrivateEndpoint = endpoints.PrivateEndpoint
})
}

Expand Down Expand Up @@ -600,10 +620,14 @@ func (c *bxConfig) ClearSession() {
func (c *bxConfig) UnsetAPI() {
c.write(func() {
c.data.APIEndpoint = ""
c.data.SSLDisabled = false
c.data.IsPrivate = false
c.data.Region = ""
c.data.RegionID = ""
c.data.ConsoleEndpoint = ""
c.data.ConsolePrivateEndpoint = ""
c.data.IAMEndpoint = ""
c.data.IAMPrivateEndpoint = ""
c.data.CloudName = ""
c.data.CloudType = ""
})
Expand Down
7 changes: 7 additions & 0 deletions bluemix/configuration/core_config/cf_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,13 @@ func (c *cfConfig) APIEndpoint() (endpoint string) {
return
}

func (c *cfConfig) AsyncTimeout() (timeout uint) {
c.read(func() {
timeout = c.data.AsyncTimeout
})
return
}

func (c *cfConfig) HasAPIEndpoint() (hasEndpoint bool) {
c.read(func() {
hasEndpoint = c.data.APIVersion != "" && c.data.Target != ""
Expand Down
14 changes: 10 additions & 4 deletions bluemix/configuration/core_config/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import (
type Repository interface {
APIEndpoint() string
HasAPIEndpoint() bool
ConsoleEndpoint() string
IAMEndpoint() string
IsPrivateEndpointEnabled() bool
ConsoleEndpoints() models.Endpoints
IAMEndpoints() models.Endpoints
CloudName() string
CloudType() string
CurrentRegion() models.Region
Expand Down Expand Up @@ -57,8 +58,9 @@ type Repository interface {

UnsetAPI()
SetAPIEndpoint(string)
SetConsoleEndpoint(string)
SetIAMEndpoint(string)
SetPrivateEndpointEnabled(bool)
SetConsoleEndpoints(models.Endpoints)
SetIAMEndpoints(models.Endpoints)
SetCloudType(string)
SetCloudName(string)
SetRegion(models.Region)
Expand Down Expand Up @@ -103,6 +105,8 @@ type ReadWriter interface {
type CFConfig interface {
APIVersion() string
APIEndpoint() string
AsyncTimeout() uint
ColorEnabled() string
HasAPIEndpoint() bool
AuthenticationEndpoint() string
UAAEndpoint() string
Expand All @@ -114,9 +118,11 @@ type CFConfig interface {
Username() string
UserGUID() string
UserEmail() string
Locale() string
LoginAt() time.Time
IsLoggedIn() bool
SetLoginAt(loginAt time.Time)
Trace() string
UAAToken() string
UAARefreshToken() string
CurrentOrganization() models.OrganizationFields
Expand Down
89 changes: 89 additions & 0 deletions bluemix/endpoints/endpoints.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package endpoints

import (
"fmt"
"strings"

"github.com/IBM-Cloud/ibm-cloud-cli-sdk/bluemix/models"
)

type Service string

const (
GlobalSearch Service = "global-search"
GlobalTagging Service = "global-tagging"
AccountManagement Service = "account-management"
UserManagement Service = "user-management"
Billing Service = "billing"
Enterprise Service = "enterprise"
ResourceController Service = "resource-controller"
ResourceCatalog Service = "global-catalog"
)

func (s Service) String() string {
return string(s)
}

var endpointsMapping = map[Service]models.Endpoints{
GlobalSearch: models.Endpoints{
PublicEndpoint: "https://api.global-search-tagging.<cloud_domain>",
PrivateEndpoint: "https://api.private.<region>.global-search-tagging.<cloud_domain>",
},
GlobalTagging: models.Endpoints{
PublicEndpoint: "https://tags.global-search-tagging.<cloud_domain>",
PrivateEndpoint: "https://tags.private.<region>.global-search-tagging.<cloud_domain>",
},
AccountManagement: models.Endpoints{
PublicEndpoint: "https://accounts.<cloud_domain>",
PrivateEndpoint: "https://private.<region>.accounts.<cloud_domain>",
},
UserManagement: models.Endpoints{
PublicEndpoint: "https://user-management.<cloud_domain>",
PrivateEndpoint: "https://private.<region>.user-management.<cloud_domain>",
},
Billing: models.Endpoints{
PublicEndpoint: "https://billing.<cloud_domain>",
PrivateEndpoint: "https://private.<region>.billing.<cloud_domain>",
},
Enterprise: models.Endpoints{
PublicEndpoint: "https://enterprise.<cloud_domain>",
PrivateEndpoint: "https://private.<region>.enterprise.<cloud_domain>",
},
ResourceController: models.Endpoints{
PublicEndpoint: "https://resource-controller.<cloud_domain>",
PrivateEndpoint: "https://private.<region>.resource-controller.<cloud_domain>",
},
ResourceCatalog: models.Endpoints{
PublicEndpoint: "https://globalcatalog.<cloud_domain>",
PrivateEndpoint: "https://private.<region>.globalcatalog.<cloud_domain>",
},
}

func Endpoint(svc Service, cloudDomain, region string, private bool) (string, error) {
var endpoint string
if endpoints, found := endpointsMapping[svc]; found {
if private {
endpoint = endpoints.PrivateEndpoint
} else {
endpoint = endpoints.PublicEndpoint
}
}
if endpoint == "" {
return "", fmt.Errorf("the endpoint of service '%s' was unknown", svc)
}

// replace <cloud_domain>
if cloudDomain == "" {
return "", fmt.Errorf("the cloud domain is empty")
}
endpoint = strings.ReplaceAll(endpoint, "<cloud_domain>", cloudDomain)

// replace <region>
if region != "" {
endpoint = strings.ReplaceAll(endpoint, "<region>", region)
} else if strings.Index(endpoint, "<region>") >= 0 {
return "", fmt.Errorf("region is required to get the endpoint of service '%s'", svc)
}

return endpoint, nil
}
68 changes: 68 additions & 0 deletions bluemix/endpoints/endpoints_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package endpoints_test

import (
"fmt"
"testing"

. "github.com/IBM-Cloud/ibm-cloud-cli-sdk/bluemix/endpoints"
"github.com/stretchr/testify/assert"
)

func TestEndpointUnknownService(t *testing.T) {
_, err := Endpoint(Service("unknown"), "cloud.ibm.com", "us-south", false)
assert.Error(t, err, "an error is expected")
}

func TestEndpointEmptyCloudDomain(t *testing.T) {
_, err := Endpoint(AccountManagement, "", "", false)
assert.Error(t, err, "an error is expected")
}

func TestEndpointPublic(t *testing.T) {
cloudDomain := "cloud.ibm.com"
region := ""
private := false

endpoints := map[Service]string{
GlobalSearch: fmt.Sprintf("https://api.global-search-tagging.%s", cloudDomain),
GlobalTagging: fmt.Sprintf("https://tags.global-search-tagging.%s", cloudDomain),
AccountManagement: fmt.Sprintf("https://accounts.%s", cloudDomain),
UserManagement: fmt.Sprintf("https://user-management.%s", cloudDomain),
Billing: fmt.Sprintf("https://billing.%s", cloudDomain),
Enterprise: fmt.Sprintf("https://enterprise.%s", cloudDomain),
ResourceController: fmt.Sprintf("https://resource-controller.%s", cloudDomain),
ResourceCatalog: fmt.Sprintf("https://globalcatalog.%s", cloudDomain),
}
for svc, expected := range endpoints {
actual, err := Endpoint(svc, cloudDomain, region, private)
assert.NoError(t, err, "public endpoint of service '%s'", svc)
assert.Equal(t, expected, actual, "public endpoint of service '%s'", svc)
}
}

func TestEndpointPrivate(t *testing.T) {
cloudDomain := "cloud.ibm.com"
region := "us-south"
private := true

endpoints := map[Service]string{
GlobalSearch: fmt.Sprintf("https://api.private.%s.global-search-tagging.%s", region, cloudDomain),
GlobalTagging: fmt.Sprintf("https://tags.private.%s.global-search-tagging.%s", region, cloudDomain),
AccountManagement: fmt.Sprintf("https://private.%s.accounts.%s", region, cloudDomain),
UserManagement: fmt.Sprintf("https://private.%s.user-management.%s", region, cloudDomain),
Billing: fmt.Sprintf("https://private.%s.billing.%s", region, cloudDomain),
Enterprise: fmt.Sprintf("https://private.%s.enterprise.%s", region, cloudDomain),
ResourceController: fmt.Sprintf("https://private.%s.resource-controller.%s", region, cloudDomain),
ResourceCatalog: fmt.Sprintf("https://private.%s.globalcatalog.%s", region, cloudDomain),
}
for svc, expected := range endpoints {
actual, err := Endpoint(svc, cloudDomain, region, private)
assert.NoError(t, err, "private endpoint of service '%s'", svc)
assert.Equal(t, expected, actual, "private endpoint of service '%s'", svc)
}
}

func TestEndpointPrivateNoRegion(t *testing.T) {
_, err := Endpoint(AccountManagement, "cloud.ibm.com", "", true)
assert.Error(t, err, "an error is expected")
}
30 changes: 22 additions & 8 deletions bluemix/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,38 @@ import (
)

var (
EnvTrace = newEnv("IBMCLOUD_TRACE", "BLUEMIX_TRACE")
EnvColor = newEnv("IBMCLOUD_COLOR", "BLUEMIX_COLOR")
// EnvTrace is the environment variable `IBMCLOUD_TRACE` and `BLUEMIX_TRACE` (deprecated)
EnvTrace = newEnv("IBMCLOUD_TRACE", "BLUEMIX_TRACE")
// EnvColor is the environment variable `IBMCLOUD_COLOR` and `BLUEMIX_COLOR` (deprecated)
EnvColor = newEnv("IBMCLOUD_COLOR", "BLUEMIX_COLOR")
// EnvVersionCheck is the environment variable `IBMCLOUD_VERSION_CHECK` and `BLUEMIX_VERSION_CHECK` (deprecated)
EnvVersionCheck = newEnv("IBMCLOUD_VERSION_CHECK", "BLUEMIX_VERSION_CHECK")
EnvAnalytics = newEnv("IBMCLOUD_ANALYTICS", "BLUEMIX_ANALYTICS")
EnvHTTPTimeout = newEnv("IBMCLOUD_HTTP_TIMEOUT", "BLUEMIX_HTTP_TIMEOUT")
EnvAPIKey = newEnv("IBMCLOUD_API_KEY", "BLUEMIX_API_KEY")
EnvConfigHome = newEnv("IBMCLOUD_HOME", "BLUEMIX_HOME")
EnvConfigDir = newEnv("IBMCLOUD_CONFIG_HOME")
EnvQuiet = newEnv("IBMCLOUD_QUIET")
// EnvAnalytics is the environment variable `IBMCLOUD_ANALYTICS` and `BLUEMIX_ANALYTICS` (deprecated)
EnvAnalytics = newEnv("IBMCLOUD_ANALYTICS", "BLUEMIX_ANALYTICS")
// EnvHTTPTimeout is the environment variable `IBMCLOUD_HTTP_TIMEOUT` and `BLUEMIX_HTTP_TIMEOUT` (deprecated)
EnvHTTPTimeout = newEnv("IBMCLOUD_HTTP_TIMEOUT", "BLUEMIX_HTTP_TIMEOUT")
// EnvAPIKey is the environment variable `IBMCLOUD_API_KEY` and `BLUEMIX_API_KEY` (deprecated)
EnvAPIKey = newEnv("IBMCLOUD_API_KEY", "BLUEMIX_API_KEY")
// EnvConfigHome is the environment variable `IBMCLOUD_HOME` and `BLUEMIX_HOME` (deprecated)
EnvConfigHome = newEnv("IBMCLOUD_HOME", "BLUEMIX_HOME")
// EnvConfigDir is the environment variable `IBMCLOUD_CONFIG_HOME`
EnvConfigDir = newEnv("IBMCLOUD_CONFIG_HOME")
// EnvQuiet is the environment variable `IBMCLOUD_QUIET`
EnvQuiet = newEnv("IBMCLOUD_QUIET")

// for internal use
EnvCLIName = newEnv("IBMCLOUD_CLI", "BLUEMIX_CLI")
EnvPluginNamespace = newEnv("IBMCLOUD_PLUGIN_NAMESPACE", "BLUEMIX_PLUGIN_NAMESPACE")
)

// Env is an environment variable supported by IBM Cloud CLI for specific purpose
// An Env could be bound to multiple environment variables due to historical reasons (i.e. renaming)
// Make sure you define the latest environment variable first
type Env struct {
names []string
}

// Get will return the value of the environment variable, the first found non-empty value will be returned
func (e Env) Get() string {
for _, n := range e.names {
if v := os.Getenv(n); v != "" {
Expand All @@ -33,6 +46,7 @@ func (e Env) Get() string {
return ""
}

// Set will set the value to **ALL** belonging environment variables
func (e Env) Set(val string) error {
for _, n := range e.names {
if err := os.Setenv(n, val); err != nil {
Expand Down
Loading

0 comments on commit 43e1b80

Please sign in to comment.