Skip to content

Commit

Permalink
OCM-11855 | test: Create bastion with proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
jameszwang committed Nov 11, 2024
1 parent 64d443a commit 8f3bfde
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 20 deletions.
7 changes: 6 additions & 1 deletion pkg/aws/aws_client/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import (
"github.com/openshift-online/ocm-common/pkg/log"
)

func (client *AWSClient) LaunchInstance(subnetID string, imageID string, count int, instanceType string, keyName string, securityGroupIds []string, wait bool) (*ec2.RunInstancesOutput, error) {
func (client *AWSClient) LaunchInstance(subnetID string, imageID string, count int, instanceType string, keyName string,
securityGroupIds []string, wait bool, userDate ...string) (*ec2.RunInstancesOutput, error) {
input := &ec2.RunInstancesInput{
ImageId: aws.String(imageID),
MinCount: aws.Int32(int32(count)),
Expand All @@ -25,6 +26,10 @@ func (client *AWSClient) LaunchInstance(subnetID string, imageID string, count i
SecurityGroupIds: securityGroupIds,
SubnetId: &subnetID,
}
if len(userDate) > 0 {
input.UserData = &userDate[0]
}

output, err := client.Ec2Client.RunInstances(context.TODO(), input)
if wait && err == nil {
instanceIDs := []string{}
Expand Down
2 changes: 2 additions & 0 deletions pkg/aws/consts/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,11 @@ const (
TCPProtocol = "tcp"
UDPProtocol = "udp"

BastionSecurityGroupName = "bastion-sg"
ProxySecurityGroupName = "proxy-sg"
AdditionalSecurityGroupName = "ocm-additional-sg"
ProxySecurityGroupDescription = "security group for proxy"
BastionSecurityGroupDescription = "security group for bastion"
DefaultAdditionalSecurityGroupDescription = "This security group is created for OCM testing"

QEFlagKey = "ocm_ci_flag"
Expand Down
60 changes: 50 additions & 10 deletions pkg/test/vpc_client/bastion.go
Original file line number Diff line number Diff line change
@@ -1,33 +1,39 @@
package vpc_client

import (
"encoding/base64"
"errors"
"fmt"
"time"

"github.com/aws/aws-sdk-go-v2/service/ec2/types"
"net"

CON "github.com/openshift-online/ocm-common/pkg/aws/consts"
"github.com/openshift-online/ocm-common/pkg/log"
)

// LaunchBastion will launch a bastion instance on the indicated zone.
// If set imageID to empty, it will find the bastion image in the bastionImageMap map
func (vpc *VPC) LaunchBastion(imageID string, zone string) (*types.Instance, error) {
// If set imageID to empty, it will find the bastion image using filter with specific name.
func (vpc *VPC) LaunchBastion(imageID string, zone string, userData string) (*types.Instance, error) {
var inst *types.Instance
if imageID == "" {

var err error
imageID, err = vpc.FindProxyLaunchImage()
if err != nil {
log.LogError("Cannot find bastion image of region %s in map bastionImageMap, please indicate it as parameter", vpc.Region)
return nil, err
}
}
if userData == "" {
log.LogError("Userdata can not be empty, pleas provide the correct userdata")
return nil, errors.New("userData should not be empty")
}
pubSubnet, err := vpc.PreparePublicSubnet(zone)
if err != nil {
log.LogInfo("Error preparing a subnet in current zone %s with image ID %s: %s", zone, imageID, err)
log.LogError("Error preparing a subnet in current zone %s with image ID %s: %s", zone, imageID, err)
return nil, err
}
SGID, err := vpc.CreateAndAuthorizeDefaultSecurityGroupForProxy()
SGID, err := vpc.CreateAndAuthorizeDefaultSecurityGroupForProxy(3128)
if err != nil {
log.LogError("Prepare SG failed for the bastion preparation %s", err)
return inst, err
Expand All @@ -38,7 +44,8 @@ func (vpc *VPC) LaunchBastion(imageID string, zone string) (*types.Instance, err
log.LogError("Create key pair failed %s", err)
return inst, err
}
instOut, err := vpc.AWSClient.LaunchInstance(pubSubnet.ID, imageID, 1, "t3.medium", *key.KeyName, []string{SGID}, true)
instOut, err := vpc.AWSClient.LaunchInstance(pubSubnet.ID, imageID, 1, "t3.medium", *key.KeyName,
[]string{SGID}, true, userData)

if err != nil {
log.LogError("Launch bastion instance failed %s", err)
Expand All @@ -63,11 +70,10 @@ func (vpc *VPC) LaunchBastion(imageID string, zone string) (*types.Instance, err
log.LogInfo("Prepare EIP successfully for the bastion preparation. Launch with IP: %s", publicIP)
inst = &instOut.Instances[0]
inst.PublicIpAddress = &publicIP
time.Sleep(2 * time.Minute)
return inst, nil
}

func (vpc *VPC) PrepareBastion(zone string) (*types.Instance, error) {
func (vpc *VPC) PrepareBastionProxy(zone string, cidrBlock string) (*types.Instance, error) {
filters := []map[string][]string{
{
"vpc-id": {
Expand All @@ -87,9 +93,43 @@ func (vpc *VPC) PrepareBastion(zone string) (*types.Instance, error) {
}
if len(insts) == 0 {
log.LogInfo("Didn't found an existing bastion, going to launch one")
return vpc.LaunchBastion("", zone)
if cidrBlock == "" {
cidrBlock = CON.RouteDestinationCidrBlock
}
_, _, err = net.ParseCIDR(cidrBlock)
if err != nil {
log.LogError("CIDR IP address format is invalid")
return nil, err
}

userData := fmt.Sprintf(`#!/bin/bash
yum update -y
yum install -y squid
cd /etc/squid/
sudo mv ./squid.conf ./squid.conf.bak
sudo touch squid.conf
echo http_port 3128 >> /etc/squid/squid.conf
echo acl allowed_ips src %s >> /etc/squid/squid.conf
echo http_access allow allowed_ips >> /etc/squid/squid.conf
echo http_access deny all >> /etc/squid/squid.conf
systemctl start squid
systemctl enable squid`, cidrBlock)

encodeUserData := base64.StdEncoding.EncodeToString([]byte(userData))
return vpc.LaunchBastion("", zone, encodeUserData)

}
log.LogInfo("Found existing bastion: %s", *insts[0].InstanceId)
return &insts[0], nil
}

func (vpc *VPC) DestroyBastionProxy(instance types.Instance) error {
var instanceIDs []string
instanceIDs = append(instanceIDs, *instance.InstanceId)
err := vpc.AWSClient.TerminateInstances(instanceIDs, true, 10)
if err != nil {
log.LogError("Terminate instance failed")
return err
}
return nil
}
35 changes: 26 additions & 9 deletions pkg/test/vpc_client/security_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,21 @@ func (vpc *VPC) DeleteVPCSecurityGroups(customizedOnly bool) error {
}

// CreateAndAuthorizeDefaultSecurityGroupForProxy can prepare a security group for the proxy launch
func (vpc *VPC) CreateAndAuthorizeDefaultSecurityGroupForProxy() (string, error) {
func (vpc *VPC) CreateAndAuthorizeDefaultSecurityGroupForProxy(ports ...int32) (string, error) {
var groupID string
var err error
sgIDs, err := vpc.CreateAdditionalSecurityGroups(1, con.ProxySecurityGroupName, con.ProxySecurityGroupDescription)
var sgIDs []string
var securityGroupName string
var securityGroupDescription string
if len(ports) > 0 {
securityGroupName = con.BastionSecurityGroupName
securityGroupDescription = con.BastionSecurityGroupDescription
} else {
securityGroupName = con.ProxySecurityGroupName
securityGroupDescription = con.ProxySecurityGroupDescription
}
sgIDs, err = vpc.CreateAdditionalSecurityGroups(1, securityGroupName, securityGroupDescription, ports...)

if err != nil {
log.LogError("Security group prepare for proxy failed")
} else {
Expand All @@ -52,7 +63,7 @@ func (vpc *VPC) CreateAndAuthorizeDefaultSecurityGroupForProxy() (string, error)
// CreateAdditionalSecurityGroups can prepare <count> additional security groups
// description can be empty which will be set to default value
// namePrefix is required, otherwise if there is same security group existing the creation will fail
func (vpc *VPC) CreateAdditionalSecurityGroups(count int, namePrefix string, description string) ([]string, error) {
func (vpc *VPC) CreateAdditionalSecurityGroups(count int, namePrefix string, description string, ports ...int32) ([]string, error) {
preparedSGs := []string{}
createdsgNum := 0
if description == "" {
Expand All @@ -65,15 +76,21 @@ func (vpc *VPC) CreateAdditionalSecurityGroups(count int, namePrefix string, des
panic(err)
}
groupID := *sg.GroupId
cidrPortsMap := map[string]int32{
vpc.CIDRValue: 8080,
con.RouteDestinationCidrBlock: 22,
cidrPortsMap := make(map[string][]int32)
cidrPortsMap[con.RouteDestinationCidrBlock] = append(cidrPortsMap[con.RouteDestinationCidrBlock], 22)
if len(ports) > 0 {
cidrPortsMap[con.RouteDestinationCidrBlock] = append(cidrPortsMap[con.RouteDestinationCidrBlock], ports...)
} else {
cidrPortsMap[vpc.CIDRValue] = append(cidrPortsMap[vpc.CIDRValue], 8080)
}
for cidr, port := range cidrPortsMap {
_, err = vpc.AWSClient.AuthorizeSecurityGroupIngress(groupID, cidr, con.TCPProtocol, port, port)
if err != nil {
return preparedSGs, err
for _, v := range port {
_, err = vpc.AWSClient.AuthorizeSecurityGroupIngress(groupID, cidr, con.TCPProtocol, v, v)
if err != nil {
return preparedSGs, err
}
}

}

preparedSGs = append(preparedSGs, *sg.GroupId)
Expand Down

0 comments on commit 8f3bfde

Please sign in to comment.