mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	Add "componentstatus" to API for easier cluster health check.
This commit is contained in:
		@@ -242,6 +242,7 @@ _kubectl_get()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    must_have_one_flag=()
 | 
					    must_have_one_flag=()
 | 
				
			||||||
    must_have_one_noun=()
 | 
					    must_have_one_noun=()
 | 
				
			||||||
 | 
					    must_have_one_noun+=("componentstatus")
 | 
				
			||||||
    must_have_one_noun+=("endpoints")
 | 
					    must_have_one_noun+=("endpoints")
 | 
				
			||||||
    must_have_one_noun+=("event")
 | 
					    must_have_one_noun+=("event")
 | 
				
			||||||
    must_have_one_noun+=("limitrange")
 | 
					    must_have_one_noun+=("limitrange")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -138,13 +138,17 @@ func kindToResource(kind string, mixedCase bool) (plural, singular string) {
 | 
				
			|||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		singular = strings.ToLower(kind)
 | 
							singular = strings.ToLower(kind)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	switch string(singular[len(singular)-1]) {
 | 
						if strings.HasSuffix(singular, "status") {
 | 
				
			||||||
	case "s":
 | 
							plural = strings.TrimSuffix(singular, "status") + "statuses"
 | 
				
			||||||
		plural = singular
 | 
						} else {
 | 
				
			||||||
	case "y":
 | 
							switch string(singular[len(singular)-1]) {
 | 
				
			||||||
		plural = strings.TrimSuffix(singular, "y") + "ies"
 | 
							case "s":
 | 
				
			||||||
	default:
 | 
								plural = singular
 | 
				
			||||||
		plural = singular + "s"
 | 
							case "y":
 | 
				
			||||||
 | 
								plural = strings.TrimSuffix(singular, "y") + "ies"
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								plural = singular + "s"
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -215,7 +219,7 @@ func (m *DefaultRESTMapper) RESTMapping(kind string, versions ...string) (*RESTM
 | 
				
			|||||||
		return nil, fmt.Errorf("the provided version %q has no relevant versions", version)
 | 
							return nil, fmt.Errorf("the provided version %q has no relevant versions", version)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &RESTMapping{
 | 
						retVal := &RESTMapping{
 | 
				
			||||||
		Resource:   resource,
 | 
							Resource:   resource,
 | 
				
			||||||
		APIVersion: version,
 | 
							APIVersion: version,
 | 
				
			||||||
		Kind:       kind,
 | 
							Kind:       kind,
 | 
				
			||||||
@@ -224,7 +228,9 @@ func (m *DefaultRESTMapper) RESTMapping(kind string, versions ...string) (*RESTM
 | 
				
			|||||||
		Codec:            interfaces.Codec,
 | 
							Codec:            interfaces.Codec,
 | 
				
			||||||
		ObjectConvertor:  interfaces.ObjectConvertor,
 | 
							ObjectConvertor:  interfaces.ObjectConvertor,
 | 
				
			||||||
		MetadataAccessor: interfaces.MetadataAccessor,
 | 
							MetadataAccessor: interfaces.MetadataAccessor,
 | 
				
			||||||
	}, nil
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return retVal, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// aliasToResource is used for mapping aliases to resources
 | 
					// aliasToResource is used for mapping aliases to resources
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -60,6 +60,8 @@ func init() {
 | 
				
			|||||||
		&PodLogOptions{},
 | 
							&PodLogOptions{},
 | 
				
			||||||
		&PodExecOptions{},
 | 
							&PodExecOptions{},
 | 
				
			||||||
		&PodProxyOptions{},
 | 
							&PodProxyOptions{},
 | 
				
			||||||
 | 
							&ComponentStatus{},
 | 
				
			||||||
 | 
							&ComponentStatusList{},
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	// Legacy names are supported
 | 
						// Legacy names are supported
 | 
				
			||||||
	Scheme.AddKnownTypeWithName("", "Minion", &Node{})
 | 
						Scheme.AddKnownTypeWithName("", "Minion", &Node{})
 | 
				
			||||||
@@ -101,3 +103,5 @@ func (*ListOptions) IsAnAPIObject()               {}
 | 
				
			|||||||
func (*PodLogOptions) IsAnAPIObject()             {}
 | 
					func (*PodLogOptions) IsAnAPIObject()             {}
 | 
				
			||||||
func (*PodExecOptions) IsAnAPIObject()            {}
 | 
					func (*PodExecOptions) IsAnAPIObject()            {}
 | 
				
			||||||
func (*PodProxyOptions) IsAnAPIObject()           {}
 | 
					func (*PodProxyOptions) IsAnAPIObject()           {}
 | 
				
			||||||
 | 
					func (*ComponentStatus) IsAnAPIObject()           {}
 | 
				
			||||||
 | 
					func (*ComponentStatusList) IsAnAPIObject()       {}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1827,3 +1827,34 @@ func AddToNodeAddresses(addresses *[]NodeAddress, addAddresses ...NodeAddress) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Type and constants for component health validation.
 | 
				
			||||||
 | 
					type ComponentConditionType string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// These are the valid conditions for the component.
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						ComponentHealthy ComponentConditionType = "Healthy"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ComponentCondition struct {
 | 
				
			||||||
 | 
						Type    ComponentConditionType `json:"type" description:"the type of condition"`
 | 
				
			||||||
 | 
						Status  ConditionStatus        `json:"status" description:"the status of this condition"`
 | 
				
			||||||
 | 
						Message string                 `json:"message,omitempty" description:"health check message received from the component"`
 | 
				
			||||||
 | 
						Error   string                 `json:"error,omitempty" description:"error code from health check attempt (if any)"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ComponentStatus (and ComponentStatusList) holds the cluster validation info.
 | 
				
			||||||
 | 
					type ComponentStatus struct {
 | 
				
			||||||
 | 
						TypeMeta   `json:",inline"`
 | 
				
			||||||
 | 
						ObjectMeta `json:"metadata,omitempty"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Name       string               `json:"name,omitempty" description:"name of the component"`
 | 
				
			||||||
 | 
						Conditions []ComponentCondition `json:"conditions,omitempty" description:"list of component condition objects"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ComponentStatusList struct {
 | 
				
			||||||
 | 
						TypeMeta `json:",inline"`
 | 
				
			||||||
 | 
						ListMeta `json:"metadata,omitempty"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Items []ComponentStatus `json:"items" description:"items is a list of component status objects"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -68,6 +68,8 @@ func init() {
 | 
				
			|||||||
		&PodLogOptions{},
 | 
							&PodLogOptions{},
 | 
				
			||||||
		&PodExecOptions{},
 | 
							&PodExecOptions{},
 | 
				
			||||||
		&PodProxyOptions{},
 | 
							&PodProxyOptions{},
 | 
				
			||||||
 | 
							&ComponentStatus{},
 | 
				
			||||||
 | 
							&ComponentStatusList{},
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	// Future names are supported
 | 
						// Future names are supported
 | 
				
			||||||
	api.Scheme.AddKnownTypeWithName("v1beta1", "Node", &Minion{})
 | 
						api.Scheme.AddKnownTypeWithName("v1beta1", "Node", &Minion{})
 | 
				
			||||||
@@ -110,3 +112,5 @@ func (*ListOptions) IsAnAPIObject()               {}
 | 
				
			|||||||
func (*PodLogOptions) IsAnAPIObject()             {}
 | 
					func (*PodLogOptions) IsAnAPIObject()             {}
 | 
				
			||||||
func (*PodExecOptions) IsAnAPIObject()            {}
 | 
					func (*PodExecOptions) IsAnAPIObject()            {}
 | 
				
			||||||
func (*PodProxyOptions) IsAnAPIObject()           {}
 | 
					func (*PodProxyOptions) IsAnAPIObject()           {}
 | 
				
			||||||
 | 
					func (*ComponentStatus) IsAnAPIObject()           {}
 | 
				
			||||||
 | 
					func (*ComponentStatusList) IsAnAPIObject()       {}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1592,3 +1592,32 @@ type GlusterfsVolumeSource struct {
 | 
				
			|||||||
	// the Glusterfs volume to be mounted with read-only permissions
 | 
						// the Glusterfs volume to be mounted with read-only permissions
 | 
				
			||||||
	ReadOnly bool `json:"readOnly,omitempty" description:"Glusterfs volume to be mounted with read-only permissions"`
 | 
						ReadOnly bool `json:"readOnly,omitempty" description:"Glusterfs volume to be mounted with read-only permissions"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Type and constants for component health validation.
 | 
				
			||||||
 | 
					type ComponentConditionType string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// These are the valid conditions for the component.
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						ComponentHealthy ComponentConditionType = "Healthy"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ComponentCondition struct {
 | 
				
			||||||
 | 
						Type    ComponentConditionType `json:"type"`
 | 
				
			||||||
 | 
						Status  ConditionStatus        `json:"status"`
 | 
				
			||||||
 | 
						Message string                 `json:"message,omitempty" description:"health check message received from the component"`
 | 
				
			||||||
 | 
						Error   string                 `json:"error,omitempty" description:"error code from health check attempt (if any)"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ComponentStatus (and ComponentStatusList) holds the cluster validation info.
 | 
				
			||||||
 | 
					type ComponentStatus struct {
 | 
				
			||||||
 | 
						TypeMeta `json:",inline"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Name       string               `json:"name,omitempty" description:"name of the component"`
 | 
				
			||||||
 | 
						Conditions []ComponentCondition `json:"conditions,omitempty"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ComponentStatusList struct {
 | 
				
			||||||
 | 
						TypeMeta `json:",inline"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Items []ComponentStatus `json:"items" description:"items is a list of component status objects"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -68,6 +68,8 @@ func init() {
 | 
				
			|||||||
		&PodLogOptions{},
 | 
							&PodLogOptions{},
 | 
				
			||||||
		&PodExecOptions{},
 | 
							&PodExecOptions{},
 | 
				
			||||||
		&PodProxyOptions{},
 | 
							&PodProxyOptions{},
 | 
				
			||||||
 | 
							&ComponentStatus{},
 | 
				
			||||||
 | 
							&ComponentStatusList{},
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	// Future names are supported
 | 
						// Future names are supported
 | 
				
			||||||
	api.Scheme.AddKnownTypeWithName("v1beta2", "Node", &Minion{})
 | 
						api.Scheme.AddKnownTypeWithName("v1beta2", "Node", &Minion{})
 | 
				
			||||||
@@ -110,3 +112,5 @@ func (*ListOptions) IsAnAPIObject()               {}
 | 
				
			|||||||
func (*PodLogOptions) IsAnAPIObject()             {}
 | 
					func (*PodLogOptions) IsAnAPIObject()             {}
 | 
				
			||||||
func (*PodExecOptions) IsAnAPIObject()            {}
 | 
					func (*PodExecOptions) IsAnAPIObject()            {}
 | 
				
			||||||
func (*PodProxyOptions) IsAnAPIObject()           {}
 | 
					func (*PodProxyOptions) IsAnAPIObject()           {}
 | 
				
			||||||
 | 
					func (*ComponentStatus) IsAnAPIObject()           {}
 | 
				
			||||||
 | 
					func (*ComponentStatusList) IsAnAPIObject()       {}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1655,3 +1655,32 @@ type SecretList struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	Items []Secret `json:"items" description:"items is a list of secret objects"`
 | 
						Items []Secret `json:"items" description:"items is a list of secret objects"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Type and constants for component health validation.
 | 
				
			||||||
 | 
					type ComponentConditionType string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// These are the valid conditions for the component.
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						ComponentHealthy ComponentConditionType = "Healthy"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ComponentCondition struct {
 | 
				
			||||||
 | 
						Type    ComponentConditionType `json:"type"`
 | 
				
			||||||
 | 
						Status  ConditionStatus        `json:"status"`
 | 
				
			||||||
 | 
						Message string                 `json:"message,omitempty" description:"health check message received from the component"`
 | 
				
			||||||
 | 
						Error   string                 `json:"error,omitempty" description:"error code from health check attempt (if any)"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ComponentStatus (and ComponentStatusList) holds the cluster validation info.
 | 
				
			||||||
 | 
					type ComponentStatus struct {
 | 
				
			||||||
 | 
						TypeMeta `json:",inline"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Name       string               `json:"name,omitempty" description:"name of the component"`
 | 
				
			||||||
 | 
						Conditions []ComponentCondition `json:"conditions,omitempty"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ComponentStatusList struct {
 | 
				
			||||||
 | 
						TypeMeta `json:",inline"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Items []ComponentStatus `json:"items" description:"items is a list of component status objects"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -61,6 +61,8 @@ func init() {
 | 
				
			|||||||
		&PodLogOptions{},
 | 
							&PodLogOptions{},
 | 
				
			||||||
		&PodExecOptions{},
 | 
							&PodExecOptions{},
 | 
				
			||||||
		&PodProxyOptions{},
 | 
							&PodProxyOptions{},
 | 
				
			||||||
 | 
							&ComponentStatus{},
 | 
				
			||||||
 | 
							&ComponentStatusList{},
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	// Legacy names are supported
 | 
						// Legacy names are supported
 | 
				
			||||||
	api.Scheme.AddKnownTypeWithName("v1beta3", "Minion", &Node{})
 | 
						api.Scheme.AddKnownTypeWithName("v1beta3", "Minion", &Node{})
 | 
				
			||||||
@@ -102,3 +104,5 @@ func (*ListOptions) IsAnAPIObject()               {}
 | 
				
			|||||||
func (*PodLogOptions) IsAnAPIObject()             {}
 | 
					func (*PodLogOptions) IsAnAPIObject()             {}
 | 
				
			||||||
func (*PodExecOptions) IsAnAPIObject()            {}
 | 
					func (*PodExecOptions) IsAnAPIObject()            {}
 | 
				
			||||||
func (*PodProxyOptions) IsAnAPIObject()           {}
 | 
					func (*PodProxyOptions) IsAnAPIObject()           {}
 | 
				
			||||||
 | 
					func (*ComponentStatus) IsAnAPIObject()           {}
 | 
				
			||||||
 | 
					func (*ComponentStatusList) IsAnAPIObject()       {}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1672,3 +1672,34 @@ type SecretList struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	Items []Secret `json:"items" description:"items is a list of secret objects"`
 | 
						Items []Secret `json:"items" description:"items is a list of secret objects"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Type and constants for component health validation.
 | 
				
			||||||
 | 
					type ComponentConditionType string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// These are the valid conditions for the component.
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						ComponentHealthy ComponentConditionType = "Healthy"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ComponentCondition struct {
 | 
				
			||||||
 | 
						Type    ComponentConditionType `json:"type"`
 | 
				
			||||||
 | 
						Status  ConditionStatus        `json:"status"`
 | 
				
			||||||
 | 
						Message string                 `json:"message,omitempty" description:"health check message received from the component"`
 | 
				
			||||||
 | 
						Error   string                 `json:"error,omitempty" description:"error code from health check attempt (if any)"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ComponentStatus (and ComponentStatusList) holds the cluster validation info.
 | 
				
			||||||
 | 
					type ComponentStatus struct {
 | 
				
			||||||
 | 
						TypeMeta   `json:",inline"`
 | 
				
			||||||
 | 
						ObjectMeta `json:"metadata,omitempty"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Name       string               `json:"name,omitempty" description:"name of the component"`
 | 
				
			||||||
 | 
						Conditions []ComponentCondition `json:"conditions,omitempty"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ComponentStatusList struct {
 | 
				
			||||||
 | 
						TypeMeta `json:",inline"`
 | 
				
			||||||
 | 
						ListMeta `json:"metadata,omitempty"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Items []ComponentStatus `json:"items" description:"items is a list of component status objects"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -140,7 +140,8 @@ func (g *APIGroupVersion) InstallREST(container *restful.Container) error {
 | 
				
			|||||||
	return errors.NewAggregate(registrationErrors)
 | 
						return errors.NewAggregate(registrationErrors)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: Convert to go-restful
 | 
					// TODO: This endpoint is deprecated and should be removed at some point.
 | 
				
			||||||
 | 
					// Use "componentstatus" API instead.
 | 
				
			||||||
func InstallValidator(mux Mux, servers func() map[string]Server) {
 | 
					func InstallValidator(mux Mux, servers func() map[string]Server) {
 | 
				
			||||||
	mux.Handle("/validate", NewValidator(servers))
 | 
						mux.Handle("/validate", NewValidator(servers))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,13 +48,39 @@ type validator struct {
 | 
				
			|||||||
	rt      http.RoundTripper
 | 
						rt      http.RoundTripper
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ServerStatus struct {
 | 
				
			||||||
 | 
						Component  string       `json:"component,omitempty"`
 | 
				
			||||||
 | 
						Health     string       `json:"health,omitempty"`
 | 
				
			||||||
 | 
						HealthCode probe.Result `json:"healthCode,omitempty"`
 | 
				
			||||||
 | 
						Msg        string       `json:"msg,omitempty"`
 | 
				
			||||||
 | 
						Err        string       `json:"err,omitempty"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: can this use pkg/probe/http
 | 
					// TODO: can this use pkg/probe/http
 | 
				
			||||||
func (s *Server) check(client httpGet) (probe.Result, string, error) {
 | 
					func (server *Server) DoServerCheck(rt http.RoundTripper) (probe.Result, string, error) {
 | 
				
			||||||
 | 
						var client *http.Client
 | 
				
			||||||
	scheme := "http://"
 | 
						scheme := "http://"
 | 
				
			||||||
	if s.EnableHTTPS {
 | 
						if server.EnableHTTPS {
 | 
				
			||||||
 | 
							// TODO(roberthbailey): The servers that use HTTPS are currently the
 | 
				
			||||||
 | 
							// kubelets, and we should be using a standard kubelet client library
 | 
				
			||||||
 | 
							// to talk to them rather than a separate http client.
 | 
				
			||||||
 | 
							transport := &http.Transport{
 | 
				
			||||||
 | 
								Proxy: http.ProxyFromEnvironment,
 | 
				
			||||||
 | 
								Dial: (&net.Dialer{
 | 
				
			||||||
 | 
									Timeout:   30 * time.Second,
 | 
				
			||||||
 | 
									KeepAlive: 30 * time.Second,
 | 
				
			||||||
 | 
								}).Dial,
 | 
				
			||||||
 | 
								TLSHandshakeTimeout: 10 * time.Second,
 | 
				
			||||||
 | 
								TLSClientConfig:     &tls.Config{InsecureSkipVerify: true},
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							client = &http.Client{Transport: transport}
 | 
				
			||||||
		scheme = "https://"
 | 
							scheme = "https://"
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							client = &http.Client{Transport: rt}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	resp, err := client.Get(scheme + net.JoinHostPort(s.Addr, strconv.Itoa(s.Port)) + s.Path)
 | 
					
 | 
				
			||||||
 | 
						resp, err := client.Get(scheme + net.JoinHostPort(server.Addr, strconv.Itoa(server.Port)) + server.Path)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return probe.Unknown, "", err
 | 
							return probe.Unknown, "", err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -70,14 +96,6 @@ func (s *Server) check(client httpGet) (probe.Result, string, error) {
 | 
				
			|||||||
	return probe.Success, string(data), nil
 | 
						return probe.Success, string(data), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ServerStatus struct {
 | 
					 | 
				
			||||||
	Component  string       `json:"component,omitempty"`
 | 
					 | 
				
			||||||
	Health     string       `json:"health,omitempty"`
 | 
					 | 
				
			||||||
	HealthCode probe.Result `json:"healthCode,omitempty"`
 | 
					 | 
				
			||||||
	Msg        string       `json:"msg,omitempty"`
 | 
					 | 
				
			||||||
	Err        string       `json:"err,omitempty"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (v *validator) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 | 
					func (v *validator) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
	verb := "get"
 | 
						verb := "get"
 | 
				
			||||||
	apiResource := ""
 | 
						apiResource := ""
 | 
				
			||||||
@@ -88,21 +106,7 @@ func (v *validator) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
	reply := []ServerStatus{}
 | 
						reply := []ServerStatus{}
 | 
				
			||||||
	for name, server := range v.servers() {
 | 
						for name, server := range v.servers() {
 | 
				
			||||||
		transport := v.rt
 | 
							transport := v.rt
 | 
				
			||||||
		if server.EnableHTTPS {
 | 
							status, msg, err := server.DoServerCheck(transport)
 | 
				
			||||||
			// TODO(roberthbailey): The servers that use HTTPS are currently the
 | 
					 | 
				
			||||||
			// kubelets, and we should be using a standard kubelet client library
 | 
					 | 
				
			||||||
			// to talk to them rather than a separate http client.
 | 
					 | 
				
			||||||
			transport = &http.Transport{
 | 
					 | 
				
			||||||
				Proxy: http.ProxyFromEnvironment,
 | 
					 | 
				
			||||||
				Dial: (&net.Dialer{
 | 
					 | 
				
			||||||
					Timeout:   30 * time.Second,
 | 
					 | 
				
			||||||
					KeepAlive: 30 * time.Second,
 | 
					 | 
				
			||||||
				}).Dial,
 | 
					 | 
				
			||||||
				TLSHandshakeTimeout: 10 * time.Second,
 | 
					 | 
				
			||||||
				TLSClientConfig:     &tls.Config{InsecureSkipVerify: true},
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		status, msg, err := server.check(&http.Client{Transport: transport})
 | 
					 | 
				
			||||||
		var errorMsg string
 | 
							var errorMsg string
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			errorMsg = err.Error()
 | 
								errorMsg = err.Error()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -65,8 +65,8 @@ func TestValidate(t *testing.T) {
 | 
				
			|||||||
				StatusCode: test.code,
 | 
									StatusCode: test.code,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		fake := &http.Client{Transport: fakeRT}
 | 
							//		fake := &http.Client{Transport: fakeRT}
 | 
				
			||||||
		status, data, err := s.check(fake)
 | 
							status, data, err := s.DoServerCheck(fakeRT)
 | 
				
			||||||
		expect := fmt.Sprintf("http://%s:%d/healthz", s.Addr, s.Port)
 | 
							expect := fmt.Sprintf("http://%s:%d/healthz", s.Addr, s.Port)
 | 
				
			||||||
		if fakeRT.url != expect {
 | 
							if fakeRT.url != expect {
 | 
				
			||||||
			t.Errorf("expected %s, got %s", expect, fakeRT.url)
 | 
								t.Errorf("expected %s, got %s", expect, fakeRT.url)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,6 +43,7 @@ type Interface interface {
 | 
				
			|||||||
	NamespacesInterface
 | 
						NamespacesInterface
 | 
				
			||||||
	PersistentVolumesInterface
 | 
						PersistentVolumesInterface
 | 
				
			||||||
	PersistentVolumeClaimsNamespacer
 | 
						PersistentVolumeClaimsNamespacer
 | 
				
			||||||
 | 
						ComponentStatusesInterface
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *Client) ReplicationControllers(namespace string) ReplicationControllerInterface {
 | 
					func (c *Client) ReplicationControllers(namespace string) ReplicationControllerInterface {
 | 
				
			||||||
@@ -92,6 +93,10 @@ func (c *Client) PersistentVolumeClaims(namespace string) PersistentVolumeClaimI
 | 
				
			|||||||
	return newPersistentVolumeClaims(c, namespace)
 | 
						return newPersistentVolumeClaims(c, namespace)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Client) ComponentStatuses() ComponentStatusInterface {
 | 
				
			||||||
 | 
						return newComponentStatuses(c)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// VersionInterface has a method to retrieve the server version.
 | 
					// VersionInterface has a method to retrieve the server version.
 | 
				
			||||||
type VersionInterface interface {
 | 
					type VersionInterface interface {
 | 
				
			||||||
	ServerVersion() (*version.Info, error)
 | 
						ServerVersion() (*version.Info, error)
 | 
				
			||||||
@@ -137,6 +142,25 @@ func (c *Client) ServerAPIVersions() (*api.APIVersions, error) {
 | 
				
			|||||||
	return &v, nil
 | 
						return &v, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ComponentValidatorInterface interface {
 | 
				
			||||||
 | 
						ValidateComponents() (*api.ComponentStatusList, error)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ValidateComponents retrieves and parses the master's self-monitored cluster state.
 | 
				
			||||||
 | 
					// TODO: This should hit the versioned endpoint when that is implemented.
 | 
				
			||||||
 | 
					func (c *Client) ValidateComponents() (*api.ComponentStatusList, error) {
 | 
				
			||||||
 | 
						body, err := c.Get().AbsPath("/validate").DoRaw()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						statuses := []api.ComponentStatus{}
 | 
				
			||||||
 | 
						if err := json.Unmarshal(body, &statuses); err != nil {
 | 
				
			||||||
 | 
							return nil, fmt.Errorf("got '%s': %v", string(body), err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return &api.ComponentStatusList{Items: statuses}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// IsTimeout tests if this is a timeout error in the underlying transport.
 | 
					// IsTimeout tests if this is a timeout error in the underlying transport.
 | 
				
			||||||
// This is unbelievably ugly.
 | 
					// This is unbelievably ugly.
 | 
				
			||||||
// See: http://stackoverflow.com/questions/23494950/specifically-check-for-timeout-error for details
 | 
					// See: http://stackoverflow.com/questions/23494950/specifically-check-for-timeout-error for details
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										63
									
								
								pkg/client/componentstatuses.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								pkg/client/componentstatuses.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2015 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 client
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ComponentStatusesInterface interface {
 | 
				
			||||||
 | 
						ComponentStatuses() ComponentStatusInterface
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ComponentStatusInterface contains methods to retrieve ComponentStatus
 | 
				
			||||||
 | 
					type ComponentStatusInterface interface {
 | 
				
			||||||
 | 
						List(label labels.Selector, field fields.Selector) (*api.ComponentStatusList, error)
 | 
				
			||||||
 | 
						Get(name string) (*api.ComponentStatus, error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: It'd be nice to have watch support at some point
 | 
				
			||||||
 | 
						//Watch(label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// componentStatuses implements ComponentStatusesInterface
 | 
				
			||||||
 | 
					type componentStatuses struct {
 | 
				
			||||||
 | 
						client *Client
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func newComponentStatuses(c *Client) *componentStatuses {
 | 
				
			||||||
 | 
						return &componentStatuses{c}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *componentStatuses) List(label labels.Selector, field fields.Selector) (result *api.ComponentStatusList, err error) {
 | 
				
			||||||
 | 
						result = &api.ComponentStatusList{}
 | 
				
			||||||
 | 
						err = c.client.Get().
 | 
				
			||||||
 | 
							Resource("componentStatuses").
 | 
				
			||||||
 | 
							LabelsSelectorParam(label).
 | 
				
			||||||
 | 
							FieldsSelectorParam(field).
 | 
				
			||||||
 | 
							Do().
 | 
				
			||||||
 | 
							Into(result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return result, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *componentStatuses) Get(name string) (result *api.ComponentStatus, err error) {
 | 
				
			||||||
 | 
						result = &api.ComponentStatus{}
 | 
				
			||||||
 | 
						err = c.client.Get().Resource("componentStatuses").Name(name).Do().Into(result)
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										47
									
								
								pkg/client/testclient/fake_componentstatuses.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								pkg/client/testclient/fake_componentstatuses.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2015 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 testclient
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Fake implements ComponentStatusInterface.
 | 
				
			||||||
 | 
					type FakeComponentStatuses struct {
 | 
				
			||||||
 | 
						Fake *Fake
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *FakeComponentStatuses) List(label labels.Selector, field fields.Selector) (result *api.ComponentStatusList, err error) {
 | 
				
			||||||
 | 
						obj, err := c.Fake.Invokes(FakeAction{Action: "list-componentstatuses"}, &api.ComponentStatusList{})
 | 
				
			||||||
 | 
						return obj.(*api.ComponentStatusList), err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *FakeComponentStatuses) Get(name string) (*api.ComponentStatus, error) {
 | 
				
			||||||
 | 
						obj, err := c.Fake.Invokes(FakeAction{Action: "get-componentstatus", Value: name}, &api.ComponentStatus{})
 | 
				
			||||||
 | 
						//   c.Actions = append(c.Actions, FakeAction{Action: "get-componentstatuses", Value: nil})
 | 
				
			||||||
 | 
						// testStatus := &api.ComponentStatus{
 | 
				
			||||||
 | 
						//   Name:       "test",
 | 
				
			||||||
 | 
						//   Health:     "ok",
 | 
				
			||||||
 | 
						//   HealthCode: int(probe.Success),
 | 
				
			||||||
 | 
						//   Message:    "ok",
 | 
				
			||||||
 | 
						//   Error:      "",
 | 
				
			||||||
 | 
						// }
 | 
				
			||||||
 | 
						// return &api.ComponentStatusList{Items: []api.ComponentStatus{*testStatus}}, nil
 | 
				
			||||||
 | 
						return obj.(*api.ComponentStatus), err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -125,3 +125,7 @@ func (c *Fake) ServerAPIVersions() (*api.APIVersions, error) {
 | 
				
			|||||||
	c.Actions = append(c.Actions, FakeAction{Action: "get-apiversions", Value: nil})
 | 
						c.Actions = append(c.Actions, FakeAction{Action: "get-apiversions", Value: nil})
 | 
				
			||||||
	return &api.APIVersions{Versions: []string{"v1beta1", "v1beta2"}}, nil
 | 
						return &api.APIVersions{Versions: []string{"v1beta1", "v1beta2"}}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Fake) ComponentStatuses() client.ComponentStatusInterface {
 | 
				
			||||||
 | 
						return &FakeComponentStatuses{Fake: c}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -150,6 +150,13 @@ func NewAPIFactory() (*cmdutil.Factory, *testFactory, runtime.Codec) {
 | 
				
			|||||||
		Object: func() (meta.RESTMapper, runtime.ObjectTyper) {
 | 
							Object: func() (meta.RESTMapper, runtime.ObjectTyper) {
 | 
				
			||||||
			return latest.RESTMapper, api.Scheme
 | 
								return latest.RESTMapper, api.Scheme
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							Client: func() (*client.Client, error) {
 | 
				
			||||||
 | 
								// Swap out the HTTP client out of the client with the fake's version.
 | 
				
			||||||
 | 
								fakeClient := t.Client.(*client.FakeRESTClient)
 | 
				
			||||||
 | 
								c := client.NewOrDie(t.ClientConfig)
 | 
				
			||||||
 | 
								c.Client = fakeClient.Client
 | 
				
			||||||
 | 
								return c, t.Err
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
		RESTClient: func(*meta.RESTMapping) (resource.RESTClient, error) {
 | 
							RESTClient: func(*meta.RESTMapping) (resource.RESTClient, error) {
 | 
				
			||||||
			return t.Client, t.Err
 | 
								return t.Client, t.Err
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,7 +34,7 @@ const (
 | 
				
			|||||||
	get_long = `Display one or many resources.
 | 
						get_long = `Display one or many resources.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Possible resources include pods (po), replication controllers (rc), services
 | 
					Possible resources include pods (po), replication controllers (rc), services
 | 
				
			||||||
(svc), minions (mi), or events (ev).
 | 
					(svc), minions (mi), events (ev), or component statuses (cs).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
By specifying the output as 'template' and providing a Go template as the value
 | 
					By specifying the output as 'template' and providing a Go template as the value
 | 
				
			||||||
of the --template flag, you can filter the attributes of the fetched resource(s).`
 | 
					of the --template flag, you can filter the attributes of the fetched resource(s).`
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -87,6 +87,31 @@ func testData() (*api.PodList, *api.ServiceList, *api.ReplicationControllerList)
 | 
				
			|||||||
	return pods, svc, rc
 | 
						return pods, svc, rc
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func testComponentStatusData() *api.ComponentStatusList {
 | 
				
			||||||
 | 
						good := &api.ComponentStatus{
 | 
				
			||||||
 | 
							Name: "servergood",
 | 
				
			||||||
 | 
							Conditions: []api.ComponentCondition{
 | 
				
			||||||
 | 
								{Type: api.ComponentHealthy, Status: api.ConditionTrue, Message: "ok", Error: "nil"},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						bad := &api.ComponentStatus{
 | 
				
			||||||
 | 
							Name: "serverbad",
 | 
				
			||||||
 | 
							Conditions: []api.ComponentCondition{
 | 
				
			||||||
 | 
								{Type: api.ComponentHealthy, Status: api.ConditionFalse, Message: "", Error: "bad status: 500"},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						unknown := &api.ComponentStatus{
 | 
				
			||||||
 | 
							Name: "serverunknown",
 | 
				
			||||||
 | 
							Conditions: []api.ComponentCondition{
 | 
				
			||||||
 | 
								{Type: api.ComponentHealthy, Status: api.ConditionUnknown, Message: "", Error: "fizzbuzz error"},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &api.ComponentStatusList{
 | 
				
			||||||
 | 
							Items: []api.ComponentStatus{*good, *bad, *unknown},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Verifies that schemas that are not in the master tree of Kubernetes can be retrieved via Get.
 | 
					// Verifies that schemas that are not in the master tree of Kubernetes can be retrieved via Get.
 | 
				
			||||||
func TestGetUnknownSchemaObject(t *testing.T) {
 | 
					func TestGetUnknownSchemaObject(t *testing.T) {
 | 
				
			||||||
	f, tf, codec := NewTestFactory()
 | 
						f, tf, codec := NewTestFactory()
 | 
				
			||||||
@@ -188,6 +213,32 @@ func TestGetListObjects(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestGetListComponentStatus(t *testing.T) {
 | 
				
			||||||
 | 
						statuses := testComponentStatusData()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						f, tf, codec := NewAPIFactory()
 | 
				
			||||||
 | 
						tf.Printer = &testPrinter{}
 | 
				
			||||||
 | 
						tf.Client = &client.FakeRESTClient{
 | 
				
			||||||
 | 
							Codec: codec,
 | 
				
			||||||
 | 
							Resp:  &http.Response{StatusCode: 200, Body: objBody(codec, statuses)},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						tf.Namespace = "test"
 | 
				
			||||||
 | 
						buf := bytes.NewBuffer([]byte{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cmd := NewCmdGet(f, buf)
 | 
				
			||||||
 | 
						cmd.SetOutput(buf)
 | 
				
			||||||
 | 
						cmd.Run(cmd, []string{"componentstatuses"})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						expected := []runtime.Object{statuses}
 | 
				
			||||||
 | 
						actual := tf.Printer.(*testPrinter).Objects
 | 
				
			||||||
 | 
						if !reflect.DeepEqual(expected, actual) {
 | 
				
			||||||
 | 
							t.Errorf("unexpected object: %#v %#v", expected, actual)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(buf.String()) == 0 {
 | 
				
			||||||
 | 
							t.Errorf("unexpected empty output")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestGetMultipleTypeObjects(t *testing.T) {
 | 
					func TestGetMultipleTypeObjects(t *testing.T) {
 | 
				
			||||||
	pods, svc, _ := testData()
 | 
						pods, svc, _ := testData()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -96,17 +96,19 @@ func (e ShortcutExpander) VersionAndKindForResource(resource string) (defaultVer
 | 
				
			|||||||
// indeed a shortcut. Otherwise, will return resource unmodified.
 | 
					// indeed a shortcut. Otherwise, will return resource unmodified.
 | 
				
			||||||
func expandResourceShortcut(resource string) string {
 | 
					func expandResourceShortcut(resource string) string {
 | 
				
			||||||
	shortForms := map[string]string{
 | 
						shortForms := map[string]string{
 | 
				
			||||||
		"po": "pods",
 | 
							// Please keep this alphabetized
 | 
				
			||||||
		"rc": "replicationcontrollers",
 | 
							"cs":     "componentstatus",
 | 
				
			||||||
		// DEPRECATED: will be removed before 1.0
 | 
					 | 
				
			||||||
		"se":     "services",
 | 
					 | 
				
			||||||
		"svc":    "services",
 | 
					 | 
				
			||||||
		"mi":     "minions",
 | 
					 | 
				
			||||||
		"ev":     "events",
 | 
							"ev":     "events",
 | 
				
			||||||
		"limits": "limitRanges",
 | 
							"limits": "limitRanges",
 | 
				
			||||||
		"quota":  "resourceQuotas",
 | 
							"mi":     "minions",
 | 
				
			||||||
 | 
							"po":     "pods",
 | 
				
			||||||
		"pv":     "persistentVolumes",
 | 
							"pv":     "persistentVolumes",
 | 
				
			||||||
		"pvc":    "persistentVolumeClaims",
 | 
							"pvc":    "persistentVolumeClaims",
 | 
				
			||||||
 | 
							"quota":  "resourceQuotas",
 | 
				
			||||||
 | 
							"rc":     "replicationcontrollers",
 | 
				
			||||||
 | 
							// DEPRECATED: will be removed before 1.0
 | 
				
			||||||
 | 
							"se":  "services",
 | 
				
			||||||
 | 
							"svc": "services",
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if expanded, ok := shortForms[resource]; ok {
 | 
						if expanded, ok := shortForms[resource]; ok {
 | 
				
			||||||
		return expanded
 | 
							return expanded
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -256,6 +256,7 @@ var namespaceColumns = []string{"NAME", "LABELS", "STATUS"}
 | 
				
			|||||||
var secretColumns = []string{"NAME", "DATA"}
 | 
					var secretColumns = []string{"NAME", "DATA"}
 | 
				
			||||||
var persistentVolumeColumns = []string{"NAME", "LABELS", "CAPACITY", "ACCESSMODES", "STATUS", "CLAIM"}
 | 
					var persistentVolumeColumns = []string{"NAME", "LABELS", "CAPACITY", "ACCESSMODES", "STATUS", "CLAIM"}
 | 
				
			||||||
var persistentVolumeClaimColumns = []string{"NAME", "LABELS", "STATUS", "VOLUME"}
 | 
					var persistentVolumeClaimColumns = []string{"NAME", "LABELS", "STATUS", "VOLUME"}
 | 
				
			||||||
 | 
					var componentStatusColumns = []string{"NAME", "STATUS", "MESSAGE", "ERROR"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// addDefaultHandlers adds print handlers for default Kubernetes types.
 | 
					// addDefaultHandlers adds print handlers for default Kubernetes types.
 | 
				
			||||||
func (h *HumanReadablePrinter) addDefaultHandlers() {
 | 
					func (h *HumanReadablePrinter) addDefaultHandlers() {
 | 
				
			||||||
@@ -284,6 +285,8 @@ func (h *HumanReadablePrinter) addDefaultHandlers() {
 | 
				
			|||||||
	h.Handler(persistentVolumeClaimColumns, printPersistentVolumeClaimList)
 | 
						h.Handler(persistentVolumeClaimColumns, printPersistentVolumeClaimList)
 | 
				
			||||||
	h.Handler(persistentVolumeColumns, printPersistentVolume)
 | 
						h.Handler(persistentVolumeColumns, printPersistentVolume)
 | 
				
			||||||
	h.Handler(persistentVolumeColumns, printPersistentVolumeList)
 | 
						h.Handler(persistentVolumeColumns, printPersistentVolumeList)
 | 
				
			||||||
 | 
						h.Handler(componentStatusColumns, printComponentStatus)
 | 
				
			||||||
 | 
						h.Handler(componentStatusColumns, printComponentStatusList)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (h *HumanReadablePrinter) unknown(data []byte, w io.Writer) error {
 | 
					func (h *HumanReadablePrinter) unknown(data []byte, w io.Writer) error {
 | 
				
			||||||
@@ -647,6 +650,36 @@ func printResourceQuotaList(list *api.ResourceQuotaList, w io.Writer) error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func printComponentStatus(item *api.ComponentStatus, w io.Writer) error {
 | 
				
			||||||
 | 
						status := "Unknown"
 | 
				
			||||||
 | 
						message := ""
 | 
				
			||||||
 | 
						error := ""
 | 
				
			||||||
 | 
						for _, condition := range item.Conditions {
 | 
				
			||||||
 | 
							if condition.Type == api.ComponentHealthy {
 | 
				
			||||||
 | 
								if condition.Status == api.ConditionTrue {
 | 
				
			||||||
 | 
									status = "Healthy"
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									status = "Unhealthy"
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								message = condition.Message
 | 
				
			||||||
 | 
								error = condition.Error
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						_, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", item.Name, status, message, error)
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func printComponentStatusList(list *api.ComponentStatusList, w io.Writer) error {
 | 
				
			||||||
 | 
						for _, item := range list.Items {
 | 
				
			||||||
 | 
							if err := printComponentStatus(&item, w); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// PrintObj prints the obj in a human-friendly format according to the type of the obj.
 | 
					// PrintObj prints the obj in a human-friendly format according to the type of the obj.
 | 
				
			||||||
func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) error {
 | 
					func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) error {
 | 
				
			||||||
	w := tabwriter.NewWriter(output, 10, 4, 3, ' ', 0)
 | 
						w := tabwriter.NewWriter(output, 10, 4, 3, ' ', 0)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,6 +43,7 @@ import (
 | 
				
			|||||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
 | 
				
			||||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
 | 
				
			||||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/master/ports"
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/master/ports"
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/componentstatus"
 | 
				
			||||||
	controlleretcd "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/controller/etcd"
 | 
						controlleretcd "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/controller/etcd"
 | 
				
			||||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/endpoint"
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/endpoint"
 | 
				
			||||||
	endpointsetcd "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/endpoint/etcd"
 | 
						endpointsetcd "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/endpoint/etcd"
 | 
				
			||||||
@@ -416,6 +417,8 @@ func (m *Master) init(c *Config) {
 | 
				
			|||||||
		"persistentVolumes/status":      persistentVolumeStatusStorage,
 | 
							"persistentVolumes/status":      persistentVolumeStatusStorage,
 | 
				
			||||||
		"persistentVolumeClaims":        persistentVolumeClaimStorage,
 | 
							"persistentVolumeClaims":        persistentVolumeClaimStorage,
 | 
				
			||||||
		"persistentVolumeClaims/status": persistentVolumeClaimStatusStorage,
 | 
							"persistentVolumeClaims/status": persistentVolumeClaimStatusStorage,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							"componentStatuses": componentstatus.NewStorage(func() map[string]apiserver.Server { return m.getServersToValidate(c) }),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	apiVersions := []string{"v1beta1", "v1beta2"}
 | 
						apiVersions := []string{"v1beta1", "v1beta2"}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										19
									
								
								pkg/registry/componentstatus/doc.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								pkg/registry/componentstatus/doc.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2015 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 componentstatus provides interfaces and implementation for retrieving cluster
 | 
				
			||||||
 | 
					// component status.
 | 
				
			||||||
 | 
					package componentstatus
 | 
				
			||||||
							
								
								
									
										110
									
								
								pkg/registry/componentstatus/rest.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								pkg/registry/componentstatus/rest.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2015 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 componentstatus
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/probe"
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type REST struct {
 | 
				
			||||||
 | 
						GetServersToValidate func() map[string]apiserver.Server
 | 
				
			||||||
 | 
						rt                   http.RoundTripper
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewStorage returns a new REST.
 | 
				
			||||||
 | 
					func NewStorage(serverRetriever func() map[string]apiserver.Server) *REST {
 | 
				
			||||||
 | 
						return &REST{
 | 
				
			||||||
 | 
							GetServersToValidate: serverRetriever,
 | 
				
			||||||
 | 
							rt:                   http.DefaultTransport,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (rs *REST) New() runtime.Object {
 | 
				
			||||||
 | 
						return &api.ComponentStatus{}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (rs *REST) NewList() runtime.Object {
 | 
				
			||||||
 | 
						return &api.ComponentStatusList{}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Returns the list of component status. Note that the label and field are both ignored.
 | 
				
			||||||
 | 
					// Note that this call doesn't support labels or selectors.
 | 
				
			||||||
 | 
					func (rs *REST) List(ctx api.Context, label labels.Selector, field fields.Selector) (runtime.Object, error) {
 | 
				
			||||||
 | 
						servers := rs.GetServersToValidate()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: This should be parallelized.
 | 
				
			||||||
 | 
						reply := []api.ComponentStatus{}
 | 
				
			||||||
 | 
						for name, server := range servers {
 | 
				
			||||||
 | 
							status := rs.getComponentStatus(name, server)
 | 
				
			||||||
 | 
							reply = append(reply, *status)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return &api.ComponentStatusList{Items: reply}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (rs *REST) Get(ctx api.Context, name string) (runtime.Object, error) {
 | 
				
			||||||
 | 
						servers := rs.GetServersToValidate()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if server, ok := servers[name]; !ok {
 | 
				
			||||||
 | 
							return nil, fmt.Errorf("Component not found: %s", name)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return rs.getComponentStatus(name, server), nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func ToConditionStatus(s probe.Result) api.ConditionStatus {
 | 
				
			||||||
 | 
						switch s {
 | 
				
			||||||
 | 
						case probe.Success:
 | 
				
			||||||
 | 
							return api.ConditionTrue
 | 
				
			||||||
 | 
						case probe.Failure:
 | 
				
			||||||
 | 
							return api.ConditionFalse
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return api.ConditionUnknown
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (rs *REST) getComponentStatus(name string, server apiserver.Server) *api.ComponentStatus {
 | 
				
			||||||
 | 
						transport := rs.rt
 | 
				
			||||||
 | 
						status, msg, err := server.DoServerCheck(transport)
 | 
				
			||||||
 | 
						var errorMsg string
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							errorMsg = err.Error()
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							errorMsg = "nil"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c := &api.ComponentCondition{
 | 
				
			||||||
 | 
							Type:    api.ComponentHealthy,
 | 
				
			||||||
 | 
							Status:  ToConditionStatus(status),
 | 
				
			||||||
 | 
							Message: msg,
 | 
				
			||||||
 | 
							Error:   errorMsg,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						retVal := &api.ComponentStatus{
 | 
				
			||||||
 | 
							Name:       name,
 | 
				
			||||||
 | 
							Conditions: []api.ComponentCondition{*c},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return retVal
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										143
									
								
								pkg/registry/componentstatus/rest_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								pkg/registry/componentstatus/rest_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,143 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2015 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 componentstatus
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
 | 
				
			||||||
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type fakeRoundTripper struct {
 | 
				
			||||||
 | 
						err  error
 | 
				
			||||||
 | 
						resp *http.Response
 | 
				
			||||||
 | 
						url  string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (f *fakeRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
 | 
				
			||||||
 | 
						f.url = req.URL.String()
 | 
				
			||||||
 | 
						return f.resp, f.err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type testResponse struct {
 | 
				
			||||||
 | 
						code int
 | 
				
			||||||
 | 
						data string
 | 
				
			||||||
 | 
						err  error
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewTestREST(resp testResponse) *REST {
 | 
				
			||||||
 | 
						return &REST{
 | 
				
			||||||
 | 
							GetServersToValidate: func() map[string]apiserver.Server {
 | 
				
			||||||
 | 
								return map[string]apiserver.Server{
 | 
				
			||||||
 | 
									"test1": {Addr: "testserver1", Port: 8000, Path: "/healthz"},
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							rt: &fakeRoundTripper{
 | 
				
			||||||
 | 
								err: resp.err,
 | 
				
			||||||
 | 
								resp: &http.Response{
 | 
				
			||||||
 | 
									Body:       ioutil.NopCloser(bytes.NewBufferString(resp.data)),
 | 
				
			||||||
 | 
									StatusCode: resp.code,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func createTestStatus(name string, status api.ConditionStatus, msg string, err string) *api.ComponentStatus {
 | 
				
			||||||
 | 
						return &api.ComponentStatus{
 | 
				
			||||||
 | 
							Name: name,
 | 
				
			||||||
 | 
							Conditions: []api.ComponentCondition{
 | 
				
			||||||
 | 
								{Type: api.ComponentHealthy, Status: status, Message: msg, Error: err},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestList_NoError(t *testing.T) {
 | 
				
			||||||
 | 
						r := NewTestREST(testResponse{code: 200, data: "ok"})
 | 
				
			||||||
 | 
						got, err := r.List(api.NewContext(), labels.Everything(), fields.Everything())
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("Unexpected error: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						expect := &api.ComponentStatusList{
 | 
				
			||||||
 | 
							Items: []api.ComponentStatus{*(createTestStatus("test1", api.ConditionTrue, "ok", "nil"))},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if e, a := expect, got; !reflect.DeepEqual(e, a) {
 | 
				
			||||||
 | 
							t.Errorf("Got unexpected object. Diff: %s", util.ObjectDiff(e, a))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestList_FailedCheck(t *testing.T) {
 | 
				
			||||||
 | 
						r := NewTestREST(testResponse{code: 500, data: ""})
 | 
				
			||||||
 | 
						got, err := r.List(api.NewContext(), labels.Everything(), fields.Everything())
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("Unexpected error: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						expect := &api.ComponentStatusList{
 | 
				
			||||||
 | 
							Items: []api.ComponentStatus{
 | 
				
			||||||
 | 
								*(createTestStatus("test1", api.ConditionFalse, "", "unhealthy http status code: 500 ()"))},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if e, a := expect, got; !reflect.DeepEqual(e, a) {
 | 
				
			||||||
 | 
							t.Errorf("Got unexpected object. Diff: %s", util.ObjectDiff(e, a))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestList_UnknownError(t *testing.T) {
 | 
				
			||||||
 | 
						r := NewTestREST(testResponse{code: 500, data: "", err: fmt.Errorf("fizzbuzz error")})
 | 
				
			||||||
 | 
						got, err := r.List(api.NewContext(), labels.Everything(), fields.Everything())
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("Unexpected error: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						expect := &api.ComponentStatusList{
 | 
				
			||||||
 | 
							Items: []api.ComponentStatus{
 | 
				
			||||||
 | 
								*(createTestStatus("test1", api.ConditionUnknown, "", "Get http://testserver1:8000/healthz: fizzbuzz error"))},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if e, a := expect, got; !reflect.DeepEqual(e, a) {
 | 
				
			||||||
 | 
							t.Errorf("Got unexpected object. Diff: %s", util.ObjectDiff(e, a))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestGet_NoError(t *testing.T) {
 | 
				
			||||||
 | 
						r := NewTestREST(testResponse{code: 200, data: "ok"})
 | 
				
			||||||
 | 
						got, err := r.Get(api.NewContext(), "test1")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("Unexpected error: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						expect := createTestStatus("test1", api.ConditionTrue, "ok", "nil")
 | 
				
			||||||
 | 
						if e, a := expect, got; !reflect.DeepEqual(e, a) {
 | 
				
			||||||
 | 
							t.Errorf("Got unexpected object. Diff: %s", util.ObjectDiff(e, a))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestGet_BadName(t *testing.T) {
 | 
				
			||||||
 | 
						r := NewTestREST(testResponse{code: 200, data: "ok"})
 | 
				
			||||||
 | 
						_, err := r.Get(api.NewContext(), "invalidname")
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							t.Fatalf("Expected error, but did not get one")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !strings.Contains(err.Error(), "Component not found: invalidname") {
 | 
				
			||||||
 | 
							t.Fatalf("Got unexpected error: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user