Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a resource fit predicate. #1474

Merged
merged 1 commit into from
Oct 1, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 14 additions & 0 deletions pkg/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,12 +423,26 @@ type EndpointsList struct {

func (*EndpointsList) IsAnAPIObject() {}

// NodeResources represents resources on a Kubernetes system node
// see https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/resources.md for more details.
type NodeResources struct {
// Capacity represents the available resources.
Capacity ResourceList `json:"capacity,omitempty" yaml:"capacity,omitempty"`
}

type ResourceName string

// TODO Replace this with a more complete "Quantity" struct
type ResourceList map[ResourceName]util.IntOrString

// Minion is a worker node in Kubernetenes.
// The name of the minion according to etcd is in JSONBase.ID.
type Minion struct {
JSONBase `json:",inline" yaml:",inline"`
// Queried from cloud provider, if available.
HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty"`
// Resources available on the node
NodeResources NodeResources `json:"resources,omitempty" yaml:"resources,omitempty"`
}

func (*Minion) IsAnAPIObject() {}
Expand Down
13 changes: 13 additions & 0 deletions pkg/api/v1beta1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -436,12 +436,25 @@ type EndpointsList struct {

func (*EndpointsList) IsAnAPIObject() {}

// NodeResources represents resources on a Kubernetes system node
// see https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/resources.md for more details.
type NodeResources struct {
// Capacity represents the available resources.
Capacity ResourceList `json:"capacity,omitempty" yaml:"capacity,omitempty"`
}

type ResourceName string

type ResourceList map[ResourceName]util.IntOrString

// Minion is a worker node in Kubernetenes.
// The name of the minion according to etcd is in JSONBase.ID.
type Minion struct {
JSONBase `json:",inline" yaml:",inline"`
// Queried from cloud provider, if available.
HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty"`
// Resources available on the node
NodeResources NodeResources `json:"resources,omitempty" yaml:"resources,omitempty"`
}

func (*Minion) IsAnAPIObject() {}
Expand Down
13 changes: 13 additions & 0 deletions pkg/api/v1beta2/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -433,12 +433,25 @@ type EndpointsList struct {

func (*EndpointsList) IsAnAPIObject() {}

// NodeResources represents resources on a Kubernetes system node
// see https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/resources.md for more details.
type NodeResources struct {
// Capacity represents the available resources.
Capacity ResourceList `json:"capacity,omitempty" yaml:"capacity,omitempty"`
}

type ResourceName string

type ResourceList map[ResourceName]util.IntOrString

// Minion is a worker node in Kubernetenes.
// The name of the minion according to etcd is in JSONBase.ID.
type Minion struct {
JSONBase `json:",inline" yaml:",inline"`
// Queried from cloud provider, if available.
HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty"`
// Resources available on the node
NodeResources NodeResources `json:"resources,omitempty" yaml:"resources,omitempty"`
}

func (*Minion) IsAnAPIObject() {}
Expand Down
16 changes: 14 additions & 2 deletions pkg/api/v1beta3/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -550,10 +550,19 @@ type NodeSpec struct {

// NodeStatus is information about the current status of a node.
type NodeStatus struct {
// Queried from cloud provider, if available.
HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty"`
}

// NodeResources represents resources on a Kubernetes system node
// see https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/resources.md for more details.
type NodeResources struct {
// Capacity represents the available resources.
Capacity ResourceList `json:"capacity,omitempty" yaml:"capacity,omitempty"`
}

type ResourceName string

type ResourceList map[ResourceName]util.IntOrString

// Node is a worker node in Kubernetenes.
// The name of the node according to etcd is in JSONBase.ID.
type Node struct {
Expand All @@ -565,6 +574,9 @@ type Node struct {

// Status describes the current status of a Node
Status NodeStatus `json:"status,omitempty" yaml:"status,omitempty"`

// NodeResources describe the resoruces available on the node.
NodeResources NodeResources `json:"resources,omitempty" yaml:"resources,omitempty"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noticed this in code, but I think this belongs in Spec (not sure if there was another issue tracking it).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, the Capacity field of NodeResources belongs in Spec. NodeResources doesn't make sense.

Sadly, I didn't have time to vet resources.md at the time it was written. I should fix it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fortunately we don't expose v1beta3 yet and can still freely change it. The long refactor has at least had some benefits.

----- Original Message -----

@@ -565,6 +574,9 @@ type Node struct {

// Status describes the current status of a Node
Status NodeStatus `json:"status,omitempty" yaml:"status,omitempty"`
  • // NodeResources describe the resoruces available on the node.
  • NodeResources NodeResources json:"resources,omitempty" yaml:"resources,omitempty"

Actually, the Capacity field of NodeResources belongs in Spec. NodeResources
doesn't make sense.

Sadly, I didn't have time to vet resources.md at the time it was written. I
should fix it.


Reply to this email directly or view it on GitHub:
https://github.com/GoogleCloudPlatform/kubernetes/pull/1474/files#r20533015

}

// NodeList is a list of minions.
Expand Down
18 changes: 18 additions & 0 deletions pkg/resources/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
Copyright 2014 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// package resources has constants and utilities for dealing with resources
package resources
75 changes: 75 additions & 0 deletions pkg/resources/resources.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
Copyright 2014 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package resources

import (
"strconv"

"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/golang/glog"
)

const (
CPU api.ResourceName = "cpu"
Memory api.ResourceName = "memory"
)

// TODO: None of these currently handle SI units

func GetFloatResource(resources api.ResourceList, name api.ResourceName, def float64) float64 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please take a look at my in-progress #1185 and let's not duplicate work... feel free to take over that while I'm out if it's blocking you.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I'm going to defer this to a later CL.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think doing this in a Quantity type will be easiest to use.

value, found := resources[name]
if !found {
return def
}
if value.Kind == util.IntstrInt {
return float64(value.IntVal)
}
result, err := strconv.ParseFloat(value.StrVal, 64)
if err != nil {
glog.Errorf("parsing failed for %s: %s", name, value.StrVal)
return def
}
return result
}

func GetIntegerResource(resources api.ResourceList, name api.ResourceName, def int) int {
value, found := resources[name]
if !found {
return def
}
if value.Kind == util.IntstrInt {
return value.IntVal
}
result, err := strconv.Atoi(value.StrVal)
if err != nil {
glog.Errorf("parsing failed for %s: %s", name, value.StrVal)
return def
}
return result
}

func GetStringResource(resources api.ResourceList, name api.ResourceName, def string) string {
value, found := resources[name]
if !found {
return def
}
if value.Kind == util.IntstrInt {
return strconv.Itoa(value.IntVal)
}
return value.StrVal
}
169 changes: 169 additions & 0 deletions pkg/resources/resources_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/*
Copyright 2014 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package resources

import (
"testing"

"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)

func TestGetInteger(t *testing.T) {
tests := []struct {
res api.ResourceList
name api.ResourceName
expected int
def int
test string
}{
{
res: api.ResourceList{},
name: CPU,
expected: 1,
def: 1,
test: "nothing present",
},
{
res: api.ResourceList{
CPU: util.NewIntOrStringFromInt(2),
},
name: CPU,
expected: 2,
def: 1,
test: "present",
},
{
res: api.ResourceList{
Memory: util.NewIntOrStringFromInt(2),
},
name: CPU,
expected: 1,
def: 1,
test: "not-present",
},
{
res: api.ResourceList{
CPU: util.NewIntOrStringFromString("2"),
},
name: CPU,
expected: 2,
def: 1,
test: "present-string",
},
{
res: api.ResourceList{
CPU: util.NewIntOrStringFromString("foo"),
},
name: CPU,
expected: 1,
def: 1,
test: "present-invalid",
},
}

for _, test := range tests {
val := GetIntegerResource(test.res, test.name, test.def)
if val != test.expected {
t.Errorf("%s: expected: %d found %d", test.expected, val)
}
}
}
func TestGetFloat(t *testing.T) {
tests := []struct {
res api.ResourceList
name api.ResourceName
expected float64
def float64
test string
}{
{
res: api.ResourceList{},
name: CPU,
expected: 1.5,
def: 1.5,
test: "nothing present",
},
{
res: api.ResourceList{
CPU: util.NewIntOrStringFromInt(2),
},
name: CPU,
expected: 2.0,
def: 1.5,
test: "present",
},
{
res: api.ResourceList{
CPU: util.NewIntOrStringFromString("2.5"),
},
name: CPU,
expected: 2.5,
def: 1,
test: "present-string",
},
{
res: api.ResourceList{
CPU: util.NewIntOrStringFromString("foo"),
},
name: CPU,
expected: 1,
def: 1,
test: "present-invalid",
},
}

for _, test := range tests {
val := GetFloatResource(test.res, test.name, test.def)
if val != test.expected {
t.Errorf("%s: expected: %d found %d", test.expected, val)
}
}
}
func TestGetString(t *testing.T) {
tests := []struct {
res api.ResourceList
name api.ResourceName
expected string
def string
test string
}{
{
res: api.ResourceList{},
name: CPU,
expected: "foo",
def: "foo",
test: "nothing present",
},
{
res: api.ResourceList{
CPU: util.NewIntOrStringFromString("bar"),
},
name: CPU,
expected: "bar",
def: "foo",
test: "present",
},
}

for _, test := range tests {
val := GetStringResource(test.res, test.name, test.def)
if val != test.expected {
t.Errorf("%s: expected: %d found %d", test.expected, val)
}
}
}