Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
34 changes: 17 additions & 17 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ require (
github.com/Azure/go-autorest/autorest v0.11.28
github.com/Azure/go-autorest/autorest/to v0.4.0
github.com/IBM-Cloud/bluemix-go v0.0.0-20211102075456-ffc4e11dfb16
github.com/IBM-Cloud/power-go-client v1.2.0
github.com/IBM/go-sdk-core/v5 v5.13.2
github.com/IBM-Cloud/power-go-client v1.5.3
github.com/IBM/go-sdk-core/v5 v5.14.1
github.com/IBM/networking-go-sdk v0.42.2
github.com/IBM/platform-services-go-sdk v0.42.0
github.com/IBM/vpc-go-sdk v0.20.0
Expand All @@ -32,9 +32,9 @@ require (
github.com/daixiang0/gci v0.9.0
github.com/diskfs/go-diskfs v1.4.0
github.com/form3tech-oss/jwt-go v3.2.3+incompatible
github.com/go-openapi/errors v0.20.3
github.com/go-openapi/strfmt v0.21.5
github.com/go-openapi/swag v0.22.3
github.com/go-openapi/errors v0.20.4
github.com/go-openapi/strfmt v0.21.7
github.com/go-openapi/swag v0.22.4
github.com/go-playground/validator/v10 v10.13.0
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/golang/mock v1.7.0-rc.1
Expand Down Expand Up @@ -82,15 +82,15 @@ require (
github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.6.0
github.com/stretchr/testify v1.8.2
github.com/stretchr/testify v1.8.4
github.com/thedevsaddam/retry v0.0.0-20200324223450-9769a859cc6d
github.com/ulikunitz/xz v0.5.11
github.com/vincent-petithory/dataurl v1.0.0
github.com/vmware/govmomi v0.30.4
golang.org/x/crypto v0.7.0
golang.org/x/crypto v0.14.0
golang.org/x/oauth2 v0.8.0
golang.org/x/sync v0.3.0
golang.org/x/sys v0.10.0
golang.org/x/sys v0.13.0
golang.org/x/term v0.6.0
google.golang.org/api v0.107.0
google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9
Expand Down Expand Up @@ -138,13 +138,13 @@ require (
github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-logr/zapr v1.2.3 // indirect
github.com/go-openapi/analysis v0.21.2 // indirect
github.com/go-openapi/analysis v0.21.4 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/loads v0.21.1 // indirect
github.com/go-openapi/runtime v0.23.0 // indirect
github.com/go-openapi/spec v0.20.7 // indirect
github.com/go-openapi/validate v0.22.0 // indirect
github.com/go-openapi/loads v0.21.2 // indirect
github.com/go-openapi/runtime v0.26.0 // indirect
github.com/go-openapi/spec v0.20.8 // indirect
github.com/go-openapi/validate v0.22.1 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/gobuffalo/flect v0.2.5 // indirect
Expand Down Expand Up @@ -205,14 +205,14 @@ require (
github.com/zclconf/go-cty v1.11.0 // indirect
go.mongodb.org/mongo-driver v1.11.3 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/otel v1.11.1 // indirect
go.opentelemetry.io/otel/trace v1.11.1 // indirect
go.opentelemetry.io/otel v1.14.0 // indirect
go.opentelemetry.io/otel/trace v1.14.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/mod v0.10.0 // indirect
golang.org/x/net v0.12.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.9.3 // indirect
google.golang.org/appengine v1.6.7 // indirect
Expand Down
100 changes: 31 additions & 69 deletions go.sum

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion pkg/asset/cluster/tfvars.go
Original file line number Diff line number Diff line change
Expand Up @@ -873,7 +873,8 @@ func (t *TerraformVariables) Generate(parents asset.Parents) error {
vpcZone = fmt.Sprintf("%s-%d", vpcRegion, rand.Intn(2)+1) //nolint:gosec // we don't need a crypto secure number
}

transitGatewayEnabled := powervsconfig.TransitGatewayEnabledZone(installConfig.Config.Platform.PowerVS.Zone)
err = powervsconfig.ValidatePERAvailability(client, installConfig.Config)
transitGatewayEnabled := err == nil

serviceInstanceCRN, err := client.ServiceInstanceIDToCRN(ctx, installConfig.Config.PowerVS.ServiceInstanceID)
if err != nil {
Expand Down
37 changes: 31 additions & 6 deletions pkg/asset/installconfig/powervs/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"time"

"github.com/IBM-Cloud/bluemix-go/crn"
"github.com/IBM-Cloud/power-go-client/power/client/datacenters"
"github.com/IBM-Cloud/power-go-client/power/client/workspaces"
"github.com/IBM/go-sdk-core/v5/core"
"github.com/IBM/networking-go-sdk/dnsrecordsv1"
"github.com/IBM/networking-go-sdk/dnssvcsv1"
Expand Down Expand Up @@ -40,6 +42,8 @@ type API interface {
ListResourceGroups(ctx context.Context) (*resourcemanagerv2.ResourceGroupList, error)
ListServiceInstances(ctx context.Context) ([]string, error)
ServiceInstanceIDToCRN(ctx context.Context, id string) (string, error)
GetDatacenterCapabilities(ctx context.Context, zone string) (map[string]bool, error)
GetWorkspaceCapabilities(ctx context.Context, svcInsID string) (map[string]bool, error)
}

// Client makes calls to the PowerVS API.
Expand Down Expand Up @@ -661,12 +665,6 @@ func (c *Client) ListServiceInstances(ctx context.Context) ([]string, error) {
return serviceInstances, nil
}

// TransitGatewayEnabledZone returns if a zone is configured for transit gateways rather than cloud connections.
func TransitGatewayEnabledZone(zone string) bool {
// @TBD - HACK. Waiting for officially supported detection function
return zone == "dal10"
}

// ServiceInstanceIDToCRN returns the CRN of the matching service instance GUID which was passed in.
func (c *Client) ServiceInstanceIDToCRN(ctx context.Context, id string) (string, error) {
var (
Expand Down Expand Up @@ -746,3 +744,30 @@ func (c *Client) ServiceInstanceIDToCRN(ctx context.Context, id string) (string,

return "", nil
}

// GetDatacenterCapabilities retrieves the capabilities of the specified datacenter.
func (c *Client) GetDatacenterCapabilities(ctx context.Context, zone string) (map[string]bool, error) {
var err error
if c.BXCli.PISession == nil {
err = c.BXCli.NewPISession()
if err != nil {
return nil, fmt.Errorf("failed to initialize PISession in GetDatacenterCapabilities: %w", err)
}
}
params := datacenters.NewV1DatacentersGetParamsWithContext(ctx).WithDatacenterRegion(zone)
getOk, err := c.BXCli.PISession.Power.Datacenters.V1DatacentersGet(params)
if err != nil {
return nil, fmt.Errorf("failed to get datacenter capabilities: %w", err)
}
return getOk.Payload.Capabilities, nil
}

// GetWorkspaceCapabilities retrieves the capabilities of the specified workspace.
func (c *Client) GetWorkspaceCapabilities(ctx context.Context, svcInsID string) (map[string]bool, error) {
params := workspaces.NewV1WorkspacesGetParamsWithContext(ctx).WithWorkspaceID(svcInsID)
getOk, err := c.BXCli.PISession.Power.Workspaces.V1WorkspacesGet(params, c.BXCli.PISession.AuthInfo(svcInsID))
if err != nil {
return nil, fmt.Errorf("failed to get workspace capabilities: %w", err)
}
return getOk.Payload.Capabilities, nil
}
30 changes: 30 additions & 0 deletions pkg/asset/installconfig/powervs/mock/powervsclient_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions pkg/asset/installconfig/powervs/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,32 @@ func validateMachinePool(fldPath *field.Path, machinePool *types.MachinePool) fi
return allErrs
}

// ValidatePERAvailability ensures the target datacenter has PER enabled.
func ValidatePERAvailability(client API, ic *types.InstallConfig) error {
capabilities, err := client.GetDatacenterCapabilities(context.TODO(), ic.PowerVS.Zone)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here it says zone but the param name in the package definition says region, good have same name everywhere.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

weird! PER enablement is zone specific so I'm a bit surprised at that. For example, dal12 does not currently support PER but dal10 does!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the API says it's a region, but when I passed in dal, it didn't work, and I was told by the PowerVS team that I should pass in dal10 (which is a zone), instead. So, there's nothing we can do on our end.

if err != nil {
return err
}
const per = "power-edge-router"
perAvail, ok := capabilities[per]
if !ok {
return fmt.Errorf("%s capability unknown at: %s", per, ic.PowerVS.Zone)
}
if !perAvail {
return fmt.Errorf("%s is not available at: %s", per, ic.PowerVS.Zone)
}

capabilities, err = client.GetWorkspaceCapabilities(context.TODO(), ic.PowerVS.ServiceInstanceID)
if err != nil {
return err
}
if !capabilities[per] {
return fmt.Errorf("%s is not available in workspace: %s", per, ic.PowerVS.ServiceInstanceID)
}

return nil
}

// ValidatePreExistingDNS ensures no pre-existing DNS record exists in the CIS
// DNS zone or IBM DNS zone for cluster's Kubernetes API.
func ValidatePreExistingDNS(client API, ic *types.InstallConfig, metadata MetadataAPI) error {
Expand Down
108 changes: 105 additions & 3 deletions pkg/asset/installconfig/powervs/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import (
type editFunctions []func(ic *types.InstallConfig)

var (
validRegion = "lon"
validRegion = "dal"
validCIDR = "192.168.0.0/24"
validCISInstanceCRN = "crn:v1:bluemix:public:internet-svcs:global:a/valid-account-id:valid-instance-id::"
validClusterName = "valid-cluster-name"
Expand All @@ -37,14 +37,15 @@ var (
validPrivateSubnetUSSouth1ID = "private-subnet-us-south-1-id"
validPrivateSubnetUSSouth2ID = "private-subnet-us-south-2-id"
validServiceInstanceID = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
invalidServiceInstanceID = "bogus-service-instance-id"
validSubnets = []string{
validPublicSubnetUSSouth1ID,
validPublicSubnetUSSouth2ID,
validPrivateSubnetUSSouth1ID,
validPrivateSubnetUSSouth2ID,
}
validUserID = "valid-user@example.com"
validZone = "lon04"
validZone = "dal10"

existingDNSRecordsResponse = []powervs.DNSRecordResponse{
{
Expand All @@ -62,7 +63,7 @@ var (
invalidMachinePoolCIDR = func(ic *types.InstallConfig) { ic.Networking.MachineNetwork[0].CIDR = *cidrInvalid }
cidrValid, _ = ipnet.ParseCIDR("192.168.0.0/24")
validMachinePoolCIDR = func(ic *types.InstallConfig) { ic.Networking.MachineNetwork[0].CIDR = *cidrValid }
validVPCRegion = "eu-gb"
validVPCRegion = "us-south"
invalidVPCRegion = "foo-bah"
setValidVPCRegion = func(ic *types.InstallConfig) { ic.Platform.PowerVS.VPCRegion = validVPCRegion }
validRG = "valid-resource-group"
Expand Down Expand Up @@ -116,6 +117,23 @@ var (
ID: &validRG,
},
}
regionWithPER = "dal10"
regionWithoutPER = "foo99"
regionPERUnknown = "bah77"
mapWithPERFalse = map[string]bool{
"disaster-recover-site": true,
"power-edge-router": false,
"vpn-connections": true,
}
mapWithPERTrue = map[string]bool{
"disaster-recover-site": true,
"power-edge-router": true,
"vpn-connections": true,
}
mapPERUnknown = map[string]bool{
"disaster-recover-site": true,
"power-vpn-connections": false,
}
)

func validInstallConfig() *types.InstallConfig {
Expand Down Expand Up @@ -632,6 +650,90 @@ func TestSystemPool(t *testing.T) {
assert.Empty(t, err)
}

func TestValidatePERAvailability(t *testing.T) {
cases := []struct {
name string
edits editFunctions
errorMsg string
}{
{
name: "Region without PER",
edits: editFunctions{
func(ic *types.InstallConfig) {
ic.Platform.PowerVS.Zone = regionWithoutPER
},
},
errorMsg: fmt.Sprintf("power-edge-router is not available at: %s", regionWithoutPER),
},
{
name: "Region with PER",
edits: editFunctions{
func(ic *types.InstallConfig) {
ic.Platform.PowerVS.Zone = regionWithPER
ic.Platform.PowerVS.ServiceInstanceID = validServiceInstanceID
},
},
errorMsg: "",
},
{
name: "Region with no PER availability info",
edits: editFunctions{
func(ic *types.InstallConfig) {
ic.Platform.PowerVS.Zone = regionPERUnknown
},
},
errorMsg: fmt.Sprintf("power-edge-router capability unknown at: %s", regionPERUnknown),
},
{
name: "Region with PER, but with invalid Workspace ID",
edits: editFunctions{
func(ic *types.InstallConfig) {
ic.Platform.PowerVS.Zone = regionWithPER
ic.Platform.PowerVS.ServiceInstanceID = invalidServiceInstanceID
},
},
errorMsg: fmt.Sprintf("power-edge-router is not available in workspace: %s", invalidServiceInstanceID),
},
}
setMockEnvVars()

mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()

powervsClient := mock.NewMockAPI(mockCtrl)

// Mocks: PER-absent region results in false
powervsClient.EXPECT().GetDatacenterCapabilities(gomock.Any(), regionWithoutPER).Return(mapWithPERFalse, nil)

// Mocks: PER-enabled region results in true
powervsClient.EXPECT().GetDatacenterCapabilities(gomock.Any(), regionWithPER).Return(mapWithPERTrue, nil)
powervsClient.EXPECT().GetWorkspaceCapabilities(gomock.Any(), validServiceInstanceID).Return(mapWithPERTrue, nil)

// Mocks: PER-unknown region results in false
powervsClient.EXPECT().GetDatacenterCapabilities(gomock.Any(), regionPERUnknown).Return(mapPERUnknown, nil)

// Mocks: PER-enabled region, but bogus Service Instance results in false
powervsClient.EXPECT().GetDatacenterCapabilities(gomock.Any(), regionWithPER).Return(mapWithPERTrue, nil)
powervsClient.EXPECT().GetWorkspaceCapabilities(gomock.Any(), invalidServiceInstanceID).Return(mapWithPERFalse, nil)

// Run tests
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
editedInstallConfig := validInstallConfig()
for _, edit := range tc.edits {
edit(editedInstallConfig)
}

aggregatedErrors := powervs.ValidatePERAvailability(powervsClient, editedInstallConfig)
if tc.errorMsg != "" {
assert.Regexp(t, tc.errorMsg, aggregatedErrors)
} else {
assert.NoError(t, aggregatedErrors)
}
})
}
}

func setMockEnvVars() {
os.Setenv("POWERVS_AUTH_FILEPATH", "./tmp/powervs/config.json")
os.Setenv("IBMID", "foo")
Expand Down
7 changes: 6 additions & 1 deletion pkg/asset/quota/quota.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,12 @@ func (a *PlatformQuotaCheck) Generate(dependencies asset.Parents) error {
return errors.Wrap(err, "failed to create a new PISession")
}

transitGatewayEnabled := configpowervs.TransitGatewayEnabledZone(ic.Config.Platform.PowerVS.Zone)
client, err := configpowervs.NewClient()
if err != nil {
return err
}
err = configpowervs.ValidatePERAvailability(client, ic.Config)
transitGatewayEnabled := err == nil

if !transitGatewayEnabled {
// Only check that there isn't an existing Cloud connection if we're not re-using one
Expand Down
Loading