diff --git a/pkg/api/types.go b/pkg/api/types.go index aa79e0c0087..4f48d488143 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -104,6 +104,7 @@ type EnvVar struct { Value string `yaml:"value,omitempty" json:"value,omitempty"` } +// HTTPGetProbe describes a liveness probe based on HTTP Get requests. type HTTPGetProbe struct { // Path to access on the http server Path string `yaml:"path,omitempty" json:"path,omitempty"` @@ -113,6 +114,7 @@ type HTTPGetProbe struct { Host string `yaml:"host,omitempty" json:"host,omitempty"` } +// LivenessProbe describes a liveness probe to be examined to the container. type LivenessProbe struct { Enabled bool `yaml:"enabled,omitempty" json:"enabled,omitempty"` // Type of liveness probe. Current legal values "http" diff --git a/pkg/api/validation.go b/pkg/api/validation.go index aa090551900..d58cbdf0521 100644 --- a/pkg/api/validation.go +++ b/pkg/api/validation.go @@ -64,7 +64,7 @@ func makeNotFoundError(field string, value interface{}) ValidationError { } // A helper for accumulating errors. This could be moved to util if anyone else needs it. -type errorList []error; +type errorList []error func (list *errorList) Append(errs ...error) { *list = append(*list, errs...) @@ -87,7 +87,7 @@ func validateVolumes(volumes []Volume) (util.StringSet, errorList) { return allNames, allErrs } -var supportedPortProtocols util.StringSet = util.NewStringSet("TCP", "UDP") +var supportedPortProtocols = util.NewStringSet("TCP", "UDP") func validatePorts(ports []Port) errorList { allErrs := errorList{} @@ -219,10 +219,10 @@ func validateContainers(containers []Container, volumes util.StringSet) errorLis // every Port.HostPort across the whole pod must be unique. allErrs.Append(checkHostPortConflicts(containers)...) - return allErrs; + return allErrs } -var supportedManifestVersions util.StringSet = util.NewStringSet("v1beta1", "v1beta2") +var supportedManifestVersions = util.NewStringSet("v1beta1", "v1beta2") // ValidateManifest tests that the specified ContainerManifest has valid data. // This includes checking formatting and uniqueness. It also canonicalizes the diff --git a/pkg/cloudprovider/cloud.go b/pkg/cloudprovider/cloud.go index a4504713e3e..4307b0a5c9c 100644 --- a/pkg/cloudprovider/cloud.go +++ b/pkg/cloudprovider/cloud.go @@ -20,7 +20,7 @@ import ( "net" ) -// CloudInterface is an abstract, pluggable interface for cloud providers +// Interface is an abstract, pluggable interface for cloud providers type Interface interface { // TCPLoadBalancer returns a balancer interface. Also returns true if the interface is supported, false otherwise. TCPLoadBalancer() (TCPLoadBalancer, bool) @@ -28,16 +28,23 @@ type Interface interface { Instances() (Instances, bool) } +// TCPLoadBalancer is an abstract, pluggable interface for TCP load balancers. type TCPLoadBalancer interface { + // TCPLoadBalancerExists returns whether the specified load balancer exists. // TODO: Break this up into different interfaces (LB, etc) when we have more than one type of service TCPLoadBalancerExists(name, region string) (bool, error) + // CreateTCPLoadBalancer creates a new tcp load balancer. CreateTCPLoadBalancer(name, region string, port int, hosts []string) error + // UpdateTCPLoadBalancer updates hosts under the specified load balancer. UpdateTCPLoadBalancer(name, region string, hosts []string) error + // DeleteTCPLoadBalancer deletes a specified load balancer. DeleteTCPLoadBalancer(name, region string) error } +// Instances is an abstract, pluggable interface for sets of instances. type Instances interface { + // IPAddress returns an IP address of the specified instance. IPAddress(name string) (net.IP, error) - // Lists instances that match 'filter' which is a regular expression which must match the entire instance name (fqdn) + // List lists instances that match 'filter' which is a regular expression which must match the entire instance name (fqdn) List(filter string) ([]string, error) } diff --git a/pkg/cloudprovider/fake_cloud.go b/pkg/cloudprovider/fake_cloud.go index b77438fe594..7c6bb9bd441 100644 --- a/pkg/cloudprovider/fake_cloud.go +++ b/pkg/cloudprovider/fake_cloud.go @@ -21,6 +21,7 @@ import ( "regexp" ) +// FakeCloud is a test-double implementation of Interface, TCPLoadBalancer and Instances. It is useful for testing. type FakeCloud struct { Exists bool Err error @@ -33,42 +34,60 @@ func (f *FakeCloud) addCall(desc string) { f.Calls = append(f.Calls, desc) } +// ClearCalls clears internal record of method calls to this FakeCloud. func (f *FakeCloud) ClearCalls() { f.Calls = []string{} } +// TCPLoadBalancer returns a fake implementation of TCPLoadBalancer. +// +// Actually it just returns f itself. func (f *FakeCloud) TCPLoadBalancer() (TCPLoadBalancer, bool) { return f, true } +// Instances returns a fake implementation of Instances. +// +// Actually it just returns f itself. func (f *FakeCloud) Instances() (Instances, bool) { return f, true } +// TCPLoadBalancerExists is a stub implementation of TCPLoadBalancer.TCPLoadBalancerExists. func (f *FakeCloud) TCPLoadBalancerExists(name, region string) (bool, error) { return f.Exists, f.Err } +// CreateTCPLoadBalancer is a test-spy implementation of TCPLoadBalancer.CreateTCPLoadBalancer. +// It adds an entry "create" into the internal method call record. func (f *FakeCloud) CreateTCPLoadBalancer(name, region string, port int, hosts []string) error { f.addCall("create") return f.Err } +// UpdateTCPLoadBalancer is a test-spy implementation of TCPLoadBalancer.UpdateTCPLoadBalancer. +// It adds an entry "update" into the internal method call record. func (f *FakeCloud) UpdateTCPLoadBalancer(name, region string, hosts []string) error { f.addCall("update") return f.Err } +// DeleteTCPLoadBalancer is a test-spy implementation of TCPLoadBalancer.DeleteTCPLoadBalancer. +// It adds an entry "delete" into the internal method call record. func (f *FakeCloud) DeleteTCPLoadBalancer(name, region string) error { f.addCall("delete") return f.Err } +// IPAddress is a test-spy implementation of Instances.IPAddress. +// It adds an entry "ip-address" into the internal method call record. func (f *FakeCloud) IPAddress(instance string) (net.IP, error) { f.addCall("ip-address") return f.IP, f.Err } +// List is a test-spy implementation of Instances.List. +// It adds an entry "list" into the internal method call record. func (f *FakeCloud) List(filter string) ([]string, error) { f.addCall("list") result := []string{} diff --git a/pkg/cloudprovider/gce.go b/pkg/cloudprovider/gce.go index 5c03ceb8972..5697ff2289e 100644 --- a/pkg/cloudprovider/gce.go +++ b/pkg/cloudprovider/gce.go @@ -30,6 +30,7 @@ import ( compute "code.google.com/p/google-api-go-client/compute/v1" ) +// GCECloud is an implementation of Interface, TCPLoadBalancer and Instances for Google Compute Engine. type GCECloud struct { service *compute.Service projectID string @@ -61,6 +62,7 @@ func getProjectAndZone() (string, string, error) { return parts[1], parts[3], nil } +// NewGCECloud creates a new instance of GCECloud. func NewGCECloud() (*GCECloud, error) { projectID, zone, err := getProjectAndZone() if err != nil { @@ -81,10 +83,12 @@ func NewGCECloud() (*GCECloud, error) { }, nil } +// TCPLoadBalancer returns an implementation of TCPLoadBalancer for Google Compute Engine. func (gce *GCECloud) TCPLoadBalancer() (TCPLoadBalancer, bool) { return gce, true } +// Instances returns an implementation of Instances for Google Compute Engine. func (gce *GCECloud) Instances() (Instances, bool) { return gce, true } @@ -128,11 +132,13 @@ func (gce *GCECloud) waitForRegionOp(op *compute.Operation, region string) error return nil } +// TCPLoadBalancerExists is an implementation of TCPLoadBalancer.TCPLoadBalancerExists. func (gce *GCECloud) TCPLoadBalancerExists(name, region string) (bool, error) { _, err := gce.service.ForwardingRules.Get(gce.projectID, region, name).Do() return false, err } +// CreateTCPLoadBalancer is an implementation of TCPLoadBalancer.CreateTCPLoadBalancer. func (gce *GCECloud) CreateTCPLoadBalancer(name, region string, port int, hosts []string) error { pool, err := gce.makeTargetPool(name, region, hosts) if err != nil { @@ -148,6 +154,7 @@ func (gce *GCECloud) CreateTCPLoadBalancer(name, region string, port int, hosts return err } +// UpdateTCPLoadBalancer is an implementation of TCPLoadBalancer.UpdateTCPLoadBalancer. func (gce *GCECloud) UpdateTCPLoadBalancer(name, region string, hosts []string) error { var refs []*compute.InstanceReference for _, host := range hosts { @@ -161,6 +168,7 @@ func (gce *GCECloud) UpdateTCPLoadBalancer(name, region string, hosts []string) return err } +// DeleteTCPLoadBalancer is an implementation of TCPLoadBalancer.DeleteTCPLoadBalancer. func (gce *GCECloud) DeleteTCPLoadBalancer(name, region string) error { _, err := gce.service.ForwardingRules.Delete(gce.projectID, region, name).Do() if err != nil { @@ -170,6 +178,7 @@ func (gce *GCECloud) DeleteTCPLoadBalancer(name, region string) error { return err } +// IPAddress is an implementation of Instances.IPAddress. func (gce *GCECloud) IPAddress(instance string) (net.IP, error) { res, err := gce.service.Instances.Get(gce.projectID, gce.zone, instance).Do() if err != nil { @@ -195,6 +204,7 @@ func fqdnSuffix() (string, error) { return strings.TrimSpace(string(fullHostname)[len(string(hostname)):]), nil } +// List is an implementation of Instances.List. func (gce *GCECloud) List(filter string) ([]string, error) { // GCE gives names without their fqdn suffix, so get that here for appending. // This is needed because the kubelet looks for its jobs in /registry/hosts//pods diff --git a/pkg/controller/replication_controller.go b/pkg/controller/replication_controller.go index 90a366797d0..771d05d1595 100644 --- a/pkg/controller/replication_controller.go +++ b/pkg/controller/replication_controller.go @@ -44,13 +44,16 @@ type ReplicationManager struct { syncHandler func(controllerSpec api.ReplicationController) error } -// An interface that knows how to add or delete pods +// PodControlInterface is an interface that knows how to add or delete pods // created as an interface to allow testing. type PodControlInterface interface { + // createReplica creates new replicated pods according to the spec. createReplica(controllerSpec api.ReplicationController) + // deletePod deletes the pod identified by podID. deletePod(podID string) error } +// RealPodControl is the default implementation of PodControllerInterface. type RealPodControl struct { kubeClient client.ClientInterface } @@ -77,6 +80,7 @@ func (r RealPodControl) deletePod(podID string) error { return r.kubeClient.DeletePod(podID) } +// MakeReplicationManager craetes a new ReplicationManager. func MakeReplicationManager(etcdClient tools.EtcdClient, kubeClient client.ClientInterface) *ReplicationManager { rm := &ReplicationManager{ kubeClient: kubeClient, @@ -91,7 +95,7 @@ func MakeReplicationManager(etcdClient tools.EtcdClient, kubeClient client.Clien return rm } -// Begin watching and syncing. +// Run begins watching and syncing. func (rm *ReplicationManager) Run(period time.Duration) { rm.syncTime = time.Tick(period) go util.Forever(func() { rm.watchControllers() }, period) @@ -145,9 +149,8 @@ func (rm *ReplicationManager) handleWatchResponse(response *etcd.Response) (*api return nil, err } return &controllerSpec, nil - } else { - return nil, fmt.Errorf("response node is null %#v", response) } + return nil, fmt.Errorf("response node is null %#v", response) } else if response.Action == "delete" { // Ensure that the final state of a replication controller is applied before it is deleted. // Otherwise, a replication controller could be modified and then deleted (for example, from 3 to 0 @@ -158,9 +161,8 @@ func (rm *ReplicationManager) handleWatchResponse(response *etcd.Response) (*api return nil, err } return &controllerSpec, nil - } else { - return nil, fmt.Errorf("previous node is null %#v", response) } + return nil, fmt.Errorf("previous node is null %#v", response) } return nil, nil diff --git a/pkg/controller/replication_controller_test.go b/pkg/controller/replication_controller_test.go index bda55a82bcb..9492e4fd658 100644 --- a/pkg/controller/replication_controller_test.go +++ b/pkg/controller/replication_controller_test.go @@ -41,7 +41,7 @@ func expectNoError(t *testing.T, err error) { } } -func makeUrl(suffix string) string { +func makeURL(suffix string) string { return apiPath + suffix } @@ -205,7 +205,7 @@ func TestCreateReplica(t *testing.T) { // DesiredState: controllerSpec.DesiredState.PodTemplate.DesiredState, //} // TODO: fix this so that it validates the body. - fakeHandler.ValidateRequest(t, makeUrl("/pods"), "POST", nil) + fakeHandler.ValidateRequest(t, makeURL("/pods"), "POST", nil) } func TestHandleWatchResponseNotSet(t *testing.T) { diff --git a/pkg/kubecfg/kubecfg.go b/pkg/kubecfg/kubecfg.go index cd398a87c63..8c023b0055e 100644 --- a/pkg/kubecfg/kubecfg.go +++ b/pkg/kubecfg/kubecfg.go @@ -39,7 +39,7 @@ func promptForString(field string) string { return result } -// Parse an AuthInfo object from a file path. Prompt user and create file if it doesn't exist. +// LoadAuthInfo parses an AuthInfo object from a file path. It prompts user and creates file if it doesn't exist. func LoadAuthInfo(path string) (*client.AuthInfo, error) { var auth client.AuthInfo if _, err := os.Stat(path); os.IsNotExist(err) { @@ -63,7 +63,7 @@ func LoadAuthInfo(path string) (*client.AuthInfo, error) { return &auth, err } -// Perform a rolling update of a collection of pods. +// Update performs a rolling update of a collection of pods. // 'name' points to a replication controller. // 'client' is used for updating pods. // 'updatePeriod' is the time between pod updates. diff --git a/pkg/kubecfg/parse.go b/pkg/kubecfg/parse.go index 21b2abc72b1..df5313d209e 100644 --- a/pkg/kubecfg/parse.go +++ b/pkg/kubecfg/parse.go @@ -29,9 +29,8 @@ var storageToType = map[string]reflect.Type{ "replicationControllers": reflect.TypeOf(api.ReplicationController{}), } -// Takes input 'data' as either json or yaml, checks that it parses as the -// appropriate object type, and returns json for sending to the API or an -// error. +// ToWireFormat takes input 'data' as either json or yaml, checks that it parses as the +// appropriate object type, and returns json for sending to the API or an error. func ToWireFormat(data []byte, storage string) ([]byte, error) { prototypeType, found := storageToType[storage] if !found { diff --git a/pkg/kubecfg/parse_test.go b/pkg/kubecfg/parse_test.go index 710f867f513..113c70d092b 100644 --- a/pkg/kubecfg/parse_test.go +++ b/pkg/kubecfg/parse_test.go @@ -31,26 +31,26 @@ func TestParseBadStorage(t *testing.T) { } func DoParseTest(t *testing.T, storage string, obj interface{}) { - json_data, _ := api.Encode(obj) - yaml_data, _ := yaml.Marshal(obj) - t.Logf("Intermediate yaml:\n%v\n", string(yaml_data)) + jsonData, _ := api.Encode(obj) + yamlData, _ := yaml.Marshal(obj) + t.Logf("Intermediate yaml:\n%v\n", string(yamlData)) - json_got, json_err := ToWireFormat(json_data, storage) - yaml_got, yaml_err := ToWireFormat(yaml_data, storage) + jsonGot, jsonErr := ToWireFormat(jsonData, storage) + yamlGot, yamlErr := ToWireFormat(yamlData, storage) - if json_err != nil { - t.Errorf("json err: %#v", json_err) + if jsonErr != nil { + t.Errorf("json err: %#v", jsonErr) } - if yaml_err != nil { - t.Errorf("yaml err: %#v", yaml_err) + if yamlErr != nil { + t.Errorf("yaml err: %#v", yamlErr) } - if string(json_got) != string(json_data) { + if string(jsonGot) != string(jsonData) { t.Errorf("json output didn't match:\nGot:\n%v\n\nWanted:\n%v\n", - string(json_got), string(json_data)) + string(jsonGot), string(jsonData)) } - if string(yaml_got) != string(json_data) { + if string(yamlGot) != string(jsonData) { t.Errorf("yaml parsed output didn't match:\nGot:\n%v\n\nWanted:\n%v\n", - string(yaml_got), string(json_data)) + string(yamlGot), string(jsonData)) } } diff --git a/pkg/kubecfg/proxy_server.go b/pkg/kubecfg/proxy_server.go index c48d557ef9d..11b986ee9e0 100644 --- a/pkg/kubecfg/proxy_server.go +++ b/pkg/kubecfg/proxy_server.go @@ -24,6 +24,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/client" ) +// ProxyServer is a http.Handler which proxies Kubenetes APIs to remote API server. type ProxyServer struct { Host string Auth *client.AuthInfo @@ -34,6 +35,8 @@ func makeFileHandler(prefix, base string) http.Handler { return http.StripPrefix(prefix, http.FileServer(http.Dir(base))) } +// NewProxyServer creates and installs a new ProxyServer. +// It automatically registers the created ProxyServer to http.DefaultServeMux. func NewProxyServer(filebase, host string, auth *client.AuthInfo) *ProxyServer { server := &ProxyServer{ Host: host, @@ -45,7 +48,7 @@ func NewProxyServer(filebase, host string, auth *client.AuthInfo) *ProxyServer { return server } -// Starts the server, loops forever. +// Serve starts the server (http.DefaultServeMux) on TCP port 8001, loops forever. func (s *ProxyServer) Serve() error { return http.ListenAndServe(":8001", nil) } diff --git a/pkg/kubecfg/resource_printer.go b/pkg/kubecfg/resource_printer.go index c2a260877c5..bb6066a5a96 100644 --- a/pkg/kubecfg/resource_printer.go +++ b/pkg/kubecfg/resource_printer.go @@ -35,14 +35,16 @@ type ResourcePrinter interface { PrintObj(interface{}, io.Writer) error } -// Identity printer simply copies the body out to the output stream +// IdentityPrinter is an implementation of ResourcePrinter which simply copies the body out to the output stream type IdentityPrinter struct{} +// Print is an implementation of ResourcePrinter.Print which simply writes the data to the Writer. func (i *IdentityPrinter) Print(data []byte, w io.Writer) error { _, err := w.Write(data) return err } +// PrintObj is an implementation of ResourcePrinter.PrintObj which simply writes the object to the Writer. func (i *IdentityPrinter) PrintObj(obj interface{}, output io.Writer) error { data, err := api.Encode(obj) if err != nil { @@ -51,9 +53,10 @@ func (i *IdentityPrinter) PrintObj(obj interface{}, output io.Writer) error { return i.Print(data, output) } -// YAMLPrinter parses JSON, and re-formats as YAML +// YAMLPrinter is an implementation of ResourcePrinter which parsess JSON, and re-formats as YAML type YAMLPrinter struct{} +// Print parses the data as JSON, re-formats as YAML and prints the YAML. func (y *YAMLPrinter) Print(data []byte, w io.Writer) error { var obj interface{} if err := json.Unmarshal(data, &obj); err != nil { @@ -67,6 +70,7 @@ func (y *YAMLPrinter) Print(data []byte, w io.Writer) error { return err } +// PrintObj prints the data as YAML. func (y *YAMLPrinter) PrintObj(obj interface{}, w io.Writer) error { output, err := yaml.Marshal(obj) if err != nil { @@ -76,7 +80,7 @@ func (y *YAMLPrinter) PrintObj(obj interface{}, w io.Writer) error { return err } -// HumanReadablePrinter attempts to provide more elegant output +// HumanReadablePrinter is an implementation of ResourcePrinter which attempts to provide more elegant output. type HumanReadablePrinter struct{} var podColumns = []string{"Name", "Image(s)", "Host", "Labels"} @@ -177,6 +181,7 @@ func (h *HumanReadablePrinter) printStatus(status *api.Status, w io.Writer) erro return err } +// Print parses the data as JSON, then prints the parsed data in a human-friendly format according to the type of the data. func (h *HumanReadablePrinter) Print(data []byte, output io.Writer) error { var mapObj map[string]interface{} if err := json.Unmarshal([]byte(data), &mapObj); err != nil { @@ -194,6 +199,7 @@ func (h *HumanReadablePrinter) Print(data []byte, output io.Writer) error { return h.PrintObj(obj, output) } +// PrintObj prints the obj in a human-friendly format according to the type of the obj. func (h *HumanReadablePrinter) PrintObj(obj interface{}, output io.Writer) error { w := tabwriter.NewWriter(output, 20, 5, 3, ' ', 0) defer w.Flush() diff --git a/pkg/kubelet/fake_docker_client.go b/pkg/kubelet/fake_docker_client.go index d84496da925..8664ba64e5b 100644 --- a/pkg/kubelet/fake_docker_client.go +++ b/pkg/kubelet/fake_docker_client.go @@ -22,7 +22,7 @@ import ( "github.com/fsouza/go-dockerclient" ) -// A simple fake docker client, so that kubelet can be run for testing without requiring a real docker setup. +// FakeDockerClient is a simple fake docker client, so that kubelet can be run for testing without requiring a real docker setup. type FakeDockerClient struct { containerList []docker.APIContainers container *docker.Container @@ -41,16 +41,22 @@ func (f *FakeDockerClient) appendCall(call string) { f.called = append(f.called, call) } +// ListContainers is a test-spy implementation of DockerInterface.ListContainers. +// It adds an entry "list" to the internal method call record. func (f *FakeDockerClient) ListContainers(options docker.ListContainersOptions) ([]docker.APIContainers, error) { f.appendCall("list") return f.containerList, f.err } +// InspectContainer is a test-spy implementation of DockerInterface.InspectContainer. +// It adds an entry "inspect" to the internal method call record. func (f *FakeDockerClient) InspectContainer(id string) (*docker.Container, error) { f.appendCall("inspect") return f.container, f.err } +// CreateContainer is a test-spy implementation of DockerInterface.CreateContainer. +// It adds an entry "create" to the internal method call record. func (f *FakeDockerClient) CreateContainer(c docker.CreateContainerOptions) (*docker.Container, error) { f.appendCall("create") f.Created = append(f.Created, c.Name) @@ -61,11 +67,15 @@ func (f *FakeDockerClient) CreateContainer(c docker.CreateContainerOptions) (*do return &docker.Container{ID: name}, nil } +// StartContainer is a test-spy implementation of DockerInterface.StartContainer. +// It adds an entry "start" to the internal method call record. func (f *FakeDockerClient) StartContainer(id string, hostConfig *docker.HostConfig) error { f.appendCall("start") return f.err } +// StopContainer is a test-spy implementation of DockerInterface.StopContainer. +// It adds an entry "stop" to the internal method call record. func (f *FakeDockerClient) StopContainer(id string, timeout uint) error { f.appendCall("stop") f.stopped = append(f.stopped, id) @@ -79,12 +89,15 @@ func (f *FakeDockerClient) StopContainer(id string, timeout uint) error { return f.err } +// PullImage is a test-spy implementation of DockerInterface.StopContainer. +// It adds an entry "pull" to the internal method call record. func (f *FakeDockerClient) PullImage(opts docker.PullImageOptions, auth docker.AuthConfiguration) error { f.appendCall("pull") f.pulled = append(f.pulled, fmt.Sprintf("%s/%s:%s", opts.Repository, opts.Registry, opts.Tag)) return f.err } +// FakeDockerPuller is a stub implementation of DockerPuller. type FakeDockerPuller struct { ImagesPulled []string @@ -93,7 +106,7 @@ type FakeDockerPuller struct { ErrorsToInject []error } -// Records the image pull attempt, and optionally injects an error. +// Pull records the image pull attempt, and optionally injects an error. func (f *FakeDockerPuller) Pull(image string) error { f.ImagesPulled = append(f.ImagesPulled, image) diff --git a/pkg/kubelet/health_check.go b/pkg/kubelet/health_check.go index 391d976efa2..7bf9933edf0 100644 --- a/pkg/kubelet/health_check.go +++ b/pkg/kubelet/health_check.go @@ -25,7 +25,9 @@ import ( "github.com/golang/glog" ) +// HealthChecker is an abstract interface for container health checker. type HealthChecker interface { + // IsHealthy checks if the container is healthy. IsHealthy(container api.Container) (bool, error) } @@ -33,6 +35,7 @@ type httpDoInterface interface { Get(string) (*http.Response, error) } +// MakeHealthChecker creates a new HealthChecker. func MakeHealthChecker() HealthChecker { return &MuxHealthChecker{ checkers: map[string]HealthChecker{ @@ -43,10 +46,12 @@ func MakeHealthChecker() HealthChecker { } } +// MuxHealthChecker bundles multiple implementations of HealthChecker of different types. type MuxHealthChecker struct { checkers map[string]HealthChecker } +// IsHealthy checks the health of the container by delegating to an appropriate HealthChecker according to container.LivenessProbe.Type. func (m *MuxHealthChecker) IsHealthy(container api.Container) (bool, error) { checker, ok := m.checkers[container.LivenessProbe.Type] if !ok || checker == nil { @@ -56,6 +61,7 @@ func (m *MuxHealthChecker) IsHealthy(container api.Container) (bool, error) { return checker.IsHealthy(container) } +// HTTPHealthChecker is an implementation of HealthChecker which checks container health by sending HTTP Get requests. type HTTPHealthChecker struct { client httpDoInterface } @@ -70,6 +76,7 @@ func (h *HTTPHealthChecker) findPort(container api.Container, portName string) i return -1 } +// IsHealthy checks if the container is healthy by trying sending HTTP Get requests to the container. func (h *HTTPHealthChecker) IsHealthy(container api.Container) (bool, error) { params := container.LivenessProbe.HTTPGet port := h.findPort(container, params.Port) diff --git a/pkg/kubelet/health_check_test.go b/pkg/kubelet/health_check_test.go index da25b590c29..6aa18dc0425 100644 --- a/pkg/kubelet/health_check_test.go +++ b/pkg/kubelet/health_check_test.go @@ -23,19 +23,19 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" ) -type fakeHttpClient struct { +type fakeHTTPClient struct { req string res http.Response err error } -func (f *fakeHttpClient) Get(url string) (*http.Response, error) { +func (f *fakeHTTPClient) Get(url string) (*http.Response, error) { f.req = url return &f.res, f.err } func TestHttpHealth(t *testing.T) { - fakeClient := fakeHttpClient{ + fakeClient := fakeHTTPClient{ res: http.Response{ StatusCode: http.StatusOK, }, diff --git a/pkg/kubelet/kubelet.go b/pkg/kubelet/kubelet.go index c329f7f9031..65f92da43b4 100644 --- a/pkg/kubelet/kubelet.go +++ b/pkg/kubelet/kubelet.go @@ -44,17 +44,14 @@ import ( "gopkg.in/v1/yaml" ) -// State, sub object of the Docker JSON data -type State struct { - Running bool -} - -// The structured representation of the JSON object returned by Docker inspect +// DockerContainerData is the structured representation of the JSON object returned by Docker inspect type DockerContainerData struct { - state State + state struct { + Running bool + } } -// Interface for testability +// DockerInterface is an abstract interface for testability. It abstracts the interface of docker.Client. type DockerInterface interface { ListContainers(options docker.ListContainersOptions) ([]docker.APIContainers, error) InspectContainer(id string) (*docker.Container, error) @@ -64,24 +61,26 @@ type DockerInterface interface { PullImage(opts docker.PullImageOptions, auth docker.AuthConfiguration) error } -// Type to make it clear when we're working with docker container Ids +// DockerID is an ID of docker container. It is a type to make it clear when we're working with docker container Ids type DockerID string -//Interface for testability +// DockerPuller is an abstract interface for testability. It abstracts image pull operations. type DockerPuller interface { Pull(image string) error } +// CadvisorInterface is an abstract interface for testability. It abstracts the interface of "github.com/google/cadvisor/client".Client. type CadvisorInterface interface { ContainerInfo(name string) (*info.ContainerInfo, error) MachineInfo() (*info.MachineInfo, error) } +// New creates a new Kubelet. func New() *Kubelet { return &Kubelet{} } -// The main kubelet implementation +// Kubelet is the main kubelet implementation. type Kubelet struct { Hostname string EtcdClient tools.EtcdClient @@ -107,9 +106,9 @@ const ( httpServerSource = "http_server" ) -// Starts background goroutines. If config_path, manifest_url, or address are empty, +// RunKubelet starts background goroutines. If config_path, manifest_url, or address are empty, // they are not watched. Never returns. -func (kl *Kubelet) RunKubelet(dockerEndpoint, config_path, manifest_url, etcd_servers, address string, port uint) { +func (kl *Kubelet) RunKubelet(dockerEndpoint, configPath, manifestURL, etcdServers, address string, port uint) { if kl.CadvisorClient == nil { var err error kl.CadvisorClient, err = cadvisor.NewClient("http://127.0.0.1:5000") @@ -121,22 +120,22 @@ func (kl *Kubelet) RunKubelet(dockerEndpoint, config_path, manifest_url, etcd_se kl.DockerPuller = kl.MakeDockerPuller() } updateChannel := make(chan manifestUpdate) - if config_path != "" { - glog.Infof("Watching for file configs at %s", config_path) + if configPath != "" { + glog.Infof("Watching for file configs at %s", configPath) go util.Forever(func() { - kl.WatchFiles(config_path, updateChannel) + kl.WatchFiles(configPath, updateChannel) }, kl.FileCheckFrequency) } - if manifest_url != "" { - glog.Infof("Watching for HTTP configs at %s", manifest_url) + if manifestURL != "" { + glog.Infof("Watching for HTTP configs at %s", manifestURL) go util.Forever(func() { - if err := kl.extractFromHTTP(manifest_url, updateChannel); err != nil { + if err := kl.extractFromHTTP(manifestURL, updateChannel); err != nil { glog.Errorf("Error syncing http: %v", err) } }, kl.HTTPCheckFrequency) } - if etcd_servers != "" { - servers := []string{etcd_servers} + if etcdServers != "" { + servers := []string{etcdServers} glog.Infof("Watching for etcd configs at %v", servers) kl.EtcdClient = etcd.NewClient(servers) go util.Forever(func() { kl.SyncAndSetupEtcdWatch(updateChannel) }, 20*time.Second) @@ -160,15 +159,15 @@ func (kl *Kubelet) RunKubelet(dockerEndpoint, config_path, manifest_url, etcd_se kl.syncLoop(updateChannel, kl) } -// Interface implemented by Kubelet, for testability +// SyncHandler is an interface implemented by Kubelet, for testability type SyncHandler interface { SyncManifests([]api.ContainerManifest) error } -// Log an event to the etcd backend. +// LogEvent logs an event to the etcd backend. func (kl *Kubelet) LogEvent(event *api.Event) error { if kl.EtcdClient == nil { - return fmt.Errorf("no etcd client connection.") + return fmt.Errorf("no etcd client connection") } event.Timestamp = time.Now().Unix() data, err := json.Marshal(event) @@ -234,12 +233,14 @@ func (kl *Kubelet) getContainer(ID DockerID) (*docker.APIContainers, error) { return nil, nil } +// MakeDockerPuller creates a new instance of the default implementation of DockerPuller. func (kl *Kubelet) MakeDockerPuller() DockerPuller { return dockerPuller{ client: kl.DockerClient, } } +// dockerPuller is the default implementation of DockerPuller. type dockerPuller struct { client DockerInterface } @@ -304,7 +305,7 @@ func makeEnvironmentVariables(container *api.Container) []string { return result } -func makeVolumesAndBinds(manifestId string, container *api.Container) (map[string]struct{}, []string) { +func makeVolumesAndBinds(manifestID string, container *api.Container) (map[string]struct{}, []string) { volumes := map[string]struct{}{} binds := []string{} for _, volume := range container.VolumeMounts { @@ -314,7 +315,7 @@ func makeVolumesAndBinds(manifestId string, container *api.Container) (map[strin basePath = fmt.Sprintf("%s:%s", volume.MountPath, volume.MountPath) } else { volumes[volume.MountPath] = struct{}{} - basePath = fmt.Sprintf("/exports/%s/%s:%s", manifestId, volume.Name, volume.MountPath) + basePath = fmt.Sprintf("/exports/%s/%s:%s", manifestID, volume.Name, volume.MountPath) } if volume.ReadOnly { basePath += ":ro" @@ -465,12 +466,12 @@ func (kl *Kubelet) extractFromDir(name string) ([]api.ContainerManifest, error) return manifests, nil } -// Watch a file or direcory of files for changes to the set of pods that +// WatchFiles watches a file or direcory of files for changes to the set of pods that // should run on this Kubelet. -func (kl *Kubelet) WatchFiles(config_path string, updateChannel chan<- manifestUpdate) { +func (kl *Kubelet) WatchFiles(configPath string, updateChannel chan<- manifestUpdate) { var err error - statInfo, err := os.Stat(config_path) + statInfo, err := os.Stat(configPath) if err != nil { if !os.IsNotExist(err) { glog.Errorf("Error accessing path: %v", err) @@ -478,14 +479,14 @@ func (kl *Kubelet) WatchFiles(config_path string, updateChannel chan<- manifestU return } if statInfo.Mode().IsDir() { - manifests, err := kl.extractFromDir(config_path) + manifests, err := kl.extractFromDir(configPath) if err != nil { glog.Errorf("Error polling dir: %v", err) return } updateChannel <- manifestUpdate{fileSource, manifests} } else if statInfo.Mode().IsRegular() { - manifest, err := kl.extractFromFile(config_path) + manifest, err := kl.extractFromFile(configPath) if err != nil { glog.Errorf("Error polling file: %v", err) return @@ -548,8 +549,8 @@ func (kl *Kubelet) extractFromHTTP(url string, updateChannel chan<- manifestUpda url, string(data), singleErr, manifest, multiErr, manifests) } -// Take an etcd Response object, and turn it into a structured list of containers -// Return a list of containers, or an error if one occurs. +// ResponseToManifests takes an etcd Response object, and turns it into a structured list of containers. +// It returns a list of containers, or an error if one occurs. func (kl *Kubelet) ResponseToManifests(response *etcd.Response) ([]api.ContainerManifest, error) { if response.Node == nil || len(response.Node.Value) == 0 { return nil, fmt.Errorf("no nodes field: %v", response) @@ -578,7 +579,7 @@ func (kl *Kubelet) getKubeletStateFromEtcd(key string, updateChannel chan<- mani return nil } -// Sync with etcd, and set up an etcd watch for new configurations +// SyncAndSetupEtcdWatch synchronizes with etcd, and sets up an etcd watch for new configurations. // The channel to send new configurations across // This function loops forever and is intended to be run in a go routine. func (kl *Kubelet) SyncAndSetupEtcdWatch(updateChannel chan<- manifestUpdate) { @@ -610,7 +611,7 @@ func (kl *Kubelet) SyncAndSetupEtcdWatch(updateChannel chan<- manifestUpdate) { } } -// Timeout the watch after 30 seconds +// TimeoutWatch timeout the watch after 30 seconds. func (kl *Kubelet) TimeoutWatch(done chan bool) { t := time.Tick(30 * time.Second) for _ = range t { @@ -618,7 +619,7 @@ func (kl *Kubelet) TimeoutWatch(done chan bool) { } } -// Extract data from YAML file into a list of containers. +// ExtractYAMLData extracts data from YAML file into a list of containers. func (kl *Kubelet) ExtractYAMLData(buf []byte, output interface{}) error { err := yaml.Unmarshal(buf, output) if err != nil { @@ -637,7 +638,7 @@ func (kl *Kubelet) extractFromEtcd(response *etcd.Response) ([]api.ContainerMani return manifests, err } -// Watch etcd for changes, receives config objects from the etcd client watch. +// WatchEtcd watches etcd for changes, receives config objects from the etcd client watch. // This function loops until the watchChannel is closed, and is intended to be run as a goroutine. func (kl *Kubelet) WatchEtcd(watchChannel <-chan *etcd.Response, updateChannel chan<- manifestUpdate) { defer util.HandleCrash() @@ -751,7 +752,7 @@ func (kl *Kubelet) syncManifest(manifest *api.ContainerManifest, keepChannel cha type empty struct{} -// Sync the configured list of containers (desired state) with the host current state +// SyncManifests synchronizes the configured list of containers (desired state) with the host current state. func (kl *Kubelet) SyncManifests(config []api.ContainerManifest) error { glog.Infof("Desired: %+v", config) var err error @@ -873,12 +874,12 @@ func (kl *Kubelet) syncLoop(updateChannel <-chan manifestUpdate, handler SyncHan } } -// getContainerIdFromName looks at the list of containers on the machine and returns the ID of the container whose name +// getContainerIDFromName looks at the list of containers on the machine and returns the ID of the container whose name // matches 'name'. It returns the name of the container, or empty string, if the container isn't found. // it returns true if the container is found, false otherwise, and any error that occurs. // TODO: This functions exists to support GetContainerInfo and GetContainerStats // It should be removed once those two functions start taking proper pod.IDs -func (kl *Kubelet) getContainerIdFromName(name string) (DockerID, bool, error) { +func (kl *Kubelet) getContainerIDFromName(name string) (DockerID, bool, error) { containerList, err := kl.DockerClient.ListContainers(docker.ListContainersOptions{}) if err != nil { return "", false, err @@ -891,7 +892,7 @@ func (kl *Kubelet) getContainerIdFromName(name string) (DockerID, bool, error) { return "", false, nil } -// Returns docker info for all containers in the pod/manifest +// GetPodInfo returns docker info for all containers in the pod/manifest. func (kl *Kubelet) GetPodInfo(podID string) (api.PodInfo, error) { info := api.PodInfo{} @@ -970,7 +971,7 @@ func (kl *Kubelet) statsFromContainerPath(containerPath string) (*api.ContainerS return ret, nil } -// Returns stats (from Cadvisor) for a container. +// GetContainerStats returns stats (from Cadvisor) for a container. func (kl *Kubelet) GetContainerStats(podID, containerName string) (*api.ContainerStats, error) { if kl.CadvisorClient == nil { return nil, nil @@ -982,7 +983,7 @@ func (kl *Kubelet) GetContainerStats(podID, containerName string) (*api.Containe return kl.statsFromContainerPath(fmt.Sprintf("/docker/%s", string(dockerID))) } -// Returns stats (from Cadvisor) of current machine. +// GetMachineStats returns stats (from Cadvisor) of current machine. func (kl *Kubelet) GetMachineStats() (*api.ContainerStats, error) { return kl.statsFromContainerPath("/") } diff --git a/pkg/kubelet/kubelet_server.go b/pkg/kubelet/kubelet_server.go index 01cae8498ae..5154c7ddc98 100644 --- a/pkg/kubelet/kubelet_server.go +++ b/pkg/kubelet/kubelet_server.go @@ -31,6 +31,7 @@ import ( "gopkg.in/v1/yaml" ) +// KubeletServer is a http.Handler which exposes kubelet functionality over HTTP. type KubeletServer struct { Kubelet kubeletInterface UpdateChannel chan<- manifestUpdate diff --git a/pkg/kubelet/kubelet_server_test.go b/pkg/kubelet/kubelet_server_test.go index 4c550edaf7b..bb00612ba95 100644 --- a/pkg/kubelet/kubelet_server_test.go +++ b/pkg/kubelet/kubelet_server_test.go @@ -54,7 +54,7 @@ type serverTestFramework struct { updateReader *channelReader serverUnderTest *KubeletServer fakeKubelet *fakeKubelet - testHttpServer *httptest.Server + testHTTPServer *httptest.Server } func makeServerTest() *serverTestFramework { @@ -67,7 +67,7 @@ func makeServerTest() *serverTestFramework { Kubelet: fw.fakeKubelet, UpdateChannel: fw.updateChan, } - fw.testHttpServer = httptest.NewServer(fw.serverUnderTest) + fw.testHTTPServer = httptest.NewServer(fw.serverUnderTest) return fw } @@ -83,7 +83,7 @@ func TestContainer(t *testing.T) { {ID: "test_manifest"}, } body := bytes.NewBuffer([]byte(util.MakeJSONString(expected[0]))) // Only send a single ContainerManifest - resp, err := http.Post(fw.testHttpServer.URL+"/container", "application/json", body) + resp, err := http.Post(fw.testHTTPServer.URL+"/container", "application/json", body) if err != nil { t.Errorf("Post returned: %v", err) } @@ -105,7 +105,7 @@ func TestContainers(t *testing.T) { {ID: "test_manifest_2"}, } body := bytes.NewBuffer([]byte(util.MakeJSONString(expected))) - resp, err := http.Post(fw.testHttpServer.URL+"/containers", "application/json", body) + resp, err := http.Post(fw.testHTTPServer.URL+"/containers", "application/json", body) if err != nil { t.Errorf("Post returned: %v", err) } @@ -129,7 +129,7 @@ func TestPodInfo(t *testing.T) { } return nil, fmt.Errorf("bad pod") } - resp, err := http.Get(fw.testHttpServer.URL + "/podInfo?podID=goodpod") + resp, err := http.Get(fw.testHTTPServer.URL + "/podInfo?podID=goodpod") if err != nil { t.Errorf("Got error GETing: %v", err) } @@ -170,7 +170,7 @@ func TestContainerStats(t *testing.T) { return expectedStats, nil } - resp, err := http.Get(fw.testHttpServer.URL + fmt.Sprintf("/stats/%v/%v", expectedPodID, expectedContainerName)) + resp, err := http.Get(fw.testHTTPServer.URL + fmt.Sprintf("/stats/%v/%v", expectedPodID, expectedContainerName)) if err != nil { t.Fatalf("Got error GETing: %v", err) } @@ -205,7 +205,7 @@ func TestMachineStats(t *testing.T) { return expectedStats, nil } - resp, err := http.Get(fw.testHttpServer.URL + "/stats") + resp, err := http.Get(fw.testHTTPServer.URL + "/stats") if err != nil { t.Fatalf("Got error GETing: %v", err) } diff --git a/pkg/kubelet/kubelet_test.go b/pkg/kubelet/kubelet_test.go index 0724bf32702..ce071451074 100644 --- a/pkg/kubelet/kubelet_test.go +++ b/pkg/kubelet/kubelet_test.go @@ -913,13 +913,15 @@ type mockCadvisorClient struct { mock.Mock } -func (self *mockCadvisorClient) ContainerInfo(name string) (*info.ContainerInfo, error) { - args := self.Called(name) +// ContainerInfo is a mock implementation of CadvisorInterface.ContainerInfo. +func (c *mockCadvisorClient) ContainerInfo(name string) (*info.ContainerInfo, error) { + args := c.Called(name) return args.Get(0).(*info.ContainerInfo), args.Error(1) } -func (self *mockCadvisorClient) MachineInfo() (*info.MachineInfo, error) { - args := self.Called() +// MachineInfo is a mock implementation of CadvisorInterface.MachineInfo. +func (c *mockCadvisorClient) MachineInfo() (*info.MachineInfo, error) { + args := c.Called() return args.Get(0).(*info.MachineInfo), args.Error(1) }