github.com/verrazzano/verrazzano@v1.7.1/cluster-operator/apis/clusters/v1alpha1/common_webhook.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 v1alpha1 5 6 import ( 7 "context" 8 "github.com/verrazzano/verrazzano/cluster-operator/controllers/quickcreate/controller/oci" 9 ocnemeta "github.com/verrazzano/verrazzano/cluster-operator/controllers/quickcreate/controller/ocne" 10 vzerror "github.com/verrazzano/verrazzano/cluster-operator/internal/errors" 11 corev1 "k8s.io/api/core/v1" 12 "k8s.io/apimachinery/pkg/runtime" 13 "net/url" 14 ctrl "sigs.k8s.io/controller-runtime" 15 clipkg "sigs.k8s.io/controller-runtime/pkg/client" 16 "strings" 17 ) 18 19 type ( 20 validationContext struct { 21 Ctx context.Context 22 Cli clipkg.Client 23 OCIClientGetter func(creds *oci.Credentials) (oci.Client, error) 24 CredentialsLoader oci.CredentialsLoader 25 Errors *vzerror.ErrorAggregator 26 } 27 ) 28 29 var ( 30 NewValidationContext = newValidationContext 31 ) 32 33 func newValidationContext() (*validationContext, error) { 34 cli, err := getWebhookClient() 35 if err != nil { 36 return nil, err 37 } 38 return &validationContext{ 39 Ctx: context.Background(), 40 Cli: cli, 41 CredentialsLoader: oci.CredentialsLoaderImpl{}, 42 OCIClientGetter: oci.NewClient, 43 Errors: vzerror.NewAggregator("\n"), 44 }, nil 45 } 46 47 func getWebhookClient() (clipkg.Client, error) { 48 scheme := runtime.NewScheme() 49 _ = corev1.AddToScheme(scheme) 50 config, err := ctrl.GetConfig() 51 if err != nil { 52 return nil, err 53 } 54 return clipkg.New(config, clipkg.Options{Scheme: scheme}) 55 } 56 57 func addOCINodeErrors(ctx *validationContext, n OCINode, field string) { 58 if n.Shape == nil { 59 ctx.Errors.Addf("%s.shape is required", field) 60 } else if !strings.Contains(*n.Shape, "Flex") { 61 if n.OCPUs != nil { 62 ctx.Errors.Addf("%s.ocpus should only be specified when using flex shapes", field) 63 } 64 if n.MemoryGbs != nil { 65 ctx.Errors.Addf("%s.memoryGbs should only be specified when using flex shapes", field) 66 } 67 } 68 } 69 70 func addOCINetworkErrors(ctx *validationContext, ociClient oci.Client, network *Network, countSubnetRoles int, field string) { 71 if network == nil { 72 return 73 } 74 // If creating a new VCN, pre-existing VCN and subnet information should not be specified 75 if network.CreateVCN { 76 if len(network.VCN) > 0 { 77 ctx.Errors.Addf("%s.vcn should not be specified when creating a new VCN", field) 78 } 79 if len(network.Subnets) > 0 { 80 ctx.Errors.Addf("%s.subnets should not be specified when creating a new VCN", field) 81 } 82 } else { // If using an existing VCN and subnets, validate that these resources are accessible using the provided credentials. 83 if len(network.Subnets) != countSubnetRoles { 84 ctx.Errors.Addf("%s.subnets should have exactly %d subnets", field, countSubnetRoles) 85 } 86 if _, err := ociClient.GetVCNByID(ctx.Ctx, network.VCN); err != nil { 87 ctx.Errors.Addf("%s.vcn [%s] is not accessible", field, network.VCN) 88 } 89 subnetCache := map[string]bool{} 90 for i, subnet := range network.Subnets { 91 if ok := subnetCache[subnet.ID]; ok { 92 continue 93 } 94 ociSubnet, err := ociClient.GetSubnetByID(ctx.Ctx, subnet.ID, string(subnet.Role)) 95 if err != nil { 96 ctx.Errors.Addf("%s.subnets[%d] : [%s] is not accessible", field, i, subnet.ID) 97 } else { 98 subnetCache[ociSubnet.ID] = true 99 } 100 } 101 } 102 } 103 104 func addOCNEErrors(ctx *validationContext, ocne OCNE, field string) { 105 if _, err := ocnemeta.GetVersionDefaults(ctx.Ctx, ctx.Cli, ocne.Version); err != nil { 106 ctx.Errors.Addf("%s.version [%s] is not a known OCNE version", field, ocne.Version) 107 } 108 } 109 110 func addProxyErrors(ctx *validationContext, proxy *Proxy, field string) { 111 if proxy == nil { 112 return 113 } 114 if _, err := url.ParseRequestURI(proxy.HTTPSProxy); err != nil { 115 ctx.Errors.Addf("%s.httpsProxy is not a valid URL", field) 116 } 117 if _, err := url.ParseRequestURI(proxy.HTTPProxy); err != nil { 118 ctx.Errors.Addf("%s.httpProxy is not a valid URL", field) 119 } 120 } 121 122 func addPrivateRegistryErrors(ctx *validationContext, privateRegistry *PrivateRegistry, field string) { 123 if privateRegistry == nil { 124 return 125 } 126 if _, err := url.ParseRequestURI(privateRegistry.URL); err != nil { 127 ctx.Errors.Addf("%s.url is not a valid URL", field) 128 } 129 }