Move the internal minion representation to match v1beta3

Moves to 'Spec' and 'Status' internally and removes duplicate
fields.  Moves Capacity into Spec and drops use of NodeResources
This commit is contained in:
Clayton Coleman 2014-11-19 17:39:10 -05:00
parent c688bd402f
commit 156000ef6d
16 changed files with 93 additions and 66 deletions

View File

@ -637,30 +637,42 @@ type EndpointsList struct {
Items []Endpoints `json:"items" yaml:"items"`
}
// NodeResources represents resources on a Kubernetes system node
// NodeSpec describes the attributes that a node is created with.
type NodeSpec struct {
// Capacity represents the available resources of a node
Capacity ResourceList `json:"capacity,omitempty" yaml:"capacity,omitempty"`
}
// 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 is an object for conveying resource information about a node.
// see https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/resources.md for more details.
// TODO: Use ResourceList instead?
type NodeResources struct {
// Capacity represents the available resources.
// Capacity represents the available resources of a node
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 ID.
// Minion is a worker node in Kubernetenes
// The name of the minion according to etcd is in ObjectMeta.Name.
// TODO: Rename to Node
type Minion struct {
TypeMeta `json:",inline" yaml:",inline"`
ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
// 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"`
// Labels for the node
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
// Spec defines the behavior of a node.
Spec NodeSpec `json:"spec,omitempty" yaml:"spec,omitempty"`
// Status describes the current status of a Node
Status NodeStatus `json:"status,omitempty" yaml:"status,omitempty"`
}
// MinionList is a list of minions.

View File

@ -498,12 +498,12 @@ func init() {
if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil {
if err := s.Convert(&in.ObjectMeta.Labels, &out.Labels, 0); err != nil {
return err
}
out.HostIP = in.HostIP
return s.Convert(&in.NodeResources, &out.NodeResources, 0)
out.HostIP = in.Status.HostIP
return s.Convert(&in.Spec.Capacity, &out.NodeResources.Capacity, 0)
},
func(in *Minion, out *newer.Minion, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
@ -512,12 +512,12 @@ func init() {
if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil {
if err := s.Convert(&in.Labels, &out.ObjectMeta.Labels, 0); err != nil {
return err
}
out.HostIP = in.HostIP
return s.Convert(&in.NodeResources, &out.NodeResources, 0)
out.Status.HostIP = in.HostIP
return s.Convert(&in.NodeResources.Capacity, &out.Spec.Capacity, 0)
},
func(in *newer.BoundPod, out *BoundPod, s conversion.Scope) error {

View File

@ -427,12 +427,12 @@ func init() {
if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil {
if err := s.Convert(&in.ObjectMeta.Labels, &out.Labels, 0); err != nil {
return err
}
out.HostIP = in.HostIP
return s.Convert(&in.NodeResources, &out.NodeResources, 0)
out.HostIP = in.Status.HostIP
return s.Convert(&in.Spec.Capacity, &out.NodeResources.Capacity, 0)
},
func(in *Minion, out *newer.Minion, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
@ -441,12 +441,12 @@ func init() {
if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil {
if err := s.Convert(&in.Labels, &out.ObjectMeta.Labels, 0); err != nil {
return err
}
out.HostIP = in.HostIP
return s.Convert(&in.NodeResources, &out.NodeResources, 0)
out.Status.HostIP = in.HostIP
return s.Convert(&in.NodeResources.Capacity, &out.Spec.Capacity, 0)
},
func(in *newer.BoundPod, out *BoundPod, s conversion.Scope) error {

View File

@ -664,24 +664,22 @@ type EndpointsList struct {
// NodeSpec describes the attributes that a node is created with.
type NodeSpec struct {
// Capacity represents the available resources of a node
// see https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/resources.md for more details.
Capacity ResourceList `json:"capacity,omitempty" yaml:"capacity,omitempty"`
}
// NodeStatus is information about the current status of a node.
type NodeStatus struct {
}
// 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"`
// Queried from cloud provider, if available.
HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty"`
}
type ResourceName string
type ResourceList map[ResourceName]util.IntOrString
// Node is a worker node in Kubernetenes.
// Node is a worker node in Kubernetes.
// The name of the node according to etcd is in ID.
type Node struct {
TypeMeta `json:",inline" yaml:",inline"`
@ -692,9 +690,6 @@ 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"`
}
// NodeList is a list of minions.

View File

@ -544,9 +544,7 @@ func ValidateMinion(minion *api.Minion) errs.ValidationErrorList {
// ValidateMinionUpdate tests to make sure a minion update can be applied. Modifies oldMinion.
func ValidateMinionUpdate(oldMinion *api.Minion, minion *api.Minion) errs.ValidationErrorList {
allErrs := errs.ValidationErrorList{}
// TODO: why we need two labels for minion.
oldMinion.Labels = minion.Labels
oldMinion.ObjectMeta.Labels = minion.ObjectMeta.Labels
if !reflect.DeepEqual(oldMinion, minion) {
allErrs = append(allErrs, fmt.Errorf("Update contains more than labels changes"))
}

View File

@ -1033,14 +1033,20 @@ func TestValidateMinion(t *testing.T) {
invalidSelector := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"}
successCases := []api.Minion{
{
ObjectMeta: api.ObjectMeta{Name: "abc"},
HostIP: "something",
ObjectMeta: api.ObjectMeta{
Name: "abc",
Labels: validSelector,
},
Status: api.NodeStatus{
HostIP: "something",
},
},
{
ObjectMeta: api.ObjectMeta{Name: "abc"},
Status: api.NodeStatus{
HostIP: "something",
},
},
}
for _, successCase := range successCases {
if errs := ValidateMinion(&successCase); len(errs) != 0 {
@ -1050,14 +1056,20 @@ func TestValidateMinion(t *testing.T) {
errorCases := map[string]api.Minion{
"zero-length Name": {
ObjectMeta: api.ObjectMeta{Name: ""},
HostIP: "something",
ObjectMeta: api.ObjectMeta{
Name: "",
Labels: validSelector,
},
Status: api.NodeStatus{
HostIP: "something",
},
},
"invalid-labels": {
ObjectMeta: api.ObjectMeta{Name: "abc-123"},
ObjectMeta: api.ObjectMeta{
Name: "abc-123",
Labels: invalidSelector,
},
},
}
for k, v := range errorCases {
errs := ValidateMinion(&v)

View File

@ -592,8 +592,10 @@ func TestCreateMinion(t *testing.T) {
ObjectMeta: api.ObjectMeta{
Name: "minion-1",
},
Status: api.NodeStatus{
HostIP: "123.321.456.654",
NodeResources: api.NodeResources{
},
Spec: api.NodeSpec{
Capacity: api.ResourceList{
resources.CPU: util.NewIntOrStringFromInt(1000),
resources.Memory: util.NewIntOrStringFromInt(1024 * 1024),

View File

@ -71,7 +71,9 @@ func (s *MinionController) SyncStatic(period time.Duration) error {
}
_, err := s.kubeClient.Minions().Create(&api.Minion{
ObjectMeta: api.ObjectMeta{Name: minionID},
NodeResources: *s.staticResources,
Spec: api.NodeSpec{
Capacity: s.staticResources.Capacity,
},
})
if err == nil {
registered.Insert(minionID)
@ -145,7 +147,7 @@ func (s *MinionController) cloudMinions() (*api.MinionList, error) {
resources = s.staticResources
}
if resources != nil {
result.Items[i].NodeResources = *resources
result.Items[i].Spec.Capacity = resources.Capacity
}
}
return result, nil

View File

@ -429,7 +429,7 @@ func (m *Master) getServersToValidate(c *Config) map[string]apiserver.Server {
glog.Errorf("Failed to list minions: %v", err)
}
for ix, node := range nodes.Items {
serversToValidate[fmt.Sprintf("node-%d", ix)] = apiserver.Server{Addr: node.HostIP, Port: 10250, Path: "/healthz"}
serversToValidate[fmt.Sprintf("node-%d", ix)] = apiserver.Server{Addr: node.Status.HostIP, Port: 10250, Path: "/healthz"}
}
return serversToValidate
}

View File

@ -135,7 +135,7 @@ func (rs *REST) ResourceLocation(ctx api.Context, id string) (string, error) {
if err != nil {
return "", err
}
host := minion.HostIP
host := minion.Status.HostIP
if host == "" {
host = minion.Name
}

View File

@ -130,7 +130,7 @@ func TestMinionStorageInvalidUpdate(t *testing.T) {
if !ok {
t.Fatalf("Object is not a minion: %#v", obj)
}
minion.HostIP = "1.2.3.4"
minion.Status.HostIP = "1.2.3.4"
if _, err = storage.Update(ctx, minion); err == nil {
t.Error("Unexpected non-error.")
}
@ -163,14 +163,20 @@ func TestMinionStorageValidatesCreate(t *testing.T) {
invalidSelector := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"}
failureCases := map[string]api.Minion{
"zero-length Name": {
ObjectMeta: api.ObjectMeta{Name: ""},
HostIP: "something",
ObjectMeta: api.ObjectMeta{
Name: "",
Labels: validSelector,
},
Status: api.NodeStatus{
HostIP: "something",
},
},
"invalid-labels": {
ObjectMeta: api.ObjectMeta{Name: "abc-123"},
ObjectMeta: api.ObjectMeta{
Name: "abc-123",
Labels: invalidSelector,
},
},
}
for _, failureCase := range failureCases {
c, err := storage.Create(ctx, &failureCase)

View File

@ -35,7 +35,7 @@ func MakeMinionList(minions []string, nodeResources api.NodeResources) *api.Mini
}
for i := range minions {
list.Items[i].Name = minions[i]
list.Items[i].NodeResources = nodeResources
list.Items[i].Spec.Capacity = nodeResources.Capacity
}
return &list
}

View File

@ -122,8 +122,8 @@ func (r *ResourceFit) PodFitsResources(pod api.Pod, existingPods []api.Pod, node
}
// TODO: convert to general purpose resource matching, when pods ask for resources
totalMilliCPU := int(resources.GetFloatResource(info.NodeResources.Capacity, resources.CPU, 0) * 1000)
totalMemory := resources.GetIntegerResource(info.NodeResources.Capacity, resources.Memory, 0)
totalMilliCPU := int(resources.GetFloatResource(info.Spec.Capacity, resources.CPU, 0) * 1000)
totalMemory := resources.GetIntegerResource(info.Spec.Capacity, resources.Memory, 0)
fitsCPU := totalMilliCPU == 0 || (totalMilliCPU-milliCPURequested) >= podRequest.milliCPU
fitsMemory := totalMemory == 0 || (totalMemory-memoryRequested) >= podRequest.memory

View File

@ -111,7 +111,7 @@ func TestPodFitsResources(t *testing.T) {
},
}
for _, test := range tests {
node := api.Minion{NodeResources: makeResources(10, 20)}
node := api.Minion{Spec: api.NodeSpec{Capacity: makeResources(10, 20).Capacity}}
fit := ResourceFit{FakeNodeInfo(node)}
fits, err := fit.PodFitsResources(test.pod, test.existingPods, "machine")
@ -335,7 +335,7 @@ func TestPodFitsSelector(t *testing.T) {
},
}
for _, test := range tests {
node := api.Minion{Labels: test.labels}
node := api.Minion{ObjectMeta: api.ObjectMeta{Labels: test.labels}}
fit := NodeSelector{FakeNodeInfo(node)}
fits, err := fit.PodSelectorMatches(test.pod, []api.Pod{}, "machine")

View File

@ -41,8 +41,8 @@ func calculateOccupancy(node api.Minion, pods []api.Pod) HostPriority {
}
}
percentageCPU := calculatePercentage(totalCPU, resources.GetIntegerResource(node.NodeResources.Capacity, resources.CPU, 0))
percentageMemory := calculatePercentage(totalMemory, resources.GetIntegerResource(node.NodeResources.Capacity, resources.Memory, 0))
percentageCPU := calculatePercentage(totalCPU, resources.GetIntegerResource(node.Spec.Capacity, resources.CPU, 0))
percentageMemory := calculatePercentage(totalMemory, resources.GetIntegerResource(node.Spec.Capacity, resources.Memory, 0))
glog.V(4).Infof("Least Requested Priority, AbsoluteRequested: (%d, %d) Percentage:(%d\\%m, %d\\%)", totalCPU, totalMemory, percentageCPU, percentageMemory)
return HostPriority{

View File

@ -28,7 +28,7 @@ import (
func makeMinion(node string, cpu, memory int) api.Minion {
return api.Minion{
ObjectMeta: api.ObjectMeta{Name: node},
NodeResources: api.NodeResources{
Spec: api.NodeSpec{
Capacity: api.ResourceList{
resources.CPU: util.NewIntOrStringFromInt(cpu),
resources.Memory: util.NewIntOrStringFromInt(memory),