From eb0b6f2bcfe3029f25316087d3e4ca9b3fcf8f8f Mon Sep 17 00:00:00 2001 From: Federico Simoncelli Date: Mon, 2 Mar 2015 04:39:12 -0500 Subject: [PATCH 1/3] kubelet: improve client url composition Signed-off-by: Federico Simoncelli --- pkg/client/kubelet.go | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/pkg/client/kubelet.go b/pkg/client/kubelet.go index 72882b5af7a..5f7c8ae1112 100644 --- a/pkg/client/kubelet.go +++ b/pkg/client/kubelet.go @@ -22,6 +22,7 @@ import ( "io/ioutil" "net" "net/http" + "net/url" "strconv" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" @@ -85,28 +86,24 @@ func NewKubeletClient(config *KubeletConfig) (KubeletClient, error) { }, nil } -func (c *HTTPKubeletClient) url(host string) string { - scheme := "http://" +func (c *HTTPKubeletClient) url(host, path, query string) string { + scheme := "http" if c.EnableHttps { - scheme = "https://" + scheme = "https" } - return fmt.Sprintf( - "%s%s", - scheme, - net.JoinHostPort(host, strconv.FormatUint(uint64(c.Port), 10))) + return (&url.URL{ + Scheme: scheme, + Host: net.JoinHostPort(host, strconv.FormatUint(uint64(c.Port), 10)), + Path: path, + RawQuery: query, + }).String() } // GetPodInfo gets information about the specified pod. func (c *HTTPKubeletClient) GetPodStatus(host, podNamespace, podID string) (api.PodStatusResult, error) { - request, err := http.NewRequest( - "GET", - fmt.Sprintf( - "%s/api/v1beta1/podInfo?podID=%s&podNamespace=%s", - c.url(host), - podID, - podNamespace), - nil) + query := url.Values{"podID": {podID}, "podNamespace": {podNamespace}} + request, err := http.NewRequest("GET", c.url(host, "/api/v1beta1/podInfo", query.Encode()), nil) status := api.PodStatusResult{} if err != nil { return status, err @@ -135,7 +132,7 @@ func (c *HTTPKubeletClient) GetPodStatus(host, podNamespace, podID string) (api. } func (c *HTTPKubeletClient) HealthCheck(host string) (probe.Result, error) { - return httprobe.DoHTTPProbe(fmt.Sprintf("%s/healthz", c.url(host)), c.Client) + return httprobe.DoHTTPProbe(c.url(host, "/healthz", ""), c.Client) } // FakeKubeletClient is a fake implementation of KubeletClient which returns an error From 1b18440f3557681d5177eda783ea4f125b7f0bc5 Mon Sep 17 00:00:00 2001 From: Federico Simoncelli Date: Sun, 1 Mar 2015 19:34:48 -0500 Subject: [PATCH 2/3] kubelet: add GetNodeInfo implementation Signed-off-by: Federico Simoncelli --- cmd/integration/integration.go | 4 ++ pkg/api/register.go | 2 + pkg/api/types.go | 7 +++ pkg/api/v1beta1/register.go | 2 + pkg/api/v1beta1/types.go | 7 +++ pkg/api/v1beta2/register.go | 2 + pkg/api/v1beta2/types.go | 7 +++ pkg/api/v1beta3/register.go | 2 + pkg/api/v1beta3/types.go | 7 +++ pkg/client/kubelet.go | 55 +++++++++++++------ .../controller/nodecontroller.go | 24 ++++++-- .../controller/nodecontroller_test.go | 4 ++ pkg/kubelet/server.go | 47 +++++++++++++++- 13 files changed, 144 insertions(+), 26 deletions(-) diff --git a/cmd/integration/integration.go b/cmd/integration/integration.go index 619e3ecf4b6..750875f3e56 100644 --- a/cmd/integration/integration.go +++ b/cmd/integration/integration.go @@ -97,6 +97,10 @@ func (fakeKubeletClient) GetPodStatus(host, podNamespace, podID string) (api.Pod return r, nil } +func (fakeKubeletClient) GetNodeInfo(host string) (api.NodeInfo, error) { + return api.NodeInfo{}, nil +} + func (fakeKubeletClient) HealthCheck(host string) (probe.Result, error) { return probe.Success, nil } diff --git a/pkg/api/register.go b/pkg/api/register.go index 976b409c37a..ef8991d3271 100644 --- a/pkg/api/register.go +++ b/pkg/api/register.go @@ -34,6 +34,7 @@ func init() { &Service{}, &NodeList{}, &Node{}, + &NodeInfo{}, &Status{}, &Endpoints{}, &EndpointsList{}, @@ -70,6 +71,7 @@ func (*ServiceList) IsAnAPIObject() {} func (*Endpoints) IsAnAPIObject() {} func (*EndpointsList) IsAnAPIObject() {} func (*Node) IsAnAPIObject() {} +func (*NodeInfo) IsAnAPIObject() {} func (*NodeList) IsAnAPIObject() {} func (*Binding) IsAnAPIObject() {} func (*Status) IsAnAPIObject() {} diff --git a/pkg/api/types.go b/pkg/api/types.go index 0b761327ab2..9409fc809d2 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -798,6 +798,13 @@ type NodeStatus struct { Addresses []NodeAddress `json:"addresses,omitempty"` } +// NodeInfo is the information collected on the node. +type NodeInfo struct { + TypeMeta `json:",inline"` + // Capacity represents the available resources of a node + Capacity ResourceList `json:"capacity,omitempty"` +} + type NodePhase string // These are the valid phases of node. diff --git a/pkg/api/v1beta1/register.go b/pkg/api/v1beta1/register.go index d98c038230c..53867530c7d 100644 --- a/pkg/api/v1beta1/register.go +++ b/pkg/api/v1beta1/register.go @@ -43,6 +43,7 @@ func init() { &EndpointsList{}, &Minion{}, &MinionList{}, + &NodeInfo{}, &Binding{}, &Status{}, &Event{}, @@ -77,6 +78,7 @@ func (*ServiceList) IsAnAPIObject() {} func (*Endpoints) IsAnAPIObject() {} func (*EndpointsList) IsAnAPIObject() {} func (*Minion) IsAnAPIObject() {} +func (*NodeInfo) IsAnAPIObject() {} func (*MinionList) IsAnAPIObject() {} func (*Binding) IsAnAPIObject() {} func (*Status) IsAnAPIObject() {} diff --git a/pkg/api/v1beta1/types.go b/pkg/api/v1beta1/types.go index ec7a8e47d47..c4183a9d7b9 100644 --- a/pkg/api/v1beta1/types.go +++ b/pkg/api/v1beta1/types.go @@ -628,6 +628,13 @@ type NodeStatus struct { Addresses []NodeAddress `json:"addresses,omitempty" description:"list of addresses reachable to the node"` } +// NodeInfo is the information collected on the node. +type NodeInfo struct { + TypeMeta `json:",inline"` + // Capacity represents the available resources. + Capacity ResourceList `json:"capacity,omitempty" description:"resource capacity of a node represented as a map of resource name to quantity of resource"` +} + type NodePhase string // These are the valid phases of node. diff --git a/pkg/api/v1beta2/register.go b/pkg/api/v1beta2/register.go index 39612227928..64499f038a3 100644 --- a/pkg/api/v1beta2/register.go +++ b/pkg/api/v1beta2/register.go @@ -42,6 +42,7 @@ func init() { &Endpoints{}, &EndpointsList{}, &Minion{}, + &NodeInfo{}, &MinionList{}, &Binding{}, &Status{}, @@ -77,6 +78,7 @@ func (*ServiceList) IsAnAPIObject() {} func (*Endpoints) IsAnAPIObject() {} func (*EndpointsList) IsAnAPIObject() {} func (*Minion) IsAnAPIObject() {} +func (*NodeInfo) IsAnAPIObject() {} func (*MinionList) IsAnAPIObject() {} func (*Binding) IsAnAPIObject() {} func (*Status) IsAnAPIObject() {} diff --git a/pkg/api/v1beta2/types.go b/pkg/api/v1beta2/types.go index 7a33b92ad6b..a85db7b7c8b 100644 --- a/pkg/api/v1beta2/types.go +++ b/pkg/api/v1beta2/types.go @@ -635,6 +635,13 @@ type NodeStatus struct { Addresses []NodeAddress `json:"addresses,omitempty" description:"list of addresses reachable to the node"` } +// NodeInfo is the information collected on the node. +type NodeInfo struct { + TypeMeta `json:",inline"` + // Capacity represents the available resources. + Capacity ResourceList `json:"capacity,omitempty" description:"resource capacity of a node represented as a map of resource name to quantity of resource"` +} + // Described the current lifecycle phase of a node. // // https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/node.md#node-phase diff --git a/pkg/api/v1beta3/register.go b/pkg/api/v1beta3/register.go index 93217e99d19..eb38ed3634e 100644 --- a/pkg/api/v1beta3/register.go +++ b/pkg/api/v1beta3/register.go @@ -40,6 +40,7 @@ func init() { &Endpoints{}, &EndpointsList{}, &Node{}, + &NodeInfo{}, &NodeList{}, &Binding{}, &Status{}, @@ -75,6 +76,7 @@ func (*ServiceList) IsAnAPIObject() {} func (*Endpoints) IsAnAPIObject() {} func (*EndpointsList) IsAnAPIObject() {} func (*Node) IsAnAPIObject() {} +func (*NodeInfo) IsAnAPIObject() {} func (*NodeList) IsAnAPIObject() {} func (*Binding) IsAnAPIObject() {} func (*Status) IsAnAPIObject() {} diff --git a/pkg/api/v1beta3/types.go b/pkg/api/v1beta3/types.go index 4bfe077bea2..51e5583405b 100644 --- a/pkg/api/v1beta3/types.go +++ b/pkg/api/v1beta3/types.go @@ -829,6 +829,13 @@ type NodeStatus struct { Addresses []NodeAddress `json:"addresses,omitempty" description:"list of addresses reachable to the node"` } +// NodeInfo is the information collected on the node. +type NodeInfo struct { + TypeMeta `json:",inline"` + // Capacity represents the available resources of a node + Capacity ResourceList `json:"capacity,omitempty"` +} + type NodePhase string // These are the valid phases of node. diff --git a/pkg/client/kubelet.go b/pkg/client/kubelet.go index 5f7c8ae1112..ec3d0efd462 100644 --- a/pkg/client/kubelet.go +++ b/pkg/client/kubelet.go @@ -29,6 +29,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" "github.com/GoogleCloudPlatform/kubernetes/pkg/probe" httprobe "github.com/GoogleCloudPlatform/kubernetes/pkg/probe/http" + "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" ) // ErrPodInfoNotAvailable may be returned when the requested pod info is not available. @@ -38,6 +39,7 @@ var ErrPodInfoNotAvailable = errors.New("no pod info available") type KubeletClient interface { KubeletHealthChecker PodInfoGetter + NodeInfoGetter } // KubeletHealthchecker is an interface for healthchecking kubelets @@ -53,6 +55,10 @@ type PodInfoGetter interface { GetPodStatus(host, podNamespace, podID string) (api.PodStatusResult, error) } +type NodeInfoGetter interface { + GetNodeInfo(host string) (api.NodeInfo, error) +} + // HTTPKubeletClient is the default implementation of PodInfoGetter and KubeletHealthchecker, accesses the kubelet over HTTP. type HTTPKubeletClient struct { Client *http.Client @@ -102,33 +108,41 @@ func (c *HTTPKubeletClient) url(host, path, query string) string { // GetPodInfo gets information about the specified pod. func (c *HTTPKubeletClient) GetPodStatus(host, podNamespace, podID string) (api.PodStatusResult, error) { - query := url.Values{"podID": {podID}, "podNamespace": {podNamespace}} - request, err := http.NewRequest("GET", c.url(host, "/api/v1beta1/podInfo", query.Encode()), nil) status := api.PodStatusResult{} - if err != nil { - return status, err - } - response, err := c.Client.Do(request) - if err != nil { - return status, err - } - defer response.Body.Close() + query := url.Values{"podID": {podID}, "podNamespace": {podNamespace}} + response, err := c.getEntity(host, "/api/v1beta1/podInfo", query.Encode(), &status) if response.StatusCode == http.StatusNotFound { return status, ErrPodInfoNotAvailable } + return status, err +} + +// GetNodeInfo gets information about the specified node. +func (c *HTTPKubeletClient) GetNodeInfo(host string) (api.NodeInfo, error) { + info := api.NodeInfo{} + _, err := c.getEntity(host, "/api/v1beta1/nodeInfo", "", &info) + return info, err +} + +func (c *HTTPKubeletClient) getEntity(host, path, query string, entity runtime.Object) (*http.Response, error) { + request, err := http.NewRequest("GET", c.url(host, path, query), nil) + if err != nil { + return nil, err + } + response, err := c.Client.Do(request) + if err != nil { + return response, err + } + defer response.Body.Close() if response.StatusCode >= 300 || response.StatusCode < 200 { - return status, fmt.Errorf("kubelet %q server responded with HTTP error code %d for pod %s/%s", host, response.StatusCode, podNamespace, podID) + return response, fmt.Errorf("kubelet %q server responded with HTTP error code %d", host, response.StatusCode) } body, err := ioutil.ReadAll(response.Body) if err != nil { - return status, err + return response, err } - // Check that this data can be unmarshalled - err = latest.Codec.DecodeInto(body, &status) - if err != nil { - return status, err - } - return status, nil + err = latest.Codec.DecodeInto(body, entity) + return response, err } func (c *HTTPKubeletClient) HealthCheck(host string) (probe.Result, error) { @@ -145,6 +159,11 @@ func (c FakeKubeletClient) GetPodStatus(host, podNamespace string, podID string) return api.PodStatusResult{}, errors.New("Not Implemented") } +// GetNodeInfo is a fake implementation of PodInfoGetter.GetNodeInfo +func (c FakeKubeletClient) GetNodeInfo(host string) (api.NodeInfo, error) { + return api.NodeInfo{}, errors.New("Not Implemented") +} + func (c FakeKubeletClient) HealthCheck(host string) (probe.Result, error) { return probe.Unknown, errors.New("Not Implemented") } diff --git a/pkg/cloudprovider/controller/nodecontroller.go b/pkg/cloudprovider/controller/nodecontroller.go index dc94ce65136..1421e886286 100644 --- a/pkg/cloudprovider/controller/nodecontroller.go +++ b/pkg/cloudprovider/controller/nodecontroller.go @@ -51,7 +51,7 @@ type NodeController struct { staticResources *api.NodeResources nodes []string kubeClient client.Interface - kubeletClient client.KubeletHealthChecker + kubeletClient client.KubeletClient registerRetryCount int podEvictionTimeout time.Duration } @@ -65,7 +65,7 @@ func NewNodeController( nodes []string, staticResources *api.NodeResources, kubeClient client.Interface, - kubeletClient client.KubeletHealthChecker, + kubeletClient client.KubeletClient, registerRetryCount int, podEvictionTimeout time.Duration) *NodeController { return &NodeController{ @@ -219,7 +219,7 @@ func (s *NodeController) SyncNodeStatus() error { if err != nil { return err } - nodes = s.DoChecks(nodes) + nodes = s.UpdateNodesStatus(nodes) nodes, err = s.PopulateAddresses(nodes) if err != nil { return err @@ -304,13 +304,16 @@ func (s *NodeController) PopulateAddresses(nodes *api.NodeList) (*api.NodeList, return nodes, nil } -// DoChecks performs health checking for given list of nodes. -func (s *NodeController) DoChecks(nodes *api.NodeList) *api.NodeList { +// UpdateNodesStatus performs health checking for given list of nodes. +func (s *NodeController) UpdateNodesStatus(nodes *api.NodeList) *api.NodeList { var wg sync.WaitGroup wg.Add(len(nodes.Items)) for i := range nodes.Items { go func(node *api.Node) { node.Status.Conditions = s.DoCheck(node) + if err := s.updateNodeInfo(node); err != nil { + glog.Errorf("Can't collect information for node %s: %v", node.Name, err) + } wg.Done() }(&nodes.Items[i]) } @@ -318,6 +321,17 @@ func (s *NodeController) DoChecks(nodes *api.NodeList) *api.NodeList { return nodes } +func (s *NodeController) updateNodeInfo(node *api.Node) error { + nodeInfo, err := s.kubeletClient.GetNodeInfo(node.Name) + if err != nil { + return err + } + for key, value := range nodeInfo.Capacity { + node.Spec.Capacity[key] = value + } + return nil +} + // DoCheck performs health checking for given node. func (s *NodeController) DoCheck(node *api.Node) []api.NodeCondition { var conditions []api.NodeCondition diff --git a/pkg/cloudprovider/controller/nodecontroller_test.go b/pkg/cloudprovider/controller/nodecontroller_test.go index c62912601b3..4e896f34543 100644 --- a/pkg/cloudprovider/controller/nodecontroller_test.go +++ b/pkg/cloudprovider/controller/nodecontroller_test.go @@ -130,6 +130,10 @@ func (c *FakeKubeletClient) GetPodStatus(host, podNamespace, podID string) (api. return api.PodStatusResult{}, errors.New("Not Implemented") } +func (c *FakeKubeletClient) GetNodeInfo(host string) (api.NodeInfo, error) { + return api.NodeInfo{}, errors.New("Not Implemented") +} + func (c *FakeKubeletClient) HealthCheck(host string) (probe.Result, error) { return c.Status, c.Err } diff --git a/pkg/kubelet/server.go b/pkg/kubelet/server.go index 1d98cb969fd..4d2feb8394d 100644 --- a/pkg/kubelet/server.go +++ b/pkg/kubelet/server.go @@ -33,6 +33,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource" "github.com/GoogleCloudPlatform/kubernetes/pkg/healthz" "github.com/GoogleCloudPlatform/kubernetes/pkg/httplog" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" @@ -46,8 +47,9 @@ import ( // Server is a http.Handler which exposes kubelet functionality over HTTP. type Server struct { - host HostInterface - mux *http.ServeMux + host HostInterface + mux *http.ServeMux + machineInfo *cadvisorApi.MachineInfo } type TLSOptions struct { @@ -114,6 +116,7 @@ func (s *Server) InstallDefaultHandlers() { healthz.InstallHandler(s.mux) s.mux.HandleFunc("/podInfo", s.handlePodInfoOld) s.mux.HandleFunc("/api/v1beta1/podInfo", s.handlePodInfoVersioned) + s.mux.HandleFunc("/api/v1beta1/nodeInfo", s.handleNodeInfoVersioned) s.mux.HandleFunc("/boundPods", s.handleBoundPods) s.mux.HandleFunc("/stats/", s.handleStats) s.mux.HandleFunc("/spec/", s.handleSpec) @@ -329,9 +332,47 @@ func (s *Server) handleLogs(w http.ResponseWriter, req *http.Request) { s.host.ServeLogs(w, req) } +// getCachedMachineInfo assumes that the machine info can't change without a reboot +func (s *Server) getCachedMachineInfo() (*cadvisorApi.MachineInfo, error) { + if s.machineInfo == nil { + info, err := s.host.GetMachineInfo() + if err != nil { + return nil, err + } + s.machineInfo = info + } + return s.machineInfo, nil +} + +// handleNodeInfoVersioned handles node info requests against the Kubelet. +func (s *Server) handleNodeInfoVersioned(w http.ResponseWriter, req *http.Request) { + info, err := s.getCachedMachineInfo() + if err != nil { + s.error(w, err) + return + } + capacity := api.ResourceList{ + api.ResourceCPU: *resource.NewMilliQuantity( + int64(info.NumCores*1000), + resource.DecimalSI), + api.ResourceMemory: *resource.NewQuantity( + info.MemoryCapacity, + resource.BinarySI), + } + data, err := json.Marshal(api.NodeInfo{ + Capacity: capacity, + }) + if err != nil { + s.error(w, err) + return + } + w.Header().Add("Content-type", "application/json") + w.Write(data) +} + // handleSpec handles spec requests against the Kubelet. func (s *Server) handleSpec(w http.ResponseWriter, req *http.Request) { - info, err := s.host.GetMachineInfo() + info, err := s.getCachedMachineInfo() if err != nil { s.error(w, err) return From 644d775bc14003f654f50693ec104735db680942 Mon Sep 17 00:00:00 2001 From: Federico Simoncelli Date: Mon, 2 Mar 2015 06:29:32 -0500 Subject: [PATCH 3/3] kubelet: retport system info in node information Signed-off-by: Federico Simoncelli --- pkg/api/types.go | 12 ++++++++++++ pkg/api/v1beta1/conversion.go | 6 ++++++ pkg/api/v1beta1/types.go | 12 ++++++++++++ pkg/api/v1beta2/conversion.go | 6 ++++++ pkg/api/v1beta2/types.go | 12 ++++++++++++ pkg/api/v1beta3/types.go | 12 ++++++++++++ pkg/cloudprovider/controller/nodecontroller.go | 1 + pkg/kubelet/server.go | 4 ++++ 8 files changed, 65 insertions(+) diff --git a/pkg/api/types.go b/pkg/api/types.go index 9409fc809d2..7ec98b4b2bd 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -788,6 +788,14 @@ type NodeSpec struct { ExternalID string `json:"externalID,omitempty"` } +// NodeSystemInfo is a set of ids/uuids to uniquely identify the node. +type NodeSystemInfo struct { + // MachineID is the machine-id reported by the node + MachineID string `json:"machineID"` + // SystemUUID is the system-uuid reported by the node + SystemUUID string `json:"systemUUID"` +} + // NodeStatus is information about the current status of a node. type NodeStatus struct { // NodePhase is the current lifecycle phase of the node. @@ -796,6 +804,8 @@ type NodeStatus struct { Conditions []NodeCondition `json:"conditions,omitempty"` // Queried from cloud provider, if available. Addresses []NodeAddress `json:"addresses,omitempty"` + // NodeSystemInfo is a set of ids/uuids to uniquely identify the node + NodeInfo NodeSystemInfo `json:"nodeInfo,omitempty"` } // NodeInfo is the information collected on the node. @@ -803,6 +813,8 @@ type NodeInfo struct { TypeMeta `json:",inline"` // Capacity represents the available resources of a node Capacity ResourceList `json:"capacity,omitempty"` + // NodeSystemInfo is a set of ids/uuids to uniquely identify the node + NodeSystemInfo `json:",inline,omitempty"` } type NodePhase string diff --git a/pkg/api/v1beta1/conversion.go b/pkg/api/v1beta1/conversion.go index 46ec4a9e8c0..fa76a6f5a1e 100644 --- a/pkg/api/v1beta1/conversion.go +++ b/pkg/api/v1beta1/conversion.go @@ -699,6 +699,9 @@ func init() { if err := s.Convert(&in.Status.Addresses, &out.Status.Addresses, 0); err != nil { return err } + if err := s.Convert(&in.Status.NodeInfo, &out.Status.NodeInfo, 0); err != nil { + return err + } for _, address := range in.Status.Addresses { if address.Type == newer.NodeLegacyHostIP { @@ -728,6 +731,9 @@ func init() { if err := s.Convert(&in.Status.Addresses, &out.Status.Addresses, 0); err != nil { return err } + if err := s.Convert(&in.Status.NodeInfo, &out.Status.NodeInfo, 0); err != nil { + return err + } if in.HostIP != "" { newer.AddToNodeAddresses(&out.Status.Addresses, diff --git a/pkg/api/v1beta1/types.go b/pkg/api/v1beta1/types.go index c4183a9d7b9..8a47ece6d98 100644 --- a/pkg/api/v1beta1/types.go +++ b/pkg/api/v1beta1/types.go @@ -618,6 +618,14 @@ type EndpointsList struct { Items []Endpoints `json:"items" description:"list of service endpoint lists"` } +// NodeSystemInfo is a set of ids/uuids to uniquely identify the node. +type NodeSystemInfo struct { + // MachineID is the machine-id reported by the node + MachineID string `json:"machineID" description:"machine id is the machine-id reported by the node"` + // SystemUUID is the system-uuid reported by the node + SystemUUID string `json:"systemUUID" description:"system uuid is the system-uuid reported by the node"` +} + // NodeStatus is information about the current status of a node. type NodeStatus struct { // NodePhase is the current lifecycle phase of the node. @@ -626,6 +634,8 @@ type NodeStatus struct { Conditions []NodeCondition `json:"conditions,omitempty" description:"conditions is an array of current node conditions"` // Queried from cloud provider, if available. Addresses []NodeAddress `json:"addresses,omitempty" description:"list of addresses reachable to the node"` + // NodeSystemInfo is a set of ids/uuids to uniquely identify the node + NodeInfo NodeSystemInfo `json:"nodeInfo,omitempty" description:"node identity is a set of ids/uuids to uniquely identify the node"` } // NodeInfo is the information collected on the node. @@ -633,6 +643,8 @@ type NodeInfo struct { TypeMeta `json:",inline"` // Capacity represents the available resources. Capacity ResourceList `json:"capacity,omitempty" description:"resource capacity of a node represented as a map of resource name to quantity of resource"` + // NodeSystemInfo is a set of ids/uuids to uniquely identify the node + NodeSystemInfo `json:",inline,omitempty" description:"node identity is a set of ids/uuids to uniquely identify the node"` } type NodePhase string diff --git a/pkg/api/v1beta2/conversion.go b/pkg/api/v1beta2/conversion.go index effc0e3e664..6291496c449 100644 --- a/pkg/api/v1beta2/conversion.go +++ b/pkg/api/v1beta2/conversion.go @@ -619,6 +619,9 @@ func init() { if err := s.Convert(&in.Status.Addresses, &out.Status.Addresses, 0); err != nil { return err } + if err := s.Convert(&in.Status.NodeInfo, &out.Status.NodeInfo, 0); err != nil { + return err + } for _, address := range in.Status.Addresses { if address.Type == newer.NodeLegacyHostIP { @@ -648,6 +651,9 @@ func init() { if err := s.Convert(&in.Status.Addresses, &out.Status.Addresses, 0); err != nil { return err } + if err := s.Convert(&in.Status.NodeInfo, &out.Status.NodeInfo, 0); err != nil { + return err + } if in.HostIP != "" { newer.AddToNodeAddresses(&out.Status.Addresses, diff --git a/pkg/api/v1beta2/types.go b/pkg/api/v1beta2/types.go index a85db7b7c8b..3b32f4d9499 100644 --- a/pkg/api/v1beta2/types.go +++ b/pkg/api/v1beta2/types.go @@ -623,6 +623,14 @@ type EndpointsList struct { Items []Endpoints `json:"items" description:"list of service endpoint lists"` } +// NodeSystemInfo is a set of ids/uuids to uniquely identify the node. +type NodeSystemInfo struct { + // MachineID is the machine-id reported by the node + MachineID string `json:"machineID" description:"machine id is the machine-id reported by the node"` + // SystemUUID is the system-uuid reported by the node + SystemUUID string `json:"systemUUID" description:"system uuid is the system-uuid reported by the node"` +} + // NodeStatus is information about the current status of a node. // // https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/node.md#node-status @@ -633,6 +641,8 @@ type NodeStatus struct { Conditions []NodeCondition `json:"conditions,omitempty" description:"conditions is an array of current node conditions"` // Queried from cloud provider, if available. Addresses []NodeAddress `json:"addresses,omitempty" description:"list of addresses reachable to the node"` + // NodeSystemInfo is a set of ids/uuids to uniquely identify the node + NodeInfo NodeSystemInfo `json:"nodeInfo,omitempty" description:"node identity is a set of ids/uuids to uniquely identify the node"` } // NodeInfo is the information collected on the node. @@ -640,6 +650,8 @@ type NodeInfo struct { TypeMeta `json:",inline"` // Capacity represents the available resources. Capacity ResourceList `json:"capacity,omitempty" description:"resource capacity of a node represented as a map of resource name to quantity of resource"` + // NodeSystemInfo is a set of ids/uuids to uniquely identify the node + NodeSystemInfo `json:",inline,omitempty" description:"node identity is a set of ids/uuids to uniquely identify the node"` } // Described the current lifecycle phase of a node. diff --git a/pkg/api/v1beta3/types.go b/pkg/api/v1beta3/types.go index 51e5583405b..079ed83d083 100644 --- a/pkg/api/v1beta3/types.go +++ b/pkg/api/v1beta3/types.go @@ -819,6 +819,14 @@ type NodeSpec struct { ExternalID string `json:"externalID,omitempty" description:"external ID assigned to the node by some machine database (e.g. a cloud provider)"` } +// NodeSystemInfo is a set of ids/uuids to uniquely identify the node. +type NodeSystemInfo struct { + // MachineID is the machine-id reported by the node + MachineID string `json:"machineID"` + // SystemUUID is the system-uuid reported by the node + SystemUUID string `json:"systemUUID"` +} + // NodeStatus is information about the current status of a node. type NodeStatus struct { // NodePhase is the current lifecycle phase of the node. @@ -827,6 +835,8 @@ type NodeStatus struct { Conditions []NodeCondition `json:"conditions,omitempty" description:"list of node conditions observed"` // Queried from cloud provider, if available. Addresses []NodeAddress `json:"addresses,omitempty" description:"list of addresses reachable to the node"` + // NodeSystemInfo is a set of ids/uuids to uniquely identify the node + NodeInfo NodeSystemInfo `json:"nodeInfo,omitempty"` } // NodeInfo is the information collected on the node. @@ -834,6 +844,8 @@ type NodeInfo struct { TypeMeta `json:",inline"` // Capacity represents the available resources of a node Capacity ResourceList `json:"capacity,omitempty"` + // NodeSystemInfo is a set of ids/uuids to uniquely identify the node + NodeSystemInfo `json:",inline,omitempty"` } type NodePhase string diff --git a/pkg/cloudprovider/controller/nodecontroller.go b/pkg/cloudprovider/controller/nodecontroller.go index 1421e886286..0f8992df399 100644 --- a/pkg/cloudprovider/controller/nodecontroller.go +++ b/pkg/cloudprovider/controller/nodecontroller.go @@ -329,6 +329,7 @@ func (s *NodeController) updateNodeInfo(node *api.Node) error { for key, value := range nodeInfo.Capacity { node.Spec.Capacity[key] = value } + node.Status.NodeInfo = nodeInfo.NodeSystemInfo return nil } diff --git a/pkg/kubelet/server.go b/pkg/kubelet/server.go index 4d2feb8394d..b481fe59520 100644 --- a/pkg/kubelet/server.go +++ b/pkg/kubelet/server.go @@ -361,6 +361,10 @@ func (s *Server) handleNodeInfoVersioned(w http.ResponseWriter, req *http.Reques } data, err := json.Marshal(api.NodeInfo{ Capacity: capacity, + NodeSystemInfo: api.NodeSystemInfo{ + MachineID: info.MachineID, + SystemUUID: info.SystemUUID, + }, }) if err != nil { s.error(w, err)