github.com/verrazzano/verrazzano@v1.7.0/platform-operator/internal/vzconfig/args.go (about)

     1  // Copyright (c) 2022, 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 vzconfig
     5  
     6  import (
     7  	"fmt"
     8  	vzapi "github.com/verrazzano/verrazzano/platform-operator/apis/verrazzano/v1alpha1"
     9  	"github.com/verrazzano/verrazzano/platform-operator/apis/verrazzano/v1beta1"
    10  	"github.com/verrazzano/verrazzano/platform-operator/apis/verrazzano/validators"
    11  	"github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/common/override"
    12  	corev1 "k8s.io/api/core/v1"
    13  	"k8s.io/apimachinery/pkg/runtime"
    14  	"net"
    15  	"reflect"
    16  	"sigs.k8s.io/controller-runtime/pkg/client"
    17  )
    18  
    19  var GetControllerRuntimeClient = validators.GetClient
    20  
    21  const invalidDataType = "value of externalIP is of type \"%v\", is invalid data type, expected properly formatted IP"
    22  
    23  // CheckExternalIPsArgs method goes through the key-value pair to detect the presence of the
    24  // specific key for the corresponding component that holds the external IP address
    25  // It also checks whether IP addresses are valid and provided in a List format
    26  func CheckExternalIPsArgs(installArgs []vzapi.InstallArgs, overrides []vzapi.Overrides, argsKeyName, jsonPath, compName, namespace string) error {
    27  	var keyPresent bool
    28  	var v1beta1Overrides = vzapi.ConvertValueOverridesToV1Beta1(overrides)
    29  	overrideYAMLs, err := getOverrideYAMLs(v1beta1Overrides, namespace)
    30  	if err != nil {
    31  		return err
    32  	}
    33  
    34  	for _, o := range overrideYAMLs {
    35  		value, err := override.ExtractValueFromOverrideString(o, jsonPath)
    36  		if err != nil {
    37  			return err
    38  		}
    39  		if value == nil {
    40  			continue
    41  		}
    42  		v, err := castValuesToString(value)
    43  		if err != nil {
    44  			return err
    45  		}
    46  		if v != nil {
    47  			keyPresent = true
    48  			if err := validateExternalIP(v, jsonPath, compName); err != nil {
    49  				return err
    50  			}
    51  		}
    52  	}
    53  	if keyPresent {
    54  		return nil
    55  	}
    56  
    57  	for _, installArg := range installArgs {
    58  		if installArg.Name == argsKeyName {
    59  			keyPresent = true
    60  			if err := validateExternalIP(installArg.ValueList, installArg.Name, compName); err != nil {
    61  				return err
    62  			}
    63  		}
    64  	}
    65  	if !keyPresent {
    66  		return fmt.Errorf("Key \"%v\" not found for component \"%v\" for type NodePort", argsKeyName, compName)
    67  	}
    68  	return nil
    69  }
    70  
    71  // CheckExternalIPsOverridesArgs method goes through the key-value pair to detect the presence of the
    72  // specific key for the corresponding component that holds the external IP address
    73  // It also checks whether IP addresses are valid and provided in a List format
    74  func CheckExternalIPsOverridesArgs(overrides []v1beta1.Overrides, jsonPath, compName string, namespace string) error {
    75  	overrideYAMLs, err := getOverrideYAMLs(overrides, namespace)
    76  	if err != nil {
    77  		return err
    78  	}
    79  	for _, o := range overrideYAMLs {
    80  		value, err := override.ExtractValueFromOverrideString(o, jsonPath)
    81  		if err != nil {
    82  			return err
    83  		}
    84  		if value == nil {
    85  			continue
    86  		}
    87  		v, err := castValuesToString(value)
    88  		if err != nil {
    89  			return err
    90  		}
    91  		if v != nil {
    92  			if err := validateExternalIP(v, jsonPath, compName); err != nil {
    93  				return err
    94  			}
    95  		}
    96  	}
    97  	return nil
    98  }
    99  
   100  // CheckExternalIPsOverridesArgsWithPaths method goes through the key-value pair to detect the presence of the
   101  // specific keys for the corresponding component that holds the Service type and external IP address
   102  // It checks whether the service is of a specific type.
   103  // It also checks whether IP addresses are valid and provided in a List format
   104  func CheckExternalIPsOverridesArgsWithPaths(overrides []v1beta1.Overrides, jsonBasePath, serviceTypePath, serviceTypeValue, externalIPPath, compName, namespace string) error {
   105  	overrideYAMLs, err := getOverrideYAMLs(overrides, namespace)
   106  	if err != nil {
   107  		return err
   108  	}
   109  
   110  	for _, o := range overrideYAMLs {
   111  		value, err := override.ExtractValueFromOverrideString(o, jsonBasePath)
   112  		if err != nil {
   113  			return err
   114  		}
   115  
   116  		if value != nil {
   117  			valueMap := value.(map[string]interface{})
   118  			extractedIP := valueMap[externalIPPath]
   119  			if extractedIP == nil {
   120  				continue
   121  			}
   122  			extractedType := valueMap[serviceTypePath]
   123  			externalIPPathFull := jsonBasePath + "." + externalIPPath
   124  			extractedIPsArray, err := castValuesToString(extractedIP)
   125  			if err != nil {
   126  				return err
   127  			}
   128  			if extractedType != nil && extractedType == serviceTypeValue {
   129  				err := validateExternalIP(extractedIPsArray, externalIPPathFull, compName)
   130  				if err != nil {
   131  					return err
   132  				}
   133  			}
   134  		}
   135  	}
   136  	return nil
   137  }
   138  
   139  func validateExternalIP(addresses []string, key, compName string) error {
   140  	if len(addresses) < 1 {
   141  		return fmt.Errorf("At least one %s external IPs need to be set as an array for the key \"%v\"", compName, key)
   142  	}
   143  	for _, address := range addresses {
   144  		if net.ParseIP(address) == nil {
   145  			return fmt.Errorf("Controller external service key \"%v\" with IP \"%v\" is of invalid format for %s. Must be a proper IP address format", key, address, compName)
   146  		}
   147  	}
   148  	return nil
   149  }
   150  
   151  func castValuesToString(value interface{}) ([]string, error) {
   152  	var values []string
   153  	switch val := value.(type) {
   154  	case string:
   155  		values = append(values, value.(string))
   156  	case []interface{}:
   157  		valueArray := value.([]interface{})
   158  		for _, v := range valueArray {
   159  			if v != nil && reflect.TypeOf(v).String() == "string" {
   160  				values = append(values, v.(string))
   161  			} else {
   162  				return nil, fmt.Errorf(invalidDataType, reflect.TypeOf(v))
   163  			}
   164  		}
   165  	default:
   166  		return nil, fmt.Errorf(invalidDataType, val)
   167  	}
   168  
   169  	return values, nil
   170  }
   171  
   172  func getOverrideYAMLs(overrides []v1beta1.Overrides, namespace string) ([]string, error) {
   173  	client, err := getRunTimeClient()
   174  	if err != nil {
   175  		return nil, err
   176  	}
   177  	overrideYAMLs, err := override.GetInstallOverridesYAMLUsingClient(client, overrides, namespace)
   178  	if err != nil {
   179  		return nil, err
   180  	}
   181  	return overrideYAMLs, err
   182  }
   183  
   184  func getRunTimeClient() (client.Client, error) {
   185  	scheme := runtime.NewScheme()
   186  	_ = corev1.AddToScheme(scheme)
   187  	client, err := GetControllerRuntimeClient(scheme)
   188  	if err != nil {
   189  		return nil, err
   190  	}
   191  	return client, err
   192  }