Skip to content

Commit

Permalink
Allowed Aerospike image tags to have hyphenated prefix and suffix
Browse files Browse the repository at this point in the history
  • Loading branch information
ashishshinde committed Sep 8, 2022
1 parent 7149fc9 commit 19909ce
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 31 deletions.
69 changes: 40 additions & 29 deletions api/v1beta1/aerospikecluster_validating_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ var immutableNetworkParams = []string{
"tls-alternate-access-port",
}

var versionPrefixRegex = regexp.MustCompile("^.*-")
var versionRegex = regexp.MustCompile(`([0-9]+(\.[0-9]+)+)`)

// +kubebuilder:webhook:path=/validate-asdb-aerospike-com-v1beta1-aerospikecluster,mutating=false,failurePolicy=fail,sideEffects=None,groups=asdb.aerospike.com,resources=aerospikeclusters,verbs=create;update,versions=v1beta1,name=vaerospikecluster.kb.io,admissionReviewVersions={v1,v1beta1}

Expand Down Expand Up @@ -205,7 +205,7 @@ func (c *AerospikeCluster) validate(aslog logr.Logger) error {

// Validate common aerospike config
if err := c.validateAerospikeConfig(
aslog, configMap, &c.Spec.Storage, int(c.Spec.Size),
configMap, &c.Spec.Storage, int(c.Spec.Size),
); err != nil {
return err
}
Expand All @@ -217,13 +217,13 @@ func (c *AerospikeCluster) validate(aslog logr.Logger) error {
}

if err := validateRequiredFileStorageForMetadata(
aslog, *configMap, &c.Spec.Storage, c.Spec.ValidationPolicy, version,
*configMap, &c.Spec.Storage, c.Spec.ValidationPolicy, version,
); err != nil {
return err
}

if err := validateRequiredFileStorageForFeatureConf(
aslog, *configMap, &c.Spec.Storage,
*configMap, &c.Spec.Storage,
); err != nil {
return err
}
Expand All @@ -244,7 +244,7 @@ func (c *AerospikeCluster) validate(aslog logr.Logger) error {
}

// Validate Sidecars
if err := c.validatePodSpec(aslog); err != nil {
if err := c.validatePodSpec(); err != nil {
return err
}

Expand Down Expand Up @@ -454,7 +454,7 @@ func (c *AerospikeCluster) validateRackConfig(aslog logr.Logger) error {
// Replication-factor in rack and commonConfig can not be different
storage := rack.Storage
if err := c.validateAerospikeConfig(
aslog, &config, &storage, int(c.Spec.Size),
&config, &storage, int(c.Spec.Size),
); err != nil {
return err
}
Expand Down Expand Up @@ -507,8 +507,7 @@ func validateClusterSize(_ logr.Logger, version string, sz int) error {
}

func (c *AerospikeCluster) validateAerospikeConfig(
aslog logr.Logger, configSpec *AerospikeConfigSpec,
storage *AerospikeStorageSpec, clSize int,
configSpec *AerospikeConfigSpec, storage *AerospikeStorageSpec, clSize int,
) error {
config := configSpec.Value

Expand Down Expand Up @@ -554,7 +553,7 @@ func (c *AerospikeCluster) validateAerospikeConfig(
nsListInterface,
)
} else if err := validateNamespaceConfig(
aslog, nsList, storage, clSize,
nsList, storage, clSize,
); err != nil {
return err
}
Expand Down Expand Up @@ -736,8 +735,8 @@ func validateNetworkConnection(
}

func validateNamespaceConfig(
aslog logr.Logger, nsConfInterfaceList []interface{},
storage *AerospikeStorageSpec, clSize int,
nsConfInterfaceList []interface{}, storage *AerospikeStorageSpec,
clSize int,
) error {
if len(nsConfInterfaceList) == 0 {
return fmt.Errorf("aerospikeConfig.namespace list cannot be empty")
Expand All @@ -759,7 +758,7 @@ func validateNamespaceConfig(
}

if err := validateNamespaceReplicationFactor(
aslog, nsConf, clSize,
nsConf, clSize,
); err != nil {
return err
}
Expand Down Expand Up @@ -864,7 +863,7 @@ func validateNamespaceConfig(

file = strings.TrimSpace(file.(string))

// File list Fields cannot be more that 2 in single line. Two in shadow device case. Validate.
// File list Fields cannot be more than 2 in single line. Two in shadow device case. Validate.
if len(strings.Fields(file.(string))) > 2 {
return fmt.Errorf(
"invalid file name %v. Max 2 file can be mentioned in single line (Shadow file config)",
Expand Down Expand Up @@ -949,7 +948,7 @@ func validateNamespaceConfig(
}

func validateNamespaceReplicationFactor(
aslog logr.Logger, nsConf map[string]interface{}, clSize int,
nsConf map[string]interface{}, clSize int,
) error {
// Validate replication-factor with cluster size only at the time of deployment
rfInterface, ok := nsConf["replication-factor"]
Expand Down Expand Up @@ -1097,9 +1096,7 @@ func validateAerospikeConfigUpdate(
}
}

if err := validateNsConfUpdate(
aslog, incomingSpec, outgoingSpec,
); err != nil {
if err := validateNsConfUpdate(incomingSpec, outgoingSpec); err != nil {
return err
}

Expand All @@ -1121,9 +1118,7 @@ func validateNetworkConnectionUpdate(
return nil
}

func validateNsConfUpdate(
aslog logr.Logger, newConfSpec, oldConfSpec *AerospikeConfigSpec,
) error {
func validateNsConfUpdate(newConfSpec, oldConfSpec *AerospikeConfigSpec) error {
newConf := newConfSpec.Value
oldConf := oldConfSpec.Value

Expand Down Expand Up @@ -1204,9 +1199,8 @@ func validateAerospikeConfigSchema(
}

func validateRequiredFileStorageForMetadata(
aslog logr.Logger, configSpec AerospikeConfigSpec,
storage *AerospikeStorageSpec, validationPolicy *ValidationPolicySpec,
version string,
configSpec AerospikeConfigSpec, storage *AerospikeStorageSpec,
validationPolicy *ValidationPolicySpec, version string,
) error {

_, fileStorageList, err := storage.GetAerospikeStorageList()
Expand Down Expand Up @@ -1271,8 +1265,7 @@ func validateRequiredFileStorageForMetadata(
}

func validateRequiredFileStorageForFeatureConf(
aslog logr.Logger, configSpec AerospikeConfigSpec,
storage *AerospikeStorageSpec,
configSpec AerospikeConfigSpec, storage *AerospikeStorageSpec,
) error {
// TODO Add validation for feature key file.
featureKeyFilePaths := getFeatureKeyFilePaths(configSpec)
Expand All @@ -1293,6 +1286,12 @@ func validateRequiredFileStorageForFeatureConf(
return nil
}

//
// GetImageVersion extracts the Aerospike version from a container image.
// The implementation extracts the image tag and find the longest string from
// it that is a version string.
// Note: The behaviour should match the operator's python implementation in
// init container extracting version.
func GetImageVersion(imageStr string) (string, error) {
_, _, version := ParseDockerImageTag(imageStr)

Expand All @@ -1302,10 +1301,22 @@ func GetImageVersion(imageStr string) (string, error) {
)
}

// Ignore special prefixes.
version = string(versionPrefixRegex.ReplaceAll([]byte(version), []byte("")))
// Ignore special prefixes and suffixes.
matches := versionRegex.FindAllString(version, -1)
if matches == nil || len(matches) < 1 {
return "", fmt.Errorf(
"invalid image version format: %v", version,
)
}

longest := 0
for i := range matches {
if len(matches[i]) >= len(matches[longest]) {
longest = i
}
}

return version, nil
return matches[longest], nil
}

// isInMemoryNamespace returns true if this namespace config uses memory for storage.
Expand Down Expand Up @@ -1423,7 +1434,7 @@ func isPathParentOrSame(dir1 string, dir2 string) bool {
return false
}

func (c *AerospikeCluster) validatePodSpec(aslog logr.Logger) error {
func (c *AerospikeCluster) validatePodSpec() error {
if c.Spec.PodSpec.HostNetwork && c.Spec.PodSpec.MultiPodPerHost {
return fmt.Errorf("host networking cannot be enabled with multi pod per host")
}
Expand Down
5 changes: 5 additions & 0 deletions api/v1beta1/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@ func ParseDockerImageTag(tag string) (
}
r := regexp.MustCompile(`(?P<registry>[^/]+/)?(?P<image>[^:]+)(?P<version>:.+)?`)
matches := r.FindStringSubmatch(tag)

if matches == nil {
return "", "", ""
}

return matches[1], matches[2], strings.TrimPrefix(matches[3], ":")
}

Expand Down
2 changes: 1 addition & 1 deletion config/manager/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ kind: Kustomization
images:
- name: controller
newName: docker.io/aerospike/aerospike-kubernetes-operator-nightly
newTag: 2.2.0-dev2
newTag: 2.2.0-dev
28 changes: 27 additions & 1 deletion controllers/scripts/create_pod_status_patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,34 @@ def __str__(self):
f"{self.effective_wipe_method}"


def longest_match(matches):
longest = matches[0]
for i in range(0, len(matches)):
if isinstance(matches[i], str):
match = matches[i]
else:
match = matches[i][0]
if len(match) > len(longest):
longest = match
return longest


'''
The implementation extracts the image tag and find the longest string from it that is a version string.
Note: The behaviour should match the operator's go implementation for extracting version.
'''
def get_image_tag(image):
return re.search(r"\d+\.\d+\.\d+\.\d+$", image).group(0)
matches = re.findall(r":(.*)", image)
if not matches:
# Should not happen since the image tag is validate
raise OSError(f"Invalid image: {image}")

tag = longest_match(matches)
matches = re.findall(r"([0-9]+(\.[0-9]+)+)", tag)
if not matches:
# Should not happen since the image tag is validate
raise OSError(f"Invalid image tag for image: {image}")
return longest_match(matches)


def get_image_version(image):
Expand Down

0 comments on commit 19909ce

Please sign in to comment.