Skip to content

Commit

Permalink
Check kubernetes label value rules (appsody#557)
Browse files Browse the repository at this point in the history
* Check kubernetes label value rules

* update error message and regex

* Fixed tests
  • Loading branch information
kylegc authored and chilanti committed Oct 31, 2019
1 parent b83f016 commit b7cecde
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 17 deletions.
52 changes: 41 additions & 11 deletions cmd/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,27 +283,48 @@ func getProjectDir(config *RootCommandConfig) (string, error) {

// IsValidProjectName tests the given string against Appsody name rules.
// This common set of name rules for Appsody must comply to Kubernetes
// resource and Docker container name rules. The current rules are:
// resource name, Kubernetes label value, and Docker container name rules.
// The current rules are:
// 1. Must start with a lowercase letter
// 2. Must contain only lowercase letters, digits, and dashes
// 3. Must end with a letter or digit
// 4. Must be less than 128 characters
// 4. Must be 68 characters or less
func IsValidProjectName(name string) (bool, error) {
match, err := regexp.MatchString("^[a-z]([a-z0-9-]*[a-z0-9])?$", name)
if name == "" {
return false, errors.New("Invalid project-name. The name cannot be an empty string")
}
if len(name) > 68 {
return false, errors.Errorf("Invalid project-name \"%s\". The name must be 68 characters or less", name)
}

match, err := regexp.MatchString("^[a-z]([a-z0-9-]*[a-z0-9])?$", name)
if err != nil {
return false, err
}

if match {
if len(name) < 128 {
return match, nil
}
return false, errors.Errorf("Invalid project-name \"%s\". The name must be less than 128 characters", name)
return true, nil
}
return false, errors.Errorf("Invalid project-name \"%s\". The name must start with a lowercase letter, contain only lowercase letters, numbers, or dashes, and cannot end in a dash.", name)
}

func IsValidKubernetesLabelValue(value string) (bool, error) {
if value == "" {
return true, nil
}
if len(value) > 68 {
return false, errors.New("The label must be 68 characters or less")
}

return match, errors.Errorf("Invalid project-name \"%s\". The name must start with a lowercase letter, contain only lowercase letters, numbers, or dashes, and cannot end in a dash.", name)
match, err := regexp.MatchString("^[a-z0-9A-Z]([a-z0-9A-Z-_.]*[a-z0-9A-Z])?$", value)
if err != nil {
return false, err
}

if match {
return true, nil
}
return false, errors.Errorf("Invalid label \"%s\". The label must begin and end with an alphanumeric character ([a-z0-9A-Z]) with dashes (-), underscores (_), dots (.), and alphanumerics between.", value)
}

// ConvertToValidProjectName takes an existing string or directory path
Expand All @@ -314,8 +335,8 @@ func ConvertToValidProjectName(projectDir string) (string, error) {

if !valid {
projectName = strings.ToLower(filepath.Base(projectDir))
if len(projectName) >= 128 {
projectName = projectName[0:127]
if len(projectName) > 68 {
projectName = projectName[0:68]
}

if projectName[0] < 'a' || projectName[0] > 'z' {
Expand Down Expand Up @@ -589,10 +610,16 @@ func getConfigLabels(projectConfig ProjectConfig) (map[string]string, error) {
}

if projectConfig.Version != "" {
if valid, err := IsValidKubernetesLabelValue(projectConfig.Version); !valid {
return labels, errors.Errorf("%s version value is invalid. %v", ConfigFile, err)
}
labels[ociKeyPrefix+"version"] = projectConfig.Version
}

if projectConfig.License != "" {
if valid, err := IsValidKubernetesLabelValue(projectConfig.License); !valid {
return labels, errors.Errorf("%s license value is invalid. %v", ConfigFile, err)
}
labels[ociKeyPrefix+"licenses"] = projectConfig.License
}

Expand All @@ -608,7 +635,10 @@ func getConfigLabels(projectConfig ProjectConfig) (map[string]string, error) {
}

if projectConfig.ApplicationName != "" {
labels["dev.appsody.app"] = projectConfig.ApplicationName
if valid, err := IsValidKubernetesLabelValue(projectConfig.ApplicationName); !valid {
return labels, errors.Errorf("%s application-name value is invalid. %v", ConfigFile, err)
}
labels["dev.appsody.app.name"] = projectConfig.ApplicationName
}

return labels, nil
Expand Down
10 changes: 5 additions & 5 deletions cmd/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ var validProjectNameTests = []string{
"m",
"m1",
"appsody-project",
// 127 chars is valid
"a234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567",
// 68 chars is valid
"a2345678901234567890123456789012345678901234567890123456789012345678",
}

func TestValidProjectNames(t *testing.T) {
Expand Down Expand Up @@ -170,9 +170,9 @@ var invalidProjectNameTests = []struct {
{"path/to/pr0ject", "pr0ject"},
{"/path/to/pr0ject", "pr0ject"},
{"path/to/1my-project", "appsody-1my-project"},
// 128 chars is invalid
{"a2345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678",
"a234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567"},
// 69 chars is invalid
{"a23456789012345678901234567890123456789012345678901234567890123456789",
"a2345678901234567890123456789012345678901234567890123456789012345678"},
}

func TestInvalidProjectNames(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion functest/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ func TestBuildLabels(t *testing.T) {
}
}

if labelsMap["dev.appsody.app"] == nil {
if labelsMap["dev.appsody.app.name"] == nil {
t.Error("Could not find requested stack label in Docker image!")
}

Expand Down

0 comments on commit b7cecde

Please sign in to comment.