github.com/verrazzano/verrazzano@v1.7.1/tests/e2e/clusterapi/capi/oci.go (about)

     1  // Copyright (c) 2023, Oracle and/or its affiliates.
     2  // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
     3  
     4  package capi
     5  
     6  import (
     7  	"context"
     8  	"github.com/oracle/oci-go-sdk/v53/common"
     9  	"github.com/oracle/oci-go-sdk/v53/core"
    10  	"go.uber.org/zap"
    11  	"os"
    12  	"strings"
    13  )
    14  
    15  const (
    16  	subnetPrivate = "private"
    17  	subnetPublic  = "public"
    18  )
    19  
    20  // Client interface for OCI Clients
    21  type OCIClient interface {
    22  	GetSubnetByID(ctx context.Context, subnetID string, log *zap.SugaredLogger) (*core.Subnet, error)
    23  	GetImageIDByName(ctx context.Context, compartmentID, displayName, operatingSystem, operatingSystemVersion, shape string, log *zap.SugaredLogger) (string, error)
    24  	GetVcnIDByName(ctx context.Context, compartmentID, displayName string, log *zap.SugaredLogger) (string, error)
    25  	GetVcnCIDRByName(ctx context.Context, compartmentID, displayName string, log *zap.SugaredLogger) (string, error)
    26  	GetSubnetIDByName(ctx context.Context, compartmentID, vcnID, displayName string, log *zap.SugaredLogger) (string, error)
    27  	GetSubnetCIDRByName(ctx context.Context, compartmentID, vcnID, displayName string, log *zap.SugaredLogger) (string, error)
    28  	GetNsgIDByName(ctx context.Context, compartmentID, vcnID, displayName string, log *zap.SugaredLogger) (string, error)
    29  	UpdateNSG(ctx context.Context, nsgID string, rule *SecurityRuleDetails, log *zap.SugaredLogger) error
    30  }
    31  
    32  // ClientImpl OCI Client implementation
    33  type ClientImpl struct {
    34  	vnClient      core.VirtualNetworkClient
    35  	computeClient core.ComputeClient
    36  }
    37  
    38  type SecurityRuleDetails struct {
    39  	Protocol    string
    40  	Description string
    41  	Source      string
    42  	IsStateless bool
    43  	TCPPortMax  int
    44  	TCPPortMin  int
    45  }
    46  
    47  // NewClient creates a new OCI Client
    48  func NewClient(provider common.ConfigurationProvider) (OCIClient, error) {
    49  	net, err := core.NewVirtualNetworkClientWithConfigurationProvider(provider)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  
    54  	compute, err := core.NewComputeClientWithConfigurationProvider(provider)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  
    59  	return &ClientImpl{
    60  		vnClient:      net,
    61  		computeClient: compute,
    62  	}, nil
    63  }
    64  
    65  // GetImageIDByName retrieves an image OCID given an image name and a compartment id, if that image exists.
    66  func (c *ClientImpl) GetImageIDByName(ctx context.Context, compartmentID, displayName, operatingSystem, operatingSystemVersion, shape string, log *zap.SugaredLogger) (string, error) {
    67  	images, err := c.computeClient.ListImages(ctx, core.ListImagesRequest{
    68  		CompartmentId:          &compartmentID,
    69  		OperatingSystem:        &operatingSystem,
    70  		OperatingSystemVersion: &operatingSystemVersion,
    71  		Shape:                  &shape,
    72  		SortBy:                 "TIMECREATED",
    73  	})
    74  	if err != nil {
    75  		return "", err
    76  	}
    77  	if len(images.Items) == 0 {
    78  		log.Errorf("no images found for %s/%s", compartmentID, displayName)
    79  		return "", err
    80  	}
    81  
    82  	for _, image := range images.Items {
    83  		if strings.Contains(*image.DisplayName, displayName) {
    84  			log.Infof(" Image details: display name= %v", *image.DisplayName)
    85  			return *image.Id, nil
    86  		}
    87  	}
    88  	// default return
    89  	return *images.Items[0].Id, nil
    90  }
    91  
    92  // GetVcnIDByName retrieves an VCN OCID given a vcn name and a compartment id, if the vcn exists.
    93  func (c *ClientImpl) GetVcnIDByName(ctx context.Context, compartmentID, displayName string, log *zap.SugaredLogger) (string, error) {
    94  	vcns, err := c.vnClient.ListVcns(ctx, core.ListVcnsRequest{
    95  		CompartmentId: &compartmentID,
    96  		DisplayName:   &displayName,
    97  	})
    98  	if err != nil {
    99  		return "", err
   100  	}
   101  
   102  	if len(vcns.Items) == 0 {
   103  		log.Errorf("no vcns found for %s/%s", compartmentID, displayName)
   104  		return "", err
   105  	}
   106  	return *vcns.Items[0].Id, nil
   107  }
   108  
   109  // GetVcnCIDRByName retrieves an VCN CIDR given a vcn name and a compartment id, if the vcn exists.
   110  func (c *ClientImpl) GetVcnCIDRByName(ctx context.Context, compartmentID, displayName string, log *zap.SugaredLogger) (string, error) {
   111  	vcns, err := c.vnClient.ListVcns(ctx, core.ListVcnsRequest{
   112  		CompartmentId: &compartmentID,
   113  		DisplayName:   &displayName,
   114  	})
   115  	if err != nil {
   116  		return "", err
   117  	}
   118  
   119  	if len(vcns.Items) == 0 {
   120  		log.Errorf("no vcns found for %s/%s", compartmentID, displayName)
   121  		return "", err
   122  	}
   123  	return vcns.Items[0].CidrBlocks[0], nil
   124  }
   125  
   126  // GetSubnetIDByName retrieves an Subnet OCID given a subnet name and a compartment id, if the subnet exists.
   127  func (c *ClientImpl) GetSubnetIDByName(ctx context.Context, compartmentID, vcnID, displayName string, log *zap.SugaredLogger) (string, error) {
   128  	subnets, err := c.vnClient.ListSubnets(ctx, core.ListSubnetsRequest{
   129  		CompartmentId: &compartmentID,
   130  		VcnId:         &vcnID,
   131  		DisplayName:   &displayName,
   132  	})
   133  	if err != nil {
   134  		return "", err
   135  	}
   136  
   137  	if len(subnets.Items) == 0 {
   138  		log.Errorf("no subnet found for %s/%s", compartmentID, displayName)
   139  		return "", err
   140  	}
   141  	return *subnets.Items[0].Id, nil
   142  }
   143  
   144  // GetSubnetCIDRByName retrieves an Subnet CIDR block given a subnet name and a compartment id, if the subnet exists.
   145  func (c *ClientImpl) GetSubnetCIDRByName(ctx context.Context, compartmentID, vcnID, displayName string, log *zap.SugaredLogger) (string, error) {
   146  	subnets, err := c.vnClient.ListSubnets(ctx, core.ListSubnetsRequest{
   147  		CompartmentId: &compartmentID,
   148  		VcnId:         &vcnID,
   149  		DisplayName:   &displayName,
   150  	})
   151  	if err != nil {
   152  		return "", err
   153  	}
   154  
   155  	if len(subnets.Items) == 0 {
   156  		log.Errorf("no subnet found for %s/%s", compartmentID, displayName)
   157  		return "", err
   158  	}
   159  	return *subnets.Items[0].CidrBlock, nil
   160  }
   161  
   162  // GetNsgIDByName retrieves an NSG OCID given a nsg name and a compartment id, if the nsg exists.
   163  func (c *ClientImpl) GetNsgIDByName(ctx context.Context, compartmentID, vcnID, displayName string, log *zap.SugaredLogger) (string, error) {
   164  	nsgs, err := c.vnClient.ListNetworkSecurityGroups(ctx, core.ListNetworkSecurityGroupsRequest{
   165  		CompartmentId: &compartmentID,
   166  		VcnId:         &vcnID,
   167  		DisplayName:   &displayName,
   168  	})
   169  	if err != nil {
   170  		return "", err
   171  	}
   172  
   173  	if len(nsgs.Items) == 0 {
   174  		log.Errorf("no nsg found for %s/%s", compartmentID, displayName)
   175  		return "", err
   176  	}
   177  
   178  	return *nsgs.Items[0].Id, nil
   179  }
   180  
   181  // UpdateNSG retrieves an NSG OCID given a nsg name and a compartment id, if the nsg exists.
   182  func (c *ClientImpl) UpdateNSG(ctx context.Context, nsgID string, rule *SecurityRuleDetails, log *zap.SugaredLogger) error {
   183  	var err error
   184  
   185  	ociCoreSecurityDetails := core.AddSecurityRuleDetails{
   186  		Direction:   core.AddSecurityRuleDetailsDirectionIngress,
   187  		Protocol:    &rule.Protocol,
   188  		Description: &rule.Description,
   189  		Source:      &rule.Source,
   190  		SourceType:  core.AddSecurityRuleDetailsSourceTypeCidrBlock,
   191  		IsStateless: &rule.IsStateless,
   192  	}
   193  
   194  	switch rule.Protocol {
   195  	case "6":
   196  		ociCoreSecurityDetails.TcpOptions = &core.TcpOptions{
   197  			DestinationPortRange: &core.PortRange{
   198  				Max: &rule.TCPPortMax,
   199  				Min: &rule.TCPPortMin,
   200  			},
   201  		}
   202  	}
   203  
   204  	_, err = c.vnClient.AddNetworkSecurityGroupSecurityRules(ctx, core.AddNetworkSecurityGroupSecurityRulesRequest{
   205  		NetworkSecurityGroupId: &nsgID,
   206  		AddNetworkSecurityGroupSecurityRulesDetails: core.AddNetworkSecurityGroupSecurityRulesDetails{
   207  			SecurityRules: []core.AddSecurityRuleDetails{
   208  				ociCoreSecurityDetails,
   209  			},
   210  		},
   211  	})
   212  
   213  	if err != nil {
   214  		log.Errorf("unable to update nsg '%s':  %v", nsgID, zap.Error(err))
   215  		return err
   216  	}
   217  
   218  	return nil
   219  }
   220  
   221  // GetSubnetByID retrieves a subnet given that subnet's Id.
   222  func (c *ClientImpl) GetSubnetByID(ctx context.Context, subnetID string, log *zap.SugaredLogger) (*core.Subnet, error) {
   223  	response, err := c.vnClient.GetSubnet(ctx, core.GetSubnetRequest{
   224  		SubnetId:        &subnetID,
   225  		RequestMetadata: common.RequestMetadata{},
   226  	})
   227  	if err != nil {
   228  		return nil, err
   229  	}
   230  
   231  	subnet := response.Subnet
   232  	return &subnet, nil
   233  }
   234  
   235  // SubnetAccess returns public or private, depending on a subnet's access type
   236  func SubnetAccess(subnet core.Subnet, log *zap.SugaredLogger) string {
   237  	if subnet.ProhibitPublicIpOnVnic != nil && subnet.ProhibitInternetIngress != nil && !*subnet.ProhibitPublicIpOnVnic && !*subnet.ProhibitInternetIngress {
   238  		return subnetPublic
   239  	}
   240  	return subnetPrivate
   241  }
   242  
   243  func GetOCIConfigurationProvider(log *zap.SugaredLogger) common.ConfigurationProvider {
   244  	_, err := os.Stat(OCIPrivateKeyPath)
   245  	if err != nil {
   246  		log.Errorf("file '%s' not found", OCIPrivateKeyPath)
   247  		return nil
   248  	}
   249  	data, err := os.ReadFile(OCIPrivateKeyPath)
   250  	if err != nil {
   251  		log.Error("failed reading file contents: ", zap.Error(err))
   252  		return nil
   253  	}
   254  	return common.NewRawConfigurationProvider(OCITenancyID, OCIUserID, OCIRegion, OCIFingerprint, strings.TrimSpace(string(data)), nil)
   255  }