Skip to content

Commit

Permalink
Merge pull request kubernetes#3588 from vishh/api_resources
Browse files Browse the repository at this point in the history
Adding a 'Typename' strongtype for representing all resource types
  • Loading branch information
thockin committed Jan 23, 2015
2 parents 35d0042 + c32295a commit 5d73fa4
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 0 deletions.
7 changes: 7 additions & 0 deletions pkg/api/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (

"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
"github.com/GoogleCloudPlatform/kubernetes/pkg/conversion"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"

"github.com/davecgh/go-spew/spew"
)
Expand Down Expand Up @@ -60,3 +61,9 @@ var Semantic = conversion.EqualitiesOrDie(
return a.Amount.Cmp(b.Amount) == 0
},
)

var standardResources = util.NewStringSet(string(ResourceMemory), string(ResourceCPU))

func IsStandardResourceName(str string) bool {
return standardResources.Has(str)
}
18 changes: 18 additions & 0 deletions pkg/api/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,21 @@ func TestSemantic(t *testing.T) {
}
}
}

func TestIsStandardResource(t *testing.T) {
testCases := []struct {
input string
output bool
}{
{"cpu", true},
{"memory", true},
{"disk", false},
{"blah", false},
{"x.y.z", false},
}
for i, tc := range testCases {
if IsStandardResourceName(tc.input) != tc.output {
t.Errorf("case[%d], expected: %t, got: %t", i, tc.output, !tc.output)
}
}
}
2 changes: 2 additions & 0 deletions pkg/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -764,6 +764,8 @@ type NodeResources struct {
type ResourceName string

const (
// The default compute resource namespace for all standard resource types.
DefaultResourceNamespace = "kubernetes.io"
// CPU, in cores. (500m = .5 cores)
ResourceCPU ResourceName = "cpu"
// Memory, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024)
Expand Down
2 changes: 2 additions & 0 deletions pkg/api/v1beta3/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,8 @@ type NodeCondition struct {
type ResourceName string

const (
// The default compute resource namespace for all standard resource types.
DefaultResourceNamespace = "kubernetes.io"
// CPU, in cores. (500m = .5 cores)
ResourceCPU ResourceName = "cpu"
// Memory, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024)
Expand Down
27 changes: 27 additions & 0 deletions pkg/api/validation/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -622,3 +622,30 @@ func ValidateMinionUpdate(oldMinion *api.Node, minion *api.Node) errs.Validation
}
return allErrs
}

// Typename is a generic representation for all compute resource typenames.
// Refer to docs/resources.md for more details.
func ValidateResourceName(str string) errs.ValidationErrorList {
if !util.IsQualifiedName(str) {
return errs.ValidationErrorList{fmt.Errorf("invalid compute resource typename format %q", str)}
}

parts := strings.Split(str, "/")
switch len(parts) {
case 1:
if !api.IsStandardResourceName(parts[0]) {
return errs.ValidationErrorList{fmt.Errorf("invalid compute resource typename. %q is neither a standard resource type nor is fully qualified", str)}
}
break
case 2:
if parts[0] == api.DefaultResourceNamespace {
if !api.IsStandardResourceName(parts[1]) {
return errs.ValidationErrorList{fmt.Errorf("invalid compute resource typename. %q contains a compute resource type not supported", str)}

}
}
break
}

return errs.ValidationErrorList{}
}
37 changes: 37 additions & 0 deletions pkg/api/validation/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1440,3 +1440,40 @@ func TestValidateMinionUpdate(t *testing.T) {
}
}
}

func TestValidateResourceNames(t *testing.T) {
longString := "a"
for i := 0; i < 6; i++ {
longString += longString
}
table := []struct {
input string
success bool
}{
{"memory", true},
{"cpu", true},
{"network", false},
{"disk", false},
{"", false},
{".", false},
{"..", false},
{"kubernetes.io/cpu", true},
{"kubernetes.io/disk", false},
{"my.favorite.app.co/12345", true},
{"my.favorite.app.co/_12345", false},
{"my.favorite.app.co/12345_", false},
{"kubernetes.io/..", false},
{"kubernetes.io/" + longString, false},
{"kubernetes.io//", false},
{"kubernetes.io", false},
{"kubernetes.io/will/not/work/", false},
}
for _, item := range table {
err := ValidateResourceName(item.input)
if len(err) != 0 && item.success {
t.Errorf("expected no failure for input %q", item.input)
} else if len(err) == 0 && !item.success {
t.Errorf("expected failure for input %q", item.input)
}
}
}
19 changes: 19 additions & 0 deletions pkg/util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"path"
"reflect"
"regexp"
"runtime"
"strconv"
"strings"
"time"

"github.com/golang/glog"
Expand Down Expand Up @@ -183,3 +185,20 @@ func AllPtrFieldsNil(obj interface{}) bool {
}
return true
}

// Splits a fully qualified name and returns its namespace and name.
// Assumes that the input 'str' has been validated.
func SplitQualifiedName(str string) (string, string) {
parts := strings.Split(str, "/")
if len(parts) < 2 {
return "", str
}

return parts[0], parts[1]
}

// Joins 'namespace' and 'name' and returns a fully qualified name
// Assumes that the input is valid.
func JoinQualifiedName(namespace, name string) string {
return path.Join(namespace, name)
}
34 changes: 34 additions & 0 deletions pkg/util/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,3 +263,37 @@ func TestAllPtrFieldsNil(t *testing.T) {
}
}
}

func TestSplitQualifiedName(t *testing.T) {
testCases := []struct {
input string
output []string
}{
{"kubernetes.io/blah", []string{"kubernetes.io", "blah"}},
{"blah", []string{"", "blah"}},
{"kubernetes.io/blah/blah", []string{"kubernetes.io", "blah"}},
}
for i, tc := range testCases {
namespace, name := SplitQualifiedName(tc.input)
if namespace != tc.output[0] || name != tc.output[1] {
t.Errorf("case[%d]: expected (%q, %q), got (%q, %q)", i, tc.output[0], tc.output[1], namespace, name)
}
}
}

func TestJoinQualifiedName(t *testing.T) {
testCases := []struct {
input []string
output string
}{
{[]string{"kubernetes.io", "blah"}, "kubernetes.io/blah"},
{[]string{"blah", ""}, "blah"},
{[]string{"kubernetes.io", "blah"}, "kubernetes.io/blah"},
}
for i, tc := range testCases {
res := JoinQualifiedName(tc.input[0], tc.input[1])
if res != tc.output {
t.Errorf("case[%d]: expected %q, got %q", i, tc.output, res)
}
}
}

0 comments on commit 5d73fa4

Please sign in to comment.