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 }