Skip to content

Commit

Permalink
OCM-8979 | test: Prepare shared VPC resources
Browse files Browse the repository at this point in the history
  • Loading branch information
jameszwang committed Jul 1, 2024
1 parent 35b747c commit dfe87e9
Show file tree
Hide file tree
Showing 7 changed files with 227 additions and 27 deletions.
7 changes: 4 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ go 1.21

require (
github.com/apparentlymart/go-cidr v1.1.0
github.com/aws/aws-sdk-go-v2 v1.26.1
github.com/aws/aws-sdk-go-v2 v1.30.0
github.com/aws/aws-sdk-go-v2/config v1.27.9
github.com/aws/aws-sdk-go-v2/credentials v1.17.9
github.com/aws/aws-sdk-go-v2/service/cloudformation v1.48.0
github.com/aws/aws-sdk-go-v2/service/ec2 v1.152.0
github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.24.3
github.com/aws/aws-sdk-go-v2/service/iam v1.27.1
github.com/aws/aws-sdk-go-v2/service/kms v1.30.0
github.com/aws/aws-sdk-go-v2/service/ram v1.26.1
github.com/aws/aws-sdk-go-v2/service/route53 v1.40.3
github.com/aws/aws-sdk-go-v2/service/sts v1.28.5
github.com/go-jose/go-jose/v4 v4.0.2
Expand All @@ -34,8 +35,8 @@ require (

require (
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.12 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.12 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.35.1
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 // indirect
Expand Down
14 changes: 8 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU=
github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc=
github.com/aws/aws-sdk-go-v2 v1.26.1 h1:5554eUqIYVWpU0YmeeYZ0wU64H2VLBs8TlhRB2L+EkA=
github.com/aws/aws-sdk-go-v2 v1.26.1/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM=
github.com/aws/aws-sdk-go-v2 v1.30.0 h1:6qAwtzlfcTtcL8NHtbDQAqgM5s6NDipQTkPxyH/6kAA=
github.com/aws/aws-sdk-go-v2 v1.30.0/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 h1:x6xsQXGSmW6frevwDA+vi/wqhp1ct18mVXYN08/93to=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2/go.mod h1:lPprDr1e6cJdyYeGXnRaJoP4Md+cDBvi2eOj00BlGmg=
github.com/aws/aws-sdk-go-v2/config v1.27.9 h1:gRx/NwpNEFSk+yQlgmk1bmxxvQ5TyJ76CWXs9XScTqg=
Expand All @@ -10,10 +10,10 @@ github.com/aws/aws-sdk-go-v2/credentials v1.17.9 h1:N8s0/7yW+h8qR8WaRlPQeJ6czVMN
github.com/aws/aws-sdk-go-v2/credentials v1.17.9/go.mod h1:446YhIdmSV0Jf/SLafGZalQo+xr2iw7/fzXGDPTU1yQ=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.0 h1:af5YzcLf80tv4Em4jWVD75lpnOHSBkPUZxZfGkrI3HI=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.0/go.mod h1:nQ3how7DMnFMWiU1SpECohgC82fpn4cKZ875NDMmwtA=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 h1:aw39xVGeRWlWx9EzGVnhOR4yOjQDHPQ6o6NmBlscyQg=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5/go.mod h1:FSaRudD0dXiMPK2UjknVwwTYyZMRsHv3TtkabsZih5I=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 h1:PG1F3OD1szkuQPzDw3CIQsRIrtTlUC3lP84taWzHlq0=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5/go.mod h1:jU1li6RFryMz+so64PpKtudI+QzbKoIEivqdf6LNpOc=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.12 h1:SJ04WXGTwnHlWIODtC5kJzKbeuHt+OUNOgKg7nfnUGw=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.12/go.mod h1:FkpvXhA92gb3GE9LD6Og0pHHycTxW7xGpnEh5E7Opwo=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.12 h1:hb5KgeYfObi5MHkSSZMEudnIvX30iB+E21evI4r6BnQ=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.12/go.mod h1:CroKe/eWJdyfy9Vx4rljP5wTUjNJfb+fPz1uMYUhEGM=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
github.com/aws/aws-sdk-go-v2/service/cloudformation v1.48.0 h1:uMlYsoHdd2Gr9sDGq2ieUR5jVu7F5AqPYz6UBJmdRhY=
Expand All @@ -32,6 +32,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.6 h1:b+E7zIUHM
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.6/go.mod h1:S2fNV0rxrP78NhPbCZeQgY8H9jdDMeGtwcfZIRxzBqU=
github.com/aws/aws-sdk-go-v2/service/kms v1.30.0 h1:yS0JkEdV6h9JOo8sy2JSpjX+i7vsKifU8SIeHrqiDhU=
github.com/aws/aws-sdk-go-v2/service/kms v1.30.0/go.mod h1:+I8VUUSVD4p5ISQtzpgSva4I8cJ4SQ4b1dcBcof7O+g=
github.com/aws/aws-sdk-go-v2/service/ram v1.26.1 h1:1UcUsMsHB7ZnpcUYNwBTX90hFjIZrhf8Xu00R9Vo+Kg=
github.com/aws/aws-sdk-go-v2/service/ram v1.26.1/go.mod h1:e/3wE+afnOAeolpqyg8fKAQK/kKya+ycDW62/X4vjK8=
github.com/aws/aws-sdk-go-v2/service/route53 v1.40.3 h1:wr5gulbwbb8PSRMWjCROoP0TIMccpF8x5A7hEk2SjpA=
github.com/aws/aws-sdk-go-v2/service/route53 v1.40.3/go.mod h1:/Gyl9xjGcjIVe80ar75YlmA8m6oFh0A4XfLciBmdS8s=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.3 h1:mnbuWHOcM70/OFUlZZ5rcdfA8PflGXXiefU/O+1S3+8=
Expand Down
28 changes: 15 additions & 13 deletions pkg/aws/aws_client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/ec2"
"github.com/aws/aws-sdk-go-v2/service/iam"
"github.com/aws/aws-sdk-go-v2/service/kms"
"github.com/aws/aws-sdk-go-v2/service/ram"
"github.com/aws/aws-sdk-go-v2/service/sts"

"github.com/openshift-online/ocm-common/pkg/log"
Expand All @@ -35,42 +36,42 @@ type AWSClient struct {
KmsClient *kms.Client
CloudWatchLogsClient *cloudwatchlogs.Client
AWSConfig *aws.Config
RamClient *ram.Client
}

type AccessKeyMod struct {
AccessKeyId string `ini:"aws_access_key_id,omitempty"`
SecretAccessKey string `ini:"aws_secret_access_key,omitempty"`
}

func CreateAWSClient(profileName string, region string) (*AWSClient, error) {
func CreateAWSClient(profileName string, region string, awsSharedCredentialFile ...string) (*AWSClient, error) {
var cfg aws.Config
var err error

if envCredential() {
log.LogInfo("Got AWS_ACCESS_KEY_ID env settings, going to build the config with the env")
if len(awsSharedCredentialFile) > 0 {
file := awsSharedCredentialFile[0]
log.LogInfo("Got aws shared credential file path: %s ", file)
cfg, err = config.LoadDefaultConfig(context.TODO(),
config.WithRegion(region),
config.WithCredentialsProvider(
credentials.NewStaticCredentialsProvider(
os.Getenv("AWS_ACCESS_KEY_ID"),
os.Getenv("AWS_SECRET_ACCESS_KEY"),
"")),
config.WithSharedCredentialsFiles([]string{file}),
)
} else {
if envAwsProfile() {
file := os.Getenv("AWS_SHARED_CREDENTIALS_FILE")
log.LogInfo("Got file path: %s from env variable AWS_SHARED_CREDENTIALS_FILE\n", file)
if envCredential() {
log.LogInfo("Got AWS_ACCESS_KEY_ID env settings, going to build the config with the env")
cfg, err = config.LoadDefaultConfig(context.TODO(),
config.WithRegion(region),
config.WithSharedCredentialsFiles([]string{file}),
config.WithCredentialsProvider(
credentials.NewStaticCredentialsProvider(
os.Getenv("AWS_ACCESS_KEY_ID"),
os.Getenv("AWS_SECRET_ACCESS_KEY"),
"")),
)
} else {
cfg, err = config.LoadDefaultConfig(context.TODO(),
config.WithRegion(region),
config.WithSharedConfigProfile(profileName),
)
}

}

if err != nil {
Expand All @@ -88,6 +89,7 @@ func CreateAWSClient(profileName string, region string) (*AWSClient, error) {
ClientContext: context.TODO(),
KmsClient: kms.NewFromConfig(cfg),
AWSConfig: &cfg,
RamClient: ram.NewFromConfig(cfg),
}
awsClient.AccountID = awsClient.GetAWSAccountID()
return awsClient, nil
Expand Down
32 changes: 32 additions & 0 deletions pkg/aws/aws_client/ram.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package aws_client

import (
"context"
"github.com/aws/aws-sdk-go-v2/service/ram"
"github.com/openshift-online/ocm-common/pkg/log"
)

func (awsClient AWSClient) CreateResourceShare(resourceShareName string, resourceArns []string, principles []string) (*ram.CreateResourceShareOutput, error) {
input := &ram.CreateResourceShareInput{
Name: &resourceShareName,
ResourceArns: resourceArns,
Principals: principles,
}

resp, err := awsClient.RamClient.CreateResourceShare(context.TODO(), input)
if err != nil {
log.LogError("Create resource share failed with name %s: %s", resourceShareName, err.Error())
} else {
log.LogInfo("Create resource share succeed with name %s", resourceShareName)
}
return resp, err
}

func (awsClient AWSClient) DeleteResourceShare(resourceShareArn string) error {
input := &ram.DeleteResourceShareInput{
ResourceShareArn: &resourceShareArn,
}

_, err := awsClient.RamClient.DeleteResourceShare(context.TODO(), input)
return err
}
44 changes: 43 additions & 1 deletion pkg/aws/aws_client/role.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,4 +316,46 @@ func (client *AWSClient) UntagRole(roleName string, tagKeys []string) error {
}
_, err := client.IamClient.UntagRole(context.TODO(), input)
return err
}
}

func (client *AWSClient) CreateRoleForSharedVPC(roleName, installerRoleArn string, ingressOperatorRoleArn string) (types.Role, error) {
statement := map[string]interface{}{
"Sid": "Statement1",
"Effect": "Allow",
"Principal": map[string]interface{}{
"AWS": []string{installerRoleArn, ingressOperatorRoleArn},
},
"Action": "sts:AssumeRole",
}

assumeRolePolicyDocument, err := completeRolePolicyDocument(statement)
if err != nil {
fmt.Println("Failed to convert Role Policy Document into JSON: ", err)
return types.Role{}, err
}

return client.CreateRole(roleName, string(assumeRolePolicyDocument), "", make(map[string]string), "/")
}

func (client *AWSClient) CreatePolicyForSharedVPC(policyName string) (string, error) {
statement := map[string]interface{}{
"Sid": "Statement1",
"Effect": "Allow",
"Action": []string{
"route53:GetChange",
"route53:GetHostedZone",
"route53:ChangeResourceRecordSets",
"route53:ListHostedZones",
"route53:ListHostedZonesByName",
"route53:ListResourceRecordSets",
"route53:ChangeTagsForResource",
"route53:GetAccountLimit",
"route53:ListTagsForResource",
"route53:UpdateHostedZoneComment",
"tag:GetResources",
"tag:UntagResources",
},
"Resource": "*",
}
return client.CreatePolicy(policyName, statement)
}
22 changes: 18 additions & 4 deletions pkg/aws/aws_client/route53.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,29 @@ import (
"github.com/openshift-online/ocm-common/pkg/log"
)

func (awsClient AWSClient) CreateHostedZone(hostedZoneName string, vpcID string, private bool) (*route53.CreateHostedZoneOutput, error) {
func (awsClient AWSClient) CreateHostedZone(hostedZoneName string, callerReference string, vpcID string, region string, private bool) (*route53.CreateHostedZoneOutput, error) {
// callReference is a required field of CreateHostedZoneInput struct, which used to identifies the request as a unique string.
// Usually random string or date/time stamp can be used as callReference.
input := &route53.CreateHostedZoneInput{
Name: &hostedZoneName,
Name: &hostedZoneName,
CallerReference: &callerReference,
HostedZoneConfig: &types.HostedZoneConfig{
PrivateZone: private,
},
}
if vpcID != "" {
vpc := &types.VPC{
VPCId: &vpcID,
VPCId: &vpcID,
VPCRegion: types.VPCRegion(region),
}
input.VPC = vpc
}

resp, err := awsClient.Route53Client.CreateHostedZone(context.TODO(), input)
if err != nil {
log.LogError("Create hosted zone failed for vpc %s with name %s: %s", vpcID, hostedZoneName, err.Error())
} else {
log.LogError("Create hosted zone succeed for vpc %s with name %s", vpcID, hostedZoneName)
log.LogInfo("Create hosted zone succeed for vpc %s with name %s", vpcID, hostedZoneName)
}
return resp, err
}
Expand All @@ -47,3 +52,12 @@ func (awsClient AWSClient) ListHostedZoneByDNSName(hostedZoneName string) (*rout

return awsClient.Route53Client.ListHostedZonesByName(context.TODO(), input)
}

func (awsClient AWSClient) DeleteHostedZone(hostedZoneID string) error {
input := &route53.DeleteHostedZoneInput{
Id: &hostedZoneID,
}

_, err := awsClient.Route53Client.DeleteHostedZone(context.TODO(), input)
return err
}
107 changes: 107 additions & 0 deletions pkg/test/vpc_client/vpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,69 @@ func PrepareVPC(vpcName string, region string, vpcCIDR string, checkExisting boo
return vpc, err
}

func PrepareSharedVPC(vpcName string, region string, awsSharedCredentialFile string, vpcCIDR string, checkExisting bool, zones ...string) (*VPC, error) {
if vpcCIDR == "" {
vpcCIDR = CON.DefaultVPCCIDR
}
logMessage := fmt.Sprintf("Going to prepare a vpc with name %s, on region %s, with cidr %s and subnets on zones %s",
vpcName, region, vpcCIDR, strings.Join(zones, ","))
if len(zones) == 0 {
logMessage = fmt.Sprintf("Going to prepare a vpc with name %s, on region %s, with cidr %s ",
vpcName, region, vpcCIDR)
}
log.LogInfo(logMessage)
awsclient, err := aws_client.CreateAWSClient("", region, awsSharedCredentialFile)
if err != nil {
log.LogError("Create AWS Client due to error: %s", err.Error())
return nil, err
}
if checkExisting {
log.LogInfo("Got checkExisting set to true, will check if there is existing vpc in same name")
vpcs, err := awsclient.ListVPCByName(vpcName)
if err != nil {
log.LogError("Error happened when try to find a vpc: %s", err.Error())
return nil, err
}
if len(vpcs) != 0 {
vpcID := *vpcs[0].VpcId
log.LogInfo("Got a vpc %s with name %s on region %s. Just load it for usage",
vpcID, vpcName, region)
vpc, err := GenerateVPCByID(vpcID, region)
if err != nil {
log.LogError("Load vpc %s details meets error %s",
vpcID, err.Error())
return nil, err
}
for _, zone := range zones {
_, err = vpc.PreparePairSubnetByZone(zone)
if err != nil {
log.LogError("Prepare subnets for vpc %s on zone %s meets error %s",
vpcID, zone, err.Error())
return nil, err
}
}
return vpc, nil
}
log.LogInfo("Got no vpc with name %s on region %s. Going to create a new one",
vpcName, region)
}

vpc := NewVPC().
Name(vpcName).
AWSclient(awsclient).
SetRegion(region).
CIDR(vpcCIDR).
NewCIDRPool()
vpc, err = vpc.CreateVPCChain(zones...)
if err != nil {
log.LogError("Create vpc chain meets error: %s", err.Error())
} else {
log.LogInfo("Create vpc chain successfully. Enjoy it.")
}

return vpc, err
}

// NewVPC will return a new VPC instance
// CIDR can be empty, then it will use default value

Expand Down Expand Up @@ -248,6 +311,37 @@ func GenerateVPCByID(vpcID string, region string) (*VPC, error) {
return vpc, nil
}

func GenerateSharedVPCByID(vpcID string, region string, awsSharedCredentialFile string) (*VPC, error) {
awsClient, err := aws_client.CreateAWSClient("", region, awsSharedCredentialFile)
if err != nil {
return nil, err
}
vpc := NewVPC().AWSclient(awsClient).ID(vpcID)
vpcResp, err := vpc.AWSClient.DescribeVPC(vpcID)
if err != nil {
return nil, err
}
vpc = vpc.Name(getTagName((vpcResp.Tags))).SetRegion(awsClient.Region).CIDR(*vpcResp.CidrBlock)
if err != nil {
return nil, err
}
_, err = vpc.ListSubnets()
if err != nil {
return nil, err
}
reservedCIDRs := []string{}
for _, sub := range vpc.SubnetList {
reservedCIDRs = append(reservedCIDRs, sub.Cidr)
}
cidrPool := NewCIDRPool(vpc.CIDRValue)
err = cidrPool.Reserve(reservedCIDRs...)
if err != nil {
return nil, err
}
vpc.CIDRPool = cidrPool
return vpc, nil
}

// GenerateVPCBySubnet will return a VPC with CIDRpool and subnets based on one of the subnet ID
// If you know the subnet ID on AWS, then try to generate it on AWS.
func GenerateVPCBySubnet(subnetID string, region string) (*VPC, error) {
Expand All @@ -262,3 +356,16 @@ func GenerateVPCBySubnet(subnetID string, region string) (*VPC, error) {
vpc, err := GenerateVPCByID(*subnetDetail[0].VpcId, region)
return vpc, err
}

func GenerateSharedVPCBySubnet(subnetID string, region string, awsSharedCredentialFile string) (*VPC, error) {
awsClient, err := aws_client.CreateAWSClient("", region, awsSharedCredentialFile)
if err != nil {
return nil, err
}
subnetDetail, err := awsClient.ListSubnetDetail(subnetID)
if err != nil {
return nil, err
}
vpc, err := GenerateVPCByID(*subnetDetail[0].VpcId, region)
return vpc, err
}

0 comments on commit dfe87e9

Please sign in to comment.