Merge branch 'master' of github.com:GoogleCloudPlatform/kubernetes into configurable-sleep-interval

This commit is contained in:
Justin Lindh 2014-10-02 14:00:33 -06:00
commit d27eb8153a
29 changed files with 347 additions and 242 deletions

View File

@ -181,6 +181,7 @@ func podsOnMinions(c *client.Client, pods api.PodList) wait.ConditionFunc {
}
func runReplicationControllerTest(c *client.Client) {
ctx := api.NewDefaultContext()
data, err := ioutil.ReadFile("api/examples/controller.json")
if err != nil {
glog.Fatalf("Unexpected error: %#v", err)
@ -191,7 +192,7 @@ func runReplicationControllerTest(c *client.Client) {
}
glog.Infof("Creating replication controllers")
if _, err := c.CreateReplicationController(&controllerRequest); err != nil {
if _, err := c.CreateReplicationController(ctx, &controllerRequest); err != nil {
glog.Fatalf("Unexpected error: %#v", err)
}
glog.Infof("Done creating replication controllers")
@ -202,7 +203,7 @@ func runReplicationControllerTest(c *client.Client) {
}
// wait for minions to indicate they have info about the desired pods
pods, err := c.ListPods(labels.Set(controllerRequest.DesiredState.ReplicaSelector).AsSelector())
pods, err := c.ListPods(ctx, labels.Set(controllerRequest.DesiredState.ReplicaSelector).AsSelector())
if err != nil {
glog.Fatalf("FAILED: unable to get pods to list: %v", err)
}

View File

@ -66,6 +66,7 @@ func init() {
flag.StringVar(&clientConfig.CAFile, "certificate_authority", "", "Path to a cert. file for the certificate authority")
flag.StringVar(&clientConfig.CertFile, "client_certificate", "", "Path to a client certificate for TLS.")
flag.StringVar(&clientConfig.KeyFile, "client_key", "", "Path to a client key file for TLS.")
flag.BoolVar(&clientConfig.Insecure, "insecure_skip_tls_verify", clientConfig.Insecure, "If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.")
}
var parser = kubecfg.NewParser(map[string]runtime.Object{
@ -175,7 +176,7 @@ func main() {
}
// TODO: get the namespace context when kubecfg ns is completed
clientConfig.Context = api.NewContext()
ctx := api.NewContext()
if clientConfig.Host == "" {
// TODO: eventually apiserver should start on 443 and be secure by default
@ -197,6 +198,9 @@ func main() {
if auth.KeyFile != "" {
clientConfig.KeyFile = auth.KeyFile
}
if auth.Insecure != nil {
clientConfig.Insecure = *auth.Insecure
}
}
kubeClient, err := client.New(clientConfig)
if err != nil {
@ -242,7 +246,7 @@ func main() {
}
method := flag.Arg(0)
matchFound := executeAPIRequest(method, kubeClient) || executeControllerRequest(method, kubeClient)
matchFound := executeAPIRequest(ctx, method, kubeClient) || executeControllerRequest(ctx, method, kubeClient)
if matchFound == false {
glog.Fatalf("Unknown command %s", method)
}
@ -302,7 +306,7 @@ func getPrinter() kubecfg.ResourcePrinter {
return printer
}
func executeAPIRequest(method string, c *client.Client) bool {
func executeAPIRequest(ctx api.Context, method string, c *client.Client) bool {
storage, path, hasSuffix := storagePathFromArg(flag.Arg(1))
validStorage := checkStorage(storage)
verb := ""
@ -401,7 +405,7 @@ func executeAPIRequest(method string, c *client.Client) bool {
return true
}
func executeControllerRequest(method string, c *client.Client) bool {
func executeControllerRequest(ctx api.Context, method string, c *client.Client) bool {
parseController := func() string {
if len(flag.Args()) != 2 {
glog.Fatal("usage: kubecfg [OPTIONS] stop|rm|rollingupdate <controller>")
@ -412,11 +416,11 @@ func executeControllerRequest(method string, c *client.Client) bool {
var err error
switch method {
case "stop":
err = kubecfg.StopController(parseController(), c)
err = kubecfg.StopController(ctx, parseController(), c)
case "rm":
err = kubecfg.DeleteController(parseController(), c)
err = kubecfg.DeleteController(ctx, parseController(), c)
case "rollingupdate":
err = kubecfg.Update(parseController(), c, *updatePeriod, *imageName)
err = kubecfg.Update(ctx, parseController(), c, *updatePeriod, *imageName)
case "run":
if len(flag.Args()) != 4 {
glog.Fatal("usage: kubecfg [OPTIONS] run <image> <replicas> <controller>")
@ -427,7 +431,7 @@ func executeControllerRequest(method string, c *client.Client) bool {
glog.Fatalf("Error parsing replicas: %v", err2)
}
name := flag.Arg(3)
err = kubecfg.RunController(image, name, replicas, c, *portSpec, *servicePort)
err = kubecfg.RunController(ctx, image, name, replicas, c, *portSpec, *servicePort)
case "resize":
args := flag.Args()
if len(args) < 3 {
@ -438,7 +442,7 @@ func executeControllerRequest(method string, c *client.Client) bool {
if err2 != nil {
glog.Fatalf("Error parsing replicas: %v", err2)
}
err = kubecfg.ResizeController(name, replicas, c)
err = kubecfg.ResizeController(ctx, name, replicas, c)
default:
return false
}

View File

@ -12,7 +12,7 @@ Via a "label selector" the user can identify a set of `pods`. The label selector
Kubernetes currently supports two objects that use label selectors to keep track of their members, `service`s and `replicationController`s:
- `service`: A service is a configuration unit for the proxies that run on every worker node. It is named and points to one or more pods.
- `replicationController`: A replication controller takes a template and ensures that there is a specified number of "replicas" of that template running at any one time. If there are too many, it'll kill some. If there are too few, it'll start more.
- `replicationController`: A [replication controller](replication-controller.md) ensures that a specified number of pod "replicas" are running at any one time. If there are too many, it'll kill some. If there are too few, it'll start more.
The set of pods that a `service` targets is defined with a label selector. Similarly, the population of pods that a `replicationController` is monitoring is also defined with a label selector.
@ -20,7 +20,7 @@ Pods may be removed from these sets by changing their labels. This flexibility m
For management convenience and consistency, `services` and `replicationControllers` may themselves have labels and would generally carry the labels their corresponding pods have in common.
Sets identified by labels and label selectors could be overlapping (think Venn diagrams). For instance, a service might point to all pods with `tier in (frontend), environment in (prod)`. Now say you have 10 replicated pods that make up this tier. But you want to be able to 'canary' a new version of this component. You could set up a `replicationController` (with `replicas` set to 9) for the bulk of the replicas with labels `tier=frontend, environment=prod, track=stable` and another `replicationController` (with `replicas` set to 1) for the canary with labels `tier=frontend, environment=prod, track=canary`. Now the service is covering both the canary and non-canary pods. But you can mess with the `replicationControllers` separately to test things out, monitor the results, etc.
Sets identified by labels and label selectors could be overlapping (think Venn diagrams). For instance, a service might target all pods with `tier in (frontend), environment in (prod)`. Now say you have 10 replicated pods that make up this tier. But you want to be able to 'canary' a new version of this component. You could set up a `replicationController` (with `replicas` set to 9) for the bulk of the replicas with labels `tier=frontend, environment=prod, track=stable` and another `replicationController` (with `replicas` set to 1) for the canary with labels `tier=frontend, environment=prod, track=canary`. Now the service is covering both the canary and non-canary pods. But you can mess with the `replicationControllers` separately to test things out, monitor the results, etc.
Note that the superset described in the previous example is also heterogeneous. In long-lived, highly available, horizontally scaled, distributed, continuously evolving service applications, heterogeneity is inevitable, due to canaries, incremental rollouts, live reconfiguration, simultaneous updates and auto-scaling, hardware upgrades, and so on.

View File

@ -1,14 +1,30 @@
# Pods
A _pod_ (as in a pod of whales or pea pod) is a relatively tightly coupled group of containers that are scheduled onto the same host. It models an application-specific "virtual host" in a containerized environment. Pods serve as units of scheduling, deployment, and horizontal scaling/replication, and share fate.
## What is a _pod_?
Why doesn't Kubernetes just support an affinity mechanism for co-scheduling containers instead? While pods have a number of benefits (e.g., simplifying the scheduler), the primary motivation is resource sharing.
A _pod_ (as in a pod of whales or pea pod) models an application-specific "logical host" in a containerized environment. It may contain one or more containers which are relatively tightly coupled -- in a pre-container world, they would have executed on the same physical or virtual host.
In addition to defining the containers that run in the pod, the pod specifies a set of shared storage volumes. Pods facilitate data sharing and IPC among their constituents. In the future, they may share CPU and/or memory ([LPC2013](http://www.linuxplumbersconf.org/2013/ocw//system/presentations/1239/original/lmctfy%20(1).pdf)).
Like running containers, pods are considered to be relatively ephemeral rather than durable entities. As discussed in [life of a pod](pod-states.md), pods are scheduled to nodes and remain there until termination (according to restart policy) or deletion. When a node dies, the pods scheduled to that node are deleted. Specific pods are never rescheduled to new nodes; instead, they must be replaced (see [replication controller](replication-controller.md) for more details). (In the future, a higher-level API may support pod migration.)
The containers in the pod also all use the same network namespace/IP (and port space). The goal is for each pod to have an IP address in a flat shared networking namespace that has full communication with other physical computers and containers across the network. [More details on networking](https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/networking.md).
## Motivation for pods
While pods can be used to host vertically integrated application stacks, their primary motivation is to support co-located, co-managed helper programs, such as:
### Resource sharing and communication
Pods facilitate data sharing and communication among their constituents.
The containers in the pod all use the same network namespace/IP and port space, and can find and communicate with each other using localhost. Each pod has an IP address in a flat shared networking namespace that has full communication with other physical computers and containers across the network. The hostname is set to the pod's Name for the containers within the pod. [More details on networking](https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/networking.md).
In addition to defining the containers that run in the pod, the pod specifies a set of shared storage volumes. Volumes enable data to survive container restarts and to be shared among the containers within the pod.
In the future, pods will share IPC namespaces, CPU, and memory ([LPC2013](http://www.linuxplumbersconf.org/2013/ocw//system/presentations/1239/original/lmctfy%20(1).pdf)).
### Management
Pods also simplify application deployment and management by providing a higher-level abstraction than the raw, low-level container interface. Pods serve as units of deployment and horizontal scaling/replication. Co-location, fate sharing, coordinated replication, resource sharing, and dependency management are handled automatically.
## Uses of pods
Pods can be used to host vertically integrated application stacks, but their primary motivation is to support co-located, co-managed helper programs, such as:
- content management systems, file and data loaders, local cache managers, etc.
- log and checkpoint backup, compression, rotation, snapshotting, etc.
- data change watchers, log tailers, logging and monitoring adapters, event publishers, etc.
@ -17,7 +33,13 @@ While pods can be used to host vertically integrated application stacks, their p
Individual pods are not intended to run multiple instances of the same application, in general.
## Alternatives considered
Why not just run multiple programs in a single Docker container?
1. Transparency. Making the containers within the pod visible to the infrastructure enables the infrastructure to provide services to those containers, such as process management and resource monitoring. This facilitates a number of conveniences for users.
2. Decoupling software dependencies. The individual containers may be rebuilt and redeployed independently. Kubernetes may even support live updates of individual containers someday.
2. Decoupling software dependencies. The individual containers may be rebuilt and redeployed independently. Kubernetes may even support live updates of individual containers someday.
3. Ease of use. Users don't need to run their own process managers, worry about signal and exit-code propagation, etc.
4. Efficiency. Because the infrastructure takes on more responsibility, containers can be lighterweight.
Why not support affinity-based co-scheduling of containers? That approach would provide co-location, but would not provide most of the benefits of pods, such as resource sharing, IPC, guaranteed fate sharing, and simplified management.

View File

@ -0,0 +1,65 @@
# Replication Controller
## What is a _replication controller_?
A _replication controller_ ensures that a specified number of pod "replicas" are running at any one time. If there are too many, it will kill some. If there are too few, it will start more. As opposed to just creating singleton pods or even creating pods in bulk, a replication controller replaces pods that are deleted or terminated for any reason, such as in the case of node failure. For this reason, we recommend that you use a replication controller even if your application requires only a single pod.
As discussed in [life of a pod](pod-states.md), `replicationController` is *only* appropriate for pods with `RestartPolicy = Always`. `ReplicationController` should refuse to instantiate any pod that has a different restart policy. As discussed in [issue #503](https://github.com/GoogleCloudPlatform/kubernetes/issues/503#issuecomment-50169443), we expect other types of controllers to be added to Kubernetes to handle other types of workloads, such as build/test and batch workloads, in the future.
A replication controller will never terminate on its own, but it isn't expected to be as long-lived as services. Services may be comprised of pods controlled by multiple replication controllers, and it is expected that many replication controllers may be created and destroyed over the lifetime of a service. Both services themselves and their clients should remain oblivious to the replication controllers that maintain the pods of the services.
## How does a replication controller work?
### Pod template
A replication controller creates new pods from a template, which is currently inline in the `replicationController` object, but which we plan to extract into its own resource [#170](https://github.com/GoogleCloudPlatform/kubernetes/issues/170).
Rather than specifying the current desired state of all replicas, pod templates are like cookie cutters. Once a cookie has been cut, the cookie has no relationship to the cutter. There is no quantum entanglement. Subsequent changes to the template or even switching to a new template has no direct effect on the pods already created. Similarly, pods created by a replication controller may subsequently be updated directly. This is in deliberate contrast to pods, which do specify the current desired state of all containers belonging to the pod. This approach radically simplifies system semantics and increases the flexibility of the primitive, as demonstrated by the use cases explained below.
Pods created by a replication controller are intended to be fungible and semantically identical, though their configurations may become heterogeneous over time. This is an obvious fit for replicated stateless servers, but replication controllers can also be used to maintain availability of master-elected, sharded, and worker-pool applications. Such applications should use dynamic work assignment mechanisms, such as the [etcd lock module](https://coreos.com/docs/distributed-configuration/etcd-modules/) or [RabbitMQ work queues](https://www.rabbitmq.com/tutorials/tutorial-two-python.html), as opposed to static/one-time customization of the configuration of each pod, which is considerined an anti-pattern. Any pod customization performed, such as vertical auto-sizing of resources (e.g., cpu or memory), should be performed by another online controller process, not unlike the replication controller itself.
### Labels
The population of pods that a `replicationController` is monitoring is defined with a [label selector](labels.md), which creates a loosely coupled relationship between the controller and the pods controlled, in contrast to pods, which are more tightly coupled. We deliberately chose not to represent the set of pods controlled using a fixed-length array of pod specifications, because our experience is that that approach increases complexity of management operations, for both clients and the system.
The replication controller should verify that the pods created from the specified template have labels that match its label selector. Though it isn't verified yet, you should also ensure that only one replication controller controls any given pod, by ensuring that the label selectors of replication controllers do not target overlapping sets.
Note that `replicationControllers` may themselves have labels and would generally carry the labels their corresponding pods have in common, but these labels do not affect the behavior of the replication controllers.
Pods may be removed from a replication controller's target set by changing their labels. This technique may be used to remove pods from service for debugging, data recovery, etc. Pods that are removed in this way will be replaced automatically (assuming that the number of replicas is not also changed).
Similarly, deleting a replication controller does not affect the pods it created. It's `replicas` field must first be set to 0 in order to delete the pods controlled. In the future, we may provide a feature to do this and the deletion in a single client operation.
## Responsibilities of the replication controller
The replication controller simply ensures that the desired number of pods matches its label selector and are operational. Currently, only terminated pods are excluded from its count. In the future, [readiness](https://github.com/GoogleCloudPlatform/kubernetes/issues/620) and other information available from the system may be taken into account, we may add more controls over the replacement policy, and we plan to emit events that could be used by external clients to implement arbitrarily sophisticated replacement and/or scale-down policies.
The replication controller is forever constrained to this narrow responsibility. It itself will not perform readiness nor liveness probes. Rather than performing auto-scaling, it is intended to be controlled by an external auto-scaler (as discussed in [#492](https://github.com/GoogleCloudPlatform/kubernetes/issues/492)), which would change its `replicas` field. We will not add scheduling policies (e.g., [spreading](https://github.com/GoogleCloudPlatform/kubernetes/issues/367#issuecomment-48428019)) to replication controller. Nor should it verify that the pods controlled match the currently specified template, as that would obstruct auto-sizing and other automated processes. Similarly, completion deadlines, ordering dependencies, configuration expansion, and other features belong elsehwere. We even plan to factor out the mechanism for bulk pod creation ([#170](https://github.com/GoogleCloudPlatform/kubernetes/issues/170)).
The replication controller is intended to be a composable building-block primitive. We expect higher-level APIs and/or tools to be built on top of it and other complementary primitives for user convenience in the future. The "macro" operations currently supported by kubecfg (run, stop, resize, rollingupdate) are proof-of-concept examples of this. For instance, we could imagine something like [Asgard](http://techblog.netflix.com/2012/06/asgard-web-based-cloud-management-and.html) managing replication controllers, auto-scalers, services, scheduling policies, canaries, etc.
## Common usage patterns
### Rescheduling
As mentioned above, whether you have 1 pod you want to keep running, or 1000, replication controller will ensure that the specified number of pods exists, even in the event of node failure or pod termination (e.g., due to an action by another control agent).
### Scaling
Replication controller makes it easy to scale the number of replicas up or down, either manually or by an auto-scaling control agent, by simply updating the `replicas` field.
### Rolling updates
Replication controller is designed to facilitate rolling updates to a service by replacing pods one-by-one.
As explained in [#1353](https://github.com/GoogleCloudPlatform/kubernetes/issues/1353), the recommended approach is to create a new replication controller with 1 replica, resize the new (+1) and old (-1) controllers one by one, and then delete the old controller after it reaches 0 replicas. This predictably updates the set of pods regardless of unexpected failures.
Ideally, the rolling update controller would take application readiness into account, and would ensure that a sufficient number of pods were productively serving at any given time.
The two replication controllers would need to create pods with at least one differentiating label, such as the image tag of the primary container of the pod, since it is typically image updates that motivate rolling updates.
### Multiple release tracks
In addition to running multiple releases of an application while a rolling update is in progress, it's common to run multiple releases for an extended period of time, or even continuously, using multiple release tracks. The tracks would be differentiated by labels.
For instance, a service might target all pods with `tier in (frontend), environment in (prod)`. Now say you have 10 replicated pods that make up this tier. But you want to be able to 'canary' a new version of this component. You could set up a `replicationController` with `replicas` set to 9 for the bulk of the replicas, with labels `tier=frontend, environment=prod, track=stable`, and another `replicationController` with `replicas` set to 1 for the canary, with labels `tier=frontend, environment=prod, track=canary`. Now the service is covering both the canary and non-canary pods. But you can mess with the `replicationControllers` separately to test things out, monitor the results, etc.

View File

@ -12,24 +12,24 @@ A process in a Container sees a filesystem view composed from two sources: a sin
Kubernetes currently supports two types of Volumes, but more may be added in the future.
### EmptyDirectory
### EmptyDir
An EmptyDirectory volume is created when a Pod is bound to a Node. It is initially empty, when the first Container command starts. Containers in the same pod can all read and write the same files in the EmptyDirectory. When a Pod is unbound, the data in the EmptyDirectory is deleted forever.
An EmptyDir volume is created when a Pod is bound to a Node. It is initially empty, when the first Container command starts. Containers in the same pod can all read and write the same files in the EmptyDir. When a Pod is unbound, the data in the EmptyDir is deleted forever.
Some uses for an EmptyDirectory are:
Some uses for an EmptyDir are:
- scratch space, such as for a disk-based mergesort or checkpointing a long computation.
- a directory that a content-manager container fills with data while a webserver container serves the data.
Currently, the user cannot control what kind of media is used for an EmptyDirectory. If the Kubelet is configured to use a disk drive, then all EmptyDirectories will be created on that disk drive. In the future, it is expected that Pods can control whether the EmptyDirectory is on a disk drive, SSD, or tmpfs.
Currently, the user cannot control what kind of media is used for an EmptyDir. If the Kubelet is configured to use a disk drive, then all EmptyDirectories will be created on that disk drive. In the future, it is expected that Pods can control whether the EmptyDir is on a disk drive, SSD, or tmpfs.
### HostDirectory
A Volume with a HostDirectory property allows access to files on the current node.
### HostDir
A Volume with a HostDir property allows access to files on the current node.
Some uses for a HostDirectory are:
- running a container that needs access to Docker internals; use a HostDirectory of /var/lib/docker.
- running cAdvisor in a container; use a HostDirectory of /dev/cgroups.
Some uses for a HostDir are:
- running a container that needs access to Docker internals; use a HostDir of /var/lib/docker.
- running cAdvisor in a container; use a HostDir of /dev/cgroups.
Watch out when using this type of volume, because:
- pods with identical configuration (such as created from a podTemplate) may behave differently on different nodes due to different files on different nodes.
- When Kubernetes adds resource-aware scheduling, as is planned, it will not be able to account for resources used by a HostDirectory.
- When Kubernetes adds resource-aware scheduling, as is planned, it will not be able to account for resources used by a HostDir.

View File

@ -85,22 +85,22 @@ type Volume struct {
type VolumeSource struct {
// Only one of the following sources may be specified
// HostDirectory represents a pre-existing directory on the host machine that is directly
// HostDir represents a pre-existing directory on the host machine that is directly
// exposed to the container. This is generally used for system agents or other privileged
// things that are allowed to see the host machine. Most containers will NOT need this.
// TODO(jonesdl) We need to restrict who can use host directory mounts and
// who can/can not mount host directories as read/write.
HostDirectory *HostDirectory `yaml:"hostDir" json:"hostDir"`
// EmptyDirectory represents a temporary directory that shares a pod's lifetime.
EmptyDirectory *EmptyDirectory `yaml:"emptyDir" json:"emptyDir"`
HostDir *HostDir `yaml:"hostDir" json:"hostDir"`
// EmptyDir represents a temporary directory that shares a pod's lifetime.
EmptyDir *EmptyDir `yaml:"emptyDir" json:"emptyDir"`
}
// HostDirectory represents bare host directory volume.
type HostDirectory struct {
// HostDir represents bare host directory volume.
type HostDir struct {
Path string `yaml:"path" json:"path"`
}
type EmptyDirectory struct{}
type EmptyDir struct{}
// Protocol defines network protocols supported for things like conatiner ports.
type Protocol string

View File

@ -83,22 +83,22 @@ type Volume struct {
type VolumeSource struct {
// Only one of the following sources may be specified
// HostDirectory represents a pre-existing directory on the host machine that is directly
// HostDir represents a pre-existing directory on the host machine that is directly
// exposed to the container. This is generally used for system agents or other privileged
// things that are allowed to see the host machine. Most containers will NOT need this.
// TODO(jonesdl) We need to restrict who can use host directory mounts and
// who can/can not mount host directories as read/write.
HostDirectory *HostDirectory `yaml:"hostDir" json:"hostDir"`
// EmptyDirectory represents a temporary directory that shares a pod's lifetime.
EmptyDirectory *EmptyDirectory `yaml:"emptyDir" json:"emptyDir"`
HostDir *HostDir `yaml:"hostDir" json:"hostDir"`
// EmptyDir represents a temporary directory that shares a pod's lifetime.
EmptyDir *EmptyDir `yaml:"emptyDir" json:"emptyDir"`
}
// HostDirectory represents bare host directory volume.
type HostDirectory struct {
// HostDir represents bare host directory volume.
type HostDir struct {
Path string `yaml:"path" json:"path"`
}
type EmptyDirectory struct{}
type EmptyDir struct{}
// Protocol defines network protocols supported for things like conatiner ports.
type Protocol string

View File

@ -83,22 +83,22 @@ type Volume struct {
type VolumeSource struct {
// Only one of the following sources may be specified
// HostDirectory represents a pre-existing directory on the host machine that is directly
// HostDir represents a pre-existing directory on the host machine that is directly
// exposed to the container. This is generally used for system agents or other privileged
// things that are allowed to see the host machine. Most containers will NOT need this.
// TODO(jonesdl) We need to restrict who can use host directory mounts and
// who can/can not mount host directories as read/write.
HostDirectory *HostDirectory `yaml:"hostDir" json:"hostDir"`
// EmptyDirectory represents a temporary directory that shares a pod's lifetime.
EmptyDirectory *EmptyDirectory `yaml:"emptyDir" json:"emptyDir"`
HostDir *HostDir `yaml:"hostDir" json:"hostDir"`
// EmptyDir represents a temporary directory that shares a pod's lifetime.
EmptyDir *EmptyDir `yaml:"emptyDir" json:"emptyDir"`
}
// HostDirectory represents bare host directory volume.
type HostDirectory struct {
// HostDir represents bare host directory volume.
type HostDir struct {
Path string `yaml:"path" json:"path"`
}
type EmptyDirectory struct{}
type EmptyDir struct{}
// Protocol defines network protocols supported for things like conatiner ports.
type Protocol string

View File

@ -126,22 +126,22 @@ type Volume struct {
type VolumeSource struct {
// Only one of the following sources may be specified
// HostDirectory represents a pre-existing directory on the host machine that is directly
// HostDir represents a pre-existing directory on the host machine that is directly
// exposed to the container. This is generally used for system agents or other privileged
// things that are allowed to see the host machine. Most containers will NOT need this.
// TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not
// mount host directories as read/write.
HostDirectory *HostDirectory `json:"hostDir" yaml:"hostDir"`
// EmptyDirectory represents a temporary directory that shares a pod's lifetime.
EmptyDirectory *EmptyDirectory `json:"emptyDir" yaml:"emptyDir"`
HostDir *HostDir `json:"hostDir" yaml:"hostDir"`
// EmptyDir represents a temporary directory that shares a pod's lifetime.
EmptyDir *EmptyDir `json:"emptyDir" yaml:"emptyDir"`
}
// HostDirectory represents bare host directory volume.
type HostDirectory struct {
// HostDir represents bare host directory volume.
type HostDir struct {
Path string `json:"path" yaml:"path"`
}
type EmptyDirectory struct{}
type EmptyDir struct{}
// Protocol defines network protocols supported for things like conatiner ports.
type Protocol string

View File

@ -56,11 +56,11 @@ func validateVolumes(volumes []api.Volume) (util.StringSet, errs.ErrorList) {
func validateSource(source *api.VolumeSource) errs.ErrorList {
numVolumes := 0
allErrs := errs.ErrorList{}
if source.HostDirectory != nil {
if source.HostDir != nil {
numVolumes++
allErrs = append(allErrs, validateHostDir(source.HostDirectory).Prefix("hostDirectory")...)
allErrs = append(allErrs, validateHostDir(source.HostDir).Prefix("hostDirectory")...)
}
if source.EmptyDirectory != nil {
if source.EmptyDir != nil {
numVolumes++
//EmptyDirs have nothing to validate
}
@ -70,7 +70,7 @@ func validateSource(source *api.VolumeSource) errs.ErrorList {
return allErrs
}
func validateHostDir(hostDir *api.HostDirectory) errs.ErrorList {
func validateHostDir(hostDir *api.HostDir) errs.ErrorList {
allErrs := errs.ErrorList{}
if hostDir.Path == "" {
allErrs = append(allErrs, errs.NewNotFound("path", hostDir.Path))

View File

@ -37,9 +37,9 @@ func expectPrefix(t *testing.T, prefix string, errs errors.ErrorList) {
func TestValidateVolumes(t *testing.T) {
successCase := []api.Volume{
{Name: "abc"},
{Name: "123", Source: &api.VolumeSource{HostDirectory: &api.HostDirectory{"/mnt/path2"}}},
{Name: "abc-123", Source: &api.VolumeSource{HostDirectory: &api.HostDirectory{"/mnt/path3"}}},
{Name: "empty", Source: &api.VolumeSource{EmptyDirectory: &api.EmptyDirectory{}}},
{Name: "123", Source: &api.VolumeSource{HostDir: &api.HostDir{"/mnt/path2"}}},
{Name: "abc-123", Source: &api.VolumeSource{HostDir: &api.HostDir{"/mnt/path3"}}},
{Name: "empty", Source: &api.VolumeSource{EmptyDir: &api.EmptyDir{}}},
}
names, errs := validateVolumes(successCase)
if len(errs) != 0 {
@ -309,8 +309,8 @@ func TestValidateManifest(t *testing.T) {
{
Version: "v1beta1",
ID: "abc",
Volumes: []api.Volume{{Name: "vol1", Source: &api.VolumeSource{HostDirectory: &api.HostDirectory{"/mnt/vol1"}}},
{Name: "vol2", Source: &api.VolumeSource{HostDirectory: &api.HostDirectory{"/mnt/vol2"}}}},
Volumes: []api.Volume{{Name: "vol1", Source: &api.VolumeSource{HostDir: &api.HostDir{"/mnt/vol1"}}},
{Name: "vol2", Source: &api.VolumeSource{HostDir: &api.HostDir{"/mnt/vol2"}}}},
Containers: []api.Container{
{
Name: "abc",

View File

@ -39,38 +39,38 @@ type Interface interface {
// PodInterface has methods to work with Pod resources.
type PodInterface interface {
ListPods(selector labels.Selector) (*api.PodList, error)
GetPod(id string) (*api.Pod, error)
DeletePod(id string) error
CreatePod(*api.Pod) (*api.Pod, error)
UpdatePod(*api.Pod) (*api.Pod, error)
ListPods(ctx api.Context, selector labels.Selector) (*api.PodList, error)
GetPod(ctx api.Context, id string) (*api.Pod, error)
DeletePod(ctx api.Context, id string) error
CreatePod(ctx api.Context, pod *api.Pod) (*api.Pod, error)
UpdatePod(ctx api.Context, pod *api.Pod) (*api.Pod, error)
}
// ReplicationControllerInterface has methods to work with ReplicationController resources.
type ReplicationControllerInterface interface {
ListReplicationControllers(selector labels.Selector) (*api.ReplicationControllerList, error)
GetReplicationController(id string) (*api.ReplicationController, error)
CreateReplicationController(*api.ReplicationController) (*api.ReplicationController, error)
UpdateReplicationController(*api.ReplicationController) (*api.ReplicationController, error)
DeleteReplicationController(string) error
WatchReplicationControllers(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error)
ListReplicationControllers(ctx api.Context, selector labels.Selector) (*api.ReplicationControllerList, error)
GetReplicationController(ctx api.Context, id string) (*api.ReplicationController, error)
CreateReplicationController(ctx api.Context, ctrl *api.ReplicationController) (*api.ReplicationController, error)
UpdateReplicationController(ctx api.Context, ctrl *api.ReplicationController) (*api.ReplicationController, error)
DeleteReplicationController(ctx api.Context, id string) error
WatchReplicationControllers(ctx api.Context, label, field labels.Selector, resourceVersion uint64) (watch.Interface, error)
}
// ServiceInterface has methods to work with Service resources.
type ServiceInterface interface {
ListServices(selector labels.Selector) (*api.ServiceList, error)
GetService(id string) (*api.Service, error)
CreateService(*api.Service) (*api.Service, error)
UpdateService(*api.Service) (*api.Service, error)
DeleteService(string) error
WatchServices(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error)
ListServices(ctx api.Context, selector labels.Selector) (*api.ServiceList, error)
GetService(ctx api.Context, id string) (*api.Service, error)
CreateService(ctx api.Context, srv *api.Service) (*api.Service, error)
UpdateService(ctx api.Context, srv *api.Service) (*api.Service, error)
DeleteService(ctx api.Context, id string) error
WatchServices(ctx api.Context, label, field labels.Selector, resourceVersion uint64) (watch.Interface, error)
}
// EndpointsInterface has methods to work with Endpoints resources
type EndpointsInterface interface {
ListEndpoints(selector labels.Selector) (*api.EndpointsList, error)
GetEndpoints(id string) (*api.Endpoints, error)
WatchEndpoints(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error)
ListEndpoints(ctx api.Context, selector labels.Selector) (*api.EndpointsList, error)
GetEndpoints(ctx api.Context, id string) (*api.Endpoints, error)
WatchEndpoints(ctx api.Context, label, field labels.Selector, resourceVersion uint64) (watch.Interface, error)
}
// VersionInterface has a method to retrieve the server version.
@ -94,33 +94,33 @@ type Client struct {
}
// ListPods takes a selector, and returns the list of pods that match that selector.
func (c *Client) ListPods(selector labels.Selector) (result *api.PodList, err error) {
func (c *Client) ListPods(ctx api.Context, selector labels.Selector) (result *api.PodList, err error) {
result = &api.PodList{}
err = c.Get().Path("pods").SelectorParam("labels", selector).Do().Into(result)
return
}
// GetPod takes the id of the pod, and returns the corresponding Pod object, and an error if it occurs
func (c *Client) GetPod(id string) (result *api.Pod, err error) {
func (c *Client) GetPod(ctx api.Context, id string) (result *api.Pod, err error) {
result = &api.Pod{}
err = c.Get().Path("pods").Path(id).Do().Into(result)
return
}
// DeletePod takes the id of the pod, and returns an error if one occurs
func (c *Client) DeletePod(id string) error {
func (c *Client) DeletePod(ctx api.Context, id string) error {
return c.Delete().Path("pods").Path(id).Do().Error()
}
// CreatePod takes the representation of a pod. Returns the server's representation of the pod, and an error, if it occurs.
func (c *Client) CreatePod(pod *api.Pod) (result *api.Pod, err error) {
func (c *Client) CreatePod(ctx api.Context, pod *api.Pod) (result *api.Pod, err error) {
result = &api.Pod{}
err = c.Post().Path("pods").Body(pod).Do().Into(result)
return
}
// UpdatePod takes the representation of a pod to update. Returns the server's representation of the pod, and an error, if it occurs.
func (c *Client) UpdatePod(pod *api.Pod) (result *api.Pod, err error) {
func (c *Client) UpdatePod(ctx api.Context, pod *api.Pod) (result *api.Pod, err error) {
result = &api.Pod{}
if pod.ResourceVersion == 0 {
err = fmt.Errorf("invalid update object, missing resource version: %v", pod)
@ -131,28 +131,28 @@ func (c *Client) UpdatePod(pod *api.Pod) (result *api.Pod, err error) {
}
// ListReplicationControllers takes a selector, and returns the list of replication controllers that match that selector.
func (c *Client) ListReplicationControllers(selector labels.Selector) (result *api.ReplicationControllerList, err error) {
func (c *Client) ListReplicationControllers(ctx api.Context, selector labels.Selector) (result *api.ReplicationControllerList, err error) {
result = &api.ReplicationControllerList{}
err = c.Get().Path("replicationControllers").SelectorParam("labels", selector).Do().Into(result)
return
}
// GetReplicationController returns information about a particular replication controller.
func (c *Client) GetReplicationController(id string) (result *api.ReplicationController, err error) {
func (c *Client) GetReplicationController(ctx api.Context, id string) (result *api.ReplicationController, err error) {
result = &api.ReplicationController{}
err = c.Get().Path("replicationControllers").Path(id).Do().Into(result)
return
}
// CreateReplicationController creates a new replication controller.
func (c *Client) CreateReplicationController(controller *api.ReplicationController) (result *api.ReplicationController, err error) {
func (c *Client) CreateReplicationController(ctx api.Context, controller *api.ReplicationController) (result *api.ReplicationController, err error) {
result = &api.ReplicationController{}
err = c.Post().Path("replicationControllers").Body(controller).Do().Into(result)
return
}
// UpdateReplicationController updates an existing replication controller.
func (c *Client) UpdateReplicationController(controller *api.ReplicationController) (result *api.ReplicationController, err error) {
func (c *Client) UpdateReplicationController(ctx api.Context, controller *api.ReplicationController) (result *api.ReplicationController, err error) {
result = &api.ReplicationController{}
if controller.ResourceVersion == 0 {
err = fmt.Errorf("invalid update object, missing resource version: %v", controller)
@ -163,12 +163,12 @@ func (c *Client) UpdateReplicationController(controller *api.ReplicationControll
}
// DeleteReplicationController deletes an existing replication controller.
func (c *Client) DeleteReplicationController(id string) error {
func (c *Client) DeleteReplicationController(ctx api.Context, id string) error {
return c.Delete().Path("replicationControllers").Path(id).Do().Error()
}
// WatchReplicationControllers returns a watch.Interface that watches the requested controllers.
func (c *Client) WatchReplicationControllers(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) {
func (c *Client) WatchReplicationControllers(ctx api.Context, label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) {
return c.Get().
Path("watch").
Path("replicationControllers").
@ -179,28 +179,28 @@ func (c *Client) WatchReplicationControllers(label, field labels.Selector, resou
}
// ListServices takes a selector, and returns the list of services that match that selector
func (c *Client) ListServices(selector labels.Selector) (result *api.ServiceList, err error) {
func (c *Client) ListServices(ctx api.Context, selector labels.Selector) (result *api.ServiceList, err error) {
result = &api.ServiceList{}
err = c.Get().Path("services").SelectorParam("labels", selector).Do().Into(result)
return
}
// GetService returns information about a particular service.
func (c *Client) GetService(id string) (result *api.Service, err error) {
func (c *Client) GetService(ctx api.Context, id string) (result *api.Service, err error) {
result = &api.Service{}
err = c.Get().Path("services").Path(id).Do().Into(result)
return
}
// CreateService creates a new service.
func (c *Client) CreateService(svc *api.Service) (result *api.Service, err error) {
func (c *Client) CreateService(ctx api.Context, svc *api.Service) (result *api.Service, err error) {
result = &api.Service{}
err = c.Post().Path("services").Body(svc).Do().Into(result)
return
}
// UpdateService updates an existing service.
func (c *Client) UpdateService(svc *api.Service) (result *api.Service, err error) {
func (c *Client) UpdateService(ctx api.Context, svc *api.Service) (result *api.Service, err error) {
result = &api.Service{}
if svc.ResourceVersion == 0 {
err = fmt.Errorf("invalid update object, missing resource version: %v", svc)
@ -211,12 +211,12 @@ func (c *Client) UpdateService(svc *api.Service) (result *api.Service, err error
}
// DeleteService deletes an existing service.
func (c *Client) DeleteService(id string) error {
func (c *Client) DeleteService(ctx api.Context, id string) error {
return c.Delete().Path("services").Path(id).Do().Error()
}
// WatchServices returns a watch.Interface that watches the requested services.
func (c *Client) WatchServices(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) {
func (c *Client) WatchServices(ctx api.Context, label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) {
return c.Get().
Path("watch").
Path("services").
@ -227,21 +227,21 @@ func (c *Client) WatchServices(label, field labels.Selector, resourceVersion uin
}
// ListEndpoints takes a selector, and returns the list of endpoints that match that selector
func (c *Client) ListEndpoints(selector labels.Selector) (result *api.EndpointsList, err error) {
func (c *Client) ListEndpoints(ctx api.Context, selector labels.Selector) (result *api.EndpointsList, err error) {
result = &api.EndpointsList{}
err = c.Get().Path("endpoints").SelectorParam("labels", selector).Do().Into(result)
return
}
// GetEndpoints returns information about the endpoints for a particular service.
func (c *Client) GetEndpoints(id string) (result *api.Endpoints, err error) {
func (c *Client) GetEndpoints(ctx api.Context, id string) (result *api.Endpoints, err error) {
result = &api.Endpoints{}
err = c.Get().Path("endpoints").Path(id).Do().Into(result)
return
}
// WatchEndpoints returns a watch.Interface that watches the requested endpoints for a service.
func (c *Client) WatchEndpoints(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) {
func (c *Client) WatchEndpoints(ctx api.Context, label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) {
return c.Get().
Path("watch").
Path("endpoints").
@ -251,13 +251,13 @@ func (c *Client) WatchEndpoints(label, field labels.Selector, resourceVersion ui
Watch()
}
func (c *Client) CreateEndpoints(endpoints *api.Endpoints) (*api.Endpoints, error) {
func (c *Client) CreateEndpoints(ctx api.Context, endpoints *api.Endpoints) (*api.Endpoints, error) {
result := &api.Endpoints{}
err := c.Post().Path("endpoints").Body(endpoints).Do().Into(result)
return result, err
}
func (c *Client) UpdateEndpoints(endpoints *api.Endpoints) (*api.Endpoints, error) {
func (c *Client) UpdateEndpoints(ctx api.Context, endpoints *api.Endpoints) (*api.Endpoints, error) {
result := &api.Endpoints{}
if endpoints.ResourceVersion == 0 {
return nil, fmt.Errorf("invalid update object, missing resource version: %v", endpoints)

View File

@ -145,15 +145,17 @@ func (c *testClient) ValidateCommon(t *testing.T, err error) {
}
func TestListEmptyPods(t *testing.T) {
ctx := api.NewContext()
c := &testClient{
Request: testRequest{Method: "GET", Path: "/pods"},
Response: Response{StatusCode: 200, Body: &api.PodList{}},
}
podList, err := c.Setup().ListPods(labels.Everything())
podList, err := c.Setup().ListPods(ctx, labels.Everything())
c.Validate(t, podList, err)
}
func TestListPods(t *testing.T) {
ctx := api.NewDefaultContext()
c := &testClient{
Request: testRequest{Method: "GET", Path: "/pods"},
Response: Response{StatusCode: 200,
@ -172,7 +174,7 @@ func TestListPods(t *testing.T) {
},
},
}
receivedPodList, err := c.Setup().ListPods(labels.Everything())
receivedPodList, err := c.Setup().ListPods(ctx, labels.Everything())
c.Validate(t, receivedPodList, err)
}
@ -183,6 +185,7 @@ func validateLabels(a, b string) bool {
}
func TestListPodsLabels(t *testing.T) {
ctx := api.NewDefaultContext()
c := &testClient{
Request: testRequest{Method: "GET", Path: "/pods", Query: url.Values{"labels": []string{"foo=bar,name=baz"}}},
Response: Response{
@ -205,11 +208,12 @@ func TestListPodsLabels(t *testing.T) {
c.Setup()
c.QueryValidator["labels"] = validateLabels
selector := labels.Set{"foo": "bar", "name": "baz"}.AsSelector()
receivedPodList, err := c.ListPods(selector)
receivedPodList, err := c.ListPods(ctx, selector)
c.Validate(t, receivedPodList, err)
}
func TestGetPod(t *testing.T) {
ctx := api.NewDefaultContext()
c := &testClient{
Request: testRequest{Method: "GET", Path: "/pods/foo"},
Response: Response{
@ -225,7 +229,7 @@ func TestGetPod(t *testing.T) {
},
},
}
receivedPod, err := c.Setup().GetPod("foo")
receivedPod, err := c.Setup().GetPod(ctx, "foo")
c.Validate(t, receivedPod, err)
}
@ -234,7 +238,7 @@ func TestDeletePod(t *testing.T) {
Request: testRequest{Method: "DELETE", Path: "/pods/foo"},
Response: Response{StatusCode: 200},
}
err := c.Setup().DeletePod("foo")
err := c.Setup().DeletePod(api.NewDefaultContext(), "foo")
c.Validate(t, nil, err)
}
@ -255,7 +259,7 @@ func TestCreatePod(t *testing.T) {
Body: requestPod,
},
}
receivedPod, err := c.Setup().CreatePod(requestPod)
receivedPod, err := c.Setup().CreatePod(api.NewDefaultContext(), requestPod)
c.Validate(t, receivedPod, err)
}
@ -274,7 +278,7 @@ func TestUpdatePod(t *testing.T) {
Request: testRequest{Method: "PUT", Path: "/pods/foo"},
Response: Response{StatusCode: 200, Body: requestPod},
}
receivedPod, err := c.Setup().UpdatePod(requestPod)
receivedPod, err := c.Setup().UpdatePod(api.NewDefaultContext(), requestPod)
c.Validate(t, receivedPod, err)
}
@ -298,7 +302,7 @@ func TestListControllers(t *testing.T) {
},
},
}
receivedControllerList, err := c.Setup().ListReplicationControllers(labels.Everything())
receivedControllerList, err := c.Setup().ListReplicationControllers(api.NewContext(), labels.Everything())
c.Validate(t, receivedControllerList, err)
}
@ -320,7 +324,7 @@ func TestGetController(t *testing.T) {
},
},
}
receivedController, err := c.Setup().GetReplicationController("foo")
receivedController, err := c.Setup().GetReplicationController(api.NewDefaultContext(), "foo")
c.Validate(t, receivedController, err)
}
@ -344,7 +348,7 @@ func TestUpdateController(t *testing.T) {
},
},
}
receivedController, err := c.Setup().UpdateReplicationController(requestController)
receivedController, err := c.Setup().UpdateReplicationController(api.NewDefaultContext(), requestController)
c.Validate(t, receivedController, err)
}
@ -353,7 +357,7 @@ func TestDeleteController(t *testing.T) {
Request: testRequest{Method: "DELETE", Path: "/replicationControllers/foo"},
Response: Response{StatusCode: 200},
}
err := c.Setup().DeleteReplicationController("foo")
err := c.Setup().DeleteReplicationController(api.NewDefaultContext(), "foo")
c.Validate(t, nil, err)
}
@ -377,7 +381,7 @@ func TestCreateController(t *testing.T) {
},
},
}
receivedController, err := c.Setup().CreateReplicationController(requestController)
receivedController, err := c.Setup().CreateReplicationController(api.NewDefaultContext(), requestController)
c.Validate(t, receivedController, err)
}
@ -410,7 +414,7 @@ func TestListServices(t *testing.T) {
},
},
}
receivedServiceList, err := c.Setup().ListServices(labels.Everything())
receivedServiceList, err := c.Setup().ListServices(api.NewDefaultContext(), labels.Everything())
c.Validate(t, receivedServiceList, err)
}
@ -437,7 +441,7 @@ func TestListServicesLabels(t *testing.T) {
c.Setup()
c.QueryValidator["labels"] = validateLabels
selector := labels.Set{"foo": "bar", "name": "baz"}.AsSelector()
receivedServiceList, err := c.ListServices(selector)
receivedServiceList, err := c.ListServices(api.NewDefaultContext(), selector)
c.Validate(t, receivedServiceList, err)
}
@ -446,7 +450,7 @@ func TestGetService(t *testing.T) {
Request: testRequest{Method: "GET", Path: "/services/1"},
Response: Response{StatusCode: 200, Body: &api.Service{JSONBase: api.JSONBase{ID: "service-1"}}},
}
response, err := c.Setup().GetService("1")
response, err := c.Setup().GetService(api.NewDefaultContext(), "1")
c.Validate(t, response, err)
}
@ -455,7 +459,7 @@ func TestCreateService(t *testing.T) {
Request: testRequest{Method: "POST", Path: "/services", Body: &api.Service{JSONBase: api.JSONBase{ID: "service-1"}}},
Response: Response{StatusCode: 200, Body: &api.Service{JSONBase: api.JSONBase{ID: "service-1"}}},
}
response, err := c.Setup().CreateService(&api.Service{JSONBase: api.JSONBase{ID: "service-1"}})
response, err := c.Setup().CreateService(api.NewDefaultContext(), &api.Service{JSONBase: api.JSONBase{ID: "service-1"}})
c.Validate(t, response, err)
}
@ -465,7 +469,7 @@ func TestUpdateService(t *testing.T) {
Request: testRequest{Method: "PUT", Path: "/services/service-1", Body: svc},
Response: Response{StatusCode: 200, Body: svc},
}
response, err := c.Setup().UpdateService(svc)
response, err := c.Setup().UpdateService(api.NewDefaultContext(), svc)
c.Validate(t, response, err)
}
@ -474,7 +478,7 @@ func TestDeleteService(t *testing.T) {
Request: testRequest{Method: "DELETE", Path: "/services/1"},
Response: Response{StatusCode: 200},
}
err := c.Setup().DeleteService("1")
err := c.Setup().DeleteService(api.NewDefaultContext(), "1")
c.Validate(t, nil, err)
}
@ -492,7 +496,7 @@ func TestListEndpooints(t *testing.T) {
},
},
}
receivedEndpointsList, err := c.Setup().ListEndpoints(labels.Everything())
receivedEndpointsList, err := c.Setup().ListEndpoints(api.NewDefaultContext(), labels.Everything())
c.Validate(t, receivedEndpointsList, err)
}
@ -501,7 +505,7 @@ func TestGetEndpoints(t *testing.T) {
Request: testRequest{Method: "GET", Path: "/endpoints/endpoint-1"},
Response: Response{StatusCode: 200, Body: &api.Endpoints{JSONBase: api.JSONBase{ID: "endpoint-1"}}},
}
response, err := c.Setup().GetEndpoints("endpoint-1")
response, err := c.Setup().GetEndpoints(api.NewDefaultContext(), "endpoint-1")
c.Validate(t, response, err)
}

View File

@ -26,7 +26,8 @@ import (
// for a controller's ReplicaSelector equals the Replicas count.
func (c *Client) ControllerHasDesiredReplicas(controller api.ReplicationController) wait.ConditionFunc {
return func() (bool, error) {
pods, err := c.ListPods(labels.Set(controller.DesiredState.ReplicaSelector).AsSelector())
ctx := api.WithNamespace(api.NewContext(), controller.Namespace)
pods, err := c.ListPods(ctx, labels.Set(controller.DesiredState.ReplicaSelector).AsSelector())
if err != nil {
return false, err
}

View File

@ -42,102 +42,102 @@ type Fake struct {
Watch watch.Interface
}
func (c *Fake) ListPods(selector labels.Selector) (*api.PodList, error) {
func (c *Fake) ListPods(ctx api.Context, selector labels.Selector) (*api.PodList, error) {
c.Actions = append(c.Actions, FakeAction{Action: "list-pods"})
return api.Scheme.CopyOrDie(&c.Pods).(*api.PodList), nil
}
func (c *Fake) GetPod(name string) (*api.Pod, error) {
func (c *Fake) GetPod(ctx api.Context, name string) (*api.Pod, error) {
c.Actions = append(c.Actions, FakeAction{Action: "get-pod", Value: name})
return &api.Pod{}, nil
}
func (c *Fake) DeletePod(name string) error {
func (c *Fake) DeletePod(ctx api.Context, name string) error {
c.Actions = append(c.Actions, FakeAction{Action: "delete-pod", Value: name})
return nil
}
func (c *Fake) CreatePod(pod *api.Pod) (*api.Pod, error) {
func (c *Fake) CreatePod(ctx api.Context, pod *api.Pod) (*api.Pod, error) {
c.Actions = append(c.Actions, FakeAction{Action: "create-pod"})
return &api.Pod{}, nil
}
func (c *Fake) UpdatePod(pod *api.Pod) (*api.Pod, error) {
func (c *Fake) UpdatePod(ctx api.Context, pod *api.Pod) (*api.Pod, error) {
c.Actions = append(c.Actions, FakeAction{Action: "update-pod", Value: pod.ID})
return &api.Pod{}, nil
}
func (c *Fake) ListReplicationControllers(selector labels.Selector) (*api.ReplicationControllerList, error) {
func (c *Fake) ListReplicationControllers(ctx api.Context, selector labels.Selector) (*api.ReplicationControllerList, error) {
c.Actions = append(c.Actions, FakeAction{Action: "list-controllers"})
return &api.ReplicationControllerList{}, nil
}
func (c *Fake) GetReplicationController(name string) (*api.ReplicationController, error) {
func (c *Fake) GetReplicationController(ctx api.Context, name string) (*api.ReplicationController, error) {
c.Actions = append(c.Actions, FakeAction{Action: "get-controller", Value: name})
return api.Scheme.CopyOrDie(&c.Ctrl).(*api.ReplicationController), nil
}
func (c *Fake) CreateReplicationController(controller *api.ReplicationController) (*api.ReplicationController, error) {
func (c *Fake) CreateReplicationController(ctx api.Context, controller *api.ReplicationController) (*api.ReplicationController, error) {
c.Actions = append(c.Actions, FakeAction{Action: "create-controller", Value: controller})
return &api.ReplicationController{}, nil
}
func (c *Fake) UpdateReplicationController(controller *api.ReplicationController) (*api.ReplicationController, error) {
func (c *Fake) UpdateReplicationController(ctx api.Context, controller *api.ReplicationController) (*api.ReplicationController, error) {
c.Actions = append(c.Actions, FakeAction{Action: "update-controller", Value: controller})
return &api.ReplicationController{}, nil
}
func (c *Fake) DeleteReplicationController(controller string) error {
func (c *Fake) DeleteReplicationController(ctx api.Context, controller string) error {
c.Actions = append(c.Actions, FakeAction{Action: "delete-controller", Value: controller})
return nil
}
func (c *Fake) WatchReplicationControllers(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) {
func (c *Fake) WatchReplicationControllers(ctx api.Context, label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) {
c.Actions = append(c.Actions, FakeAction{Action: "watch-controllers", Value: resourceVersion})
return c.Watch, nil
}
func (c *Fake) ListServices(selector labels.Selector) (*api.ServiceList, error) {
func (c *Fake) ListServices(ctx api.Context, selector labels.Selector) (*api.ServiceList, error) {
c.Actions = append(c.Actions, FakeAction{Action: "list-services"})
return &c.ServiceList, c.Err
}
func (c *Fake) GetService(name string) (*api.Service, error) {
func (c *Fake) GetService(ctx api.Context, name string) (*api.Service, error) {
c.Actions = append(c.Actions, FakeAction{Action: "get-service", Value: name})
return &api.Service{}, nil
}
func (c *Fake) CreateService(service *api.Service) (*api.Service, error) {
func (c *Fake) CreateService(ctx api.Context, service *api.Service) (*api.Service, error) {
c.Actions = append(c.Actions, FakeAction{Action: "create-service", Value: service})
return &api.Service{}, nil
}
func (c *Fake) UpdateService(service *api.Service) (*api.Service, error) {
func (c *Fake) UpdateService(ctx api.Context, service *api.Service) (*api.Service, error) {
c.Actions = append(c.Actions, FakeAction{Action: "update-service", Value: service})
return &api.Service{}, nil
}
func (c *Fake) DeleteService(service string) error {
func (c *Fake) DeleteService(ctx api.Context, service string) error {
c.Actions = append(c.Actions, FakeAction{Action: "delete-service", Value: service})
return nil
}
func (c *Fake) WatchServices(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) {
func (c *Fake) WatchServices(ctx api.Context, label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) {
c.Actions = append(c.Actions, FakeAction{Action: "watch-services", Value: resourceVersion})
return c.Watch, c.Err
}
func (c *Fake) ListEndpoints(selector labels.Selector) (*api.EndpointsList, error) {
func (c *Fake) ListEndpoints(ctx api.Context, selector labels.Selector) (*api.EndpointsList, error) {
c.Actions = append(c.Actions, FakeAction{Action: "list-endpoints"})
return api.Scheme.CopyOrDie(&c.EndpointsList).(*api.EndpointsList), c.Err
}
func (c *Fake) GetEndpoints(name string) (*api.Endpoints, error) {
func (c *Fake) GetEndpoints(ctx api.Context, name string) (*api.Endpoints, error) {
c.Actions = append(c.Actions, FakeAction{Action: "get-endpoints"})
return &api.Endpoints{}, nil
}
func (c *Fake) WatchEndpoints(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) {
func (c *Fake) WatchEndpoints(ctx api.Context, label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) {
c.Actions = append(c.Actions, FakeAction{Action: "watch-endpoints", Value: resourceVersion})
return c.Watch, c.Err
}

View File

@ -20,10 +20,12 @@ package client
// and cobra pflags (Posix style).
type FlagSet interface {
StringVar(p *string, name, value, usage string)
BoolVar(p *bool, name string, value bool, usage string)
}
// BindClientConfigFlags registers a standard set of CLI flags for connecting to a Kubernetes API server.
func BindClientConfigFlags(flags FlagSet, config *Config) {
flags.StringVar(&config.Host, "master", config.Host, "The address of the Kubernetes API server")
flags.StringVar(&config.Version, "api_version", config.Version, "The API version to use when talking to the server")
flags.BoolVar(&config.Insecure, "insecure_skip_tls_verify", config.Insecure, "If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.")
}

View File

@ -23,7 +23,6 @@ import (
"path"
"strings"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
)
@ -55,10 +54,6 @@ type Config struct {
// Transport may be used for custom HTTP behavior. This attribute may not
// be specified with the TLS client certificate options.
Transport http.RoundTripper
// Context is the context that should be passed down to the server. If nil, the
// context will be set to the appropriate default.
Context api.Context
}
// New creates a Kubernetes client for the given config. This client works with pods,

View File

@ -42,9 +42,9 @@ type ReplicationManager struct {
// created as an interface to allow testing.
type PodControlInterface interface {
// createReplica creates new replicated pods according to the spec.
createReplica(controllerSpec api.ReplicationController)
createReplica(ctx api.Context, controllerSpec api.ReplicationController)
// deletePod deletes the pod identified by podID.
deletePod(podID string) error
deletePod(ctx api.Context, podID string) error
}
// RealPodControl is the default implementation of PodControllerInterface.
@ -52,7 +52,7 @@ type RealPodControl struct {
kubeClient client.Interface
}
func (r RealPodControl) createReplica(controllerSpec api.ReplicationController) {
func (r RealPodControl) createReplica(ctx api.Context, controllerSpec api.ReplicationController) {
labels := controllerSpec.DesiredState.PodTemplate.Labels
// TODO: don't fail to set this label just because the map isn't created.
if labels != nil {
@ -62,14 +62,14 @@ func (r RealPodControl) createReplica(controllerSpec api.ReplicationController)
DesiredState: controllerSpec.DesiredState.PodTemplate.DesiredState,
Labels: controllerSpec.DesiredState.PodTemplate.Labels,
}
_, err := r.kubeClient.CreatePod(pod)
_, err := r.kubeClient.CreatePod(ctx, pod)
if err != nil {
glog.Errorf("%#v\n", err)
}
}
func (r RealPodControl) deletePod(podID string) error {
return r.kubeClient.DeletePod(podID)
func (r RealPodControl) deletePod(ctx api.Context, podID string) error {
return r.kubeClient.DeletePod(ctx, podID)
}
// NewReplicationManager creates a new ReplicationManager.
@ -93,7 +93,9 @@ func (rm *ReplicationManager) Run(period time.Duration) {
// resourceVersion is a pointer to the resource version to use/update.
func (rm *ReplicationManager) watchControllers(resourceVersion *uint64) {
ctx := api.NewContext()
watching, err := rm.kubeClient.WatchReplicationControllers(
ctx,
labels.Everything(),
labels.Everything(),
*resourceVersion,
@ -143,7 +145,8 @@ func (rm *ReplicationManager) filterActivePods(pods []api.Pod) []api.Pod {
func (rm *ReplicationManager) syncReplicationController(controllerSpec api.ReplicationController) error {
s := labels.Set(controllerSpec.DesiredState.ReplicaSelector).AsSelector()
podList, err := rm.kubeClient.ListPods(s)
ctx := api.WithNamespace(api.NewContext(), controllerSpec.Namespace)
podList, err := rm.kubeClient.ListPods(ctx, s)
if err != nil {
return err
}
@ -157,7 +160,7 @@ func (rm *ReplicationManager) syncReplicationController(controllerSpec api.Repli
for i := 0; i < diff; i++ {
go func() {
defer wait.Done()
rm.podControl.createReplica(controllerSpec)
rm.podControl.createReplica(ctx, controllerSpec)
}()
}
wait.Wait()
@ -168,7 +171,7 @@ func (rm *ReplicationManager) syncReplicationController(controllerSpec api.Repli
for i := 0; i < diff; i++ {
go func(ix int) {
defer wait.Done()
rm.podControl.deletePod(filteredList[ix].ID)
rm.podControl.deletePod(ctx, filteredList[ix].ID)
}(i)
}
wait.Wait()
@ -180,7 +183,8 @@ func (rm *ReplicationManager) synchronize() {
// TODO: remove this method completely and rely on the watch.
// Add resource version tracking to watch to make this work.
var controllerSpecs []api.ReplicationController
list, err := rm.kubeClient.ListReplicationControllers(labels.Everything())
ctx := api.NewContext()
list, err := rm.kubeClient.ListReplicationControllers(ctx, labels.Everything())
if err != nil {
glog.Errorf("Synchronization error: %v (%#v)", err, err)
return

View File

@ -49,13 +49,13 @@ type FakePodControl struct {
lock sync.Mutex
}
func (f *FakePodControl) createReplica(spec api.ReplicationController) {
func (f *FakePodControl) createReplica(ctx api.Context, spec api.ReplicationController) {
f.lock.Lock()
defer f.lock.Unlock()
f.controllerSpec = append(f.controllerSpec, spec)
}
func (f *FakePodControl) deletePod(podID string) error {
func (f *FakePodControl) deletePod(ctx api.Context, podID string) error {
f.lock.Lock()
defer f.lock.Unlock()
f.deletePodID = append(f.deletePodID, podID)
@ -169,6 +169,7 @@ func TestSyncReplicationControllerCreates(t *testing.T) {
}
func TestCreateReplica(t *testing.T) {
ctx := api.NewDefaultContext()
body := runtime.EncodeOrDie(testapi.CodecForVersionOrDie(), &api.Pod{})
fakeHandler := util.FakeHandler{
StatusCode: 200,
@ -204,7 +205,7 @@ func TestCreateReplica(t *testing.T) {
},
}
podControl.createReplica(controllerSpec)
podControl.createReplica(ctx, controllerSpec)
expectedPod := api.Pod{
JSONBase: api.JSONBase{
@ -323,7 +324,7 @@ type FakeWatcher struct {
*client.Fake
}
func (fw FakeWatcher) WatchReplicationControllers(l, f labels.Selector, rv uint64) (watch.Interface, error) {
func (fw FakeWatcher) WatchReplicationControllers(ctx api.Context, l, f labels.Selector, rv uint64) (watch.Interface, error) {
return fw.w, nil
}

View File

@ -57,6 +57,7 @@ type AuthInfo struct {
CAFile string
CertFile string
KeyFile string
Insecure *bool
}
// LoadAuthInfo parses an AuthInfo object from a file path. It prompts user and creates file if it doesn't exist.
@ -91,15 +92,15 @@ func LoadAuthInfo(path string, r io.Reader) (*AuthInfo, error) {
// with the first container in the pod. There is no support yet for
// updating more complex replication controllers. If this is blank then no
// update of the image is performed.
func Update(name string, client client.Interface, updatePeriod time.Duration, imageName string) error {
controller, err := client.GetReplicationController(name)
func Update(ctx api.Context, name string, client client.Interface, updatePeriod time.Duration, imageName string) error {
controller, err := client.GetReplicationController(ctx, name)
if err != nil {
return err
}
if len(imageName) != 0 {
controller.DesiredState.PodTemplate.DesiredState.Manifest.Containers[0].Image = imageName
controller, err = client.UpdateReplicationController(controller)
controller, err = client.UpdateReplicationController(ctx, controller)
if err != nil {
return err
}
@ -107,7 +108,7 @@ func Update(name string, client client.Interface, updatePeriod time.Duration, im
s := labels.Set(controller.DesiredState.ReplicaSelector).AsSelector()
podList, err := client.ListPods(s)
podList, err := client.ListPods(ctx, s)
if err != nil {
return err
}
@ -118,14 +119,14 @@ func Update(name string, client client.Interface, updatePeriod time.Duration, im
for _, pod := range podList.Items {
// We delete the pod here, the controller will recreate it. This will result in pulling
// a new Docker image. This isn't a full "update" but it's what we support for now.
err = client.DeletePod(pod.ID)
err = client.DeletePod(ctx, pod.ID)
if err != nil {
return err
}
time.Sleep(updatePeriod)
}
return wait.Poll(time.Second*5, time.Second*300, func() (bool, error) {
podList, err := client.ListPods(s)
podList, err := client.ListPods(ctx, s)
if err != nil {
return false, err
}
@ -134,18 +135,18 @@ func Update(name string, client client.Interface, updatePeriod time.Duration, im
}
// StopController stops a controller named 'name' by setting replicas to zero.
func StopController(name string, client client.Interface) error {
return ResizeController(name, 0, client)
func StopController(ctx api.Context, name string, client client.Interface) error {
return ResizeController(ctx, name, 0, client)
}
// ResizeController resizes a controller named 'name' by setting replicas to 'replicas'.
func ResizeController(name string, replicas int, client client.Interface) error {
controller, err := client.GetReplicationController(name)
func ResizeController(ctx api.Context, name string, replicas int, client client.Interface) error {
controller, err := client.GetReplicationController(ctx, name)
if err != nil {
return err
}
controller.DesiredState.Replicas = replicas
controllerOut, err := client.UpdateReplicationController(controller)
controllerOut, err := client.UpdateReplicationController(ctx, controller)
if err != nil {
return err
}
@ -198,7 +199,7 @@ func portsFromString(spec string) []api.Port {
}
// RunController creates a new replication controller named 'name' which creates 'replicas' pods running 'image'.
func RunController(image, name string, replicas int, client client.Interface, portSpec string, servicePort int) error {
func RunController(ctx api.Context, image, name string, replicas int, client client.Interface, portSpec string, servicePort int) error {
if servicePort > 0 && !util.IsDNSLabel(name) {
return fmt.Errorf("Service creation requested, but an invalid name for a service was provided (%s). Service names must be valid DNS labels.", name)
}
@ -231,7 +232,7 @@ func RunController(image, name string, replicas int, client client.Interface, po
},
}
controllerOut, err := client.CreateReplicationController(controller)
controllerOut, err := client.CreateReplicationController(ctx, controller)
if err != nil {
return err
}
@ -242,7 +243,7 @@ func RunController(image, name string, replicas int, client client.Interface, po
fmt.Print(string(data))
if servicePort > 0 {
svc, err := createService(name, servicePort, client)
svc, err := createService(ctx, name, servicePort, client)
if err != nil {
return err
}
@ -255,7 +256,7 @@ func RunController(image, name string, replicas int, client client.Interface, po
return nil
}
func createService(name string, port int, client client.Interface) (*api.Service, error) {
func createService(ctx api.Context, name string, port int, client client.Interface) (*api.Service, error) {
svc := &api.Service{
JSONBase: api.JSONBase{ID: name},
Port: port,
@ -266,19 +267,19 @@ func createService(name string, port int, client client.Interface) (*api.Service
"simpleService": name,
},
}
svc, err := client.CreateService(svc)
svc, err := client.CreateService(ctx, svc)
return svc, err
}
// DeleteController deletes a replication controller named 'name', requires that the controller
// already be stopped.
func DeleteController(name string, client client.Interface) error {
controller, err := client.GetReplicationController(name)
func DeleteController(ctx api.Context, name string, client client.Interface) error {
controller, err := client.GetReplicationController(ctx, name)
if err != nil {
return err
}
if controller.DesiredState.Replicas != 0 {
return fmt.Errorf("controller has non-zero replicas (%d), please stop it first", controller.DesiredState.Replicas)
}
return client.DeleteReplicationController(name)
return client.DeleteReplicationController(ctx, name)
}

View File

@ -43,7 +43,7 @@ func TestUpdateWithPods(t *testing.T) {
},
},
}
Update("foo", &fakeClient, 0, "")
Update(api.NewDefaultContext(), "foo", &fakeClient, 0, "")
if len(fakeClient.Actions) != 5 {
t.Fatalf("Unexpected action list %#v", fakeClient.Actions)
}
@ -57,7 +57,7 @@ func TestUpdateWithPods(t *testing.T) {
func TestUpdateNoPods(t *testing.T) {
fakeClient := client.Fake{}
Update("foo", &fakeClient, 0, "")
Update(api.NewDefaultContext(), "foo", &fakeClient, 0, "")
if len(fakeClient.Actions) != 2 {
t.Errorf("Unexpected action list %#v", fakeClient.Actions)
}
@ -87,7 +87,7 @@ func TestUpdateWithNewImage(t *testing.T) {
},
},
}
Update("foo", &fakeClient, 0, "fooImage:2")
Update(api.NewDefaultContext(), "foo", &fakeClient, 0, "fooImage:2")
if len(fakeClient.Actions) != 6 {
t.Errorf("Unexpected action list %#v", fakeClient.Actions)
}
@ -109,7 +109,7 @@ func TestRunController(t *testing.T) {
name := "name"
image := "foo/bar"
replicas := 3
RunController(image, name, replicas, &fakeClient, "8080:80", -1)
RunController(api.NewDefaultContext(), image, name, replicas, &fakeClient, "8080:80", -1)
if len(fakeClient.Actions) != 1 || fakeClient.Actions[0].Action != "create-controller" {
t.Errorf("Unexpected actions: %#v", fakeClient.Actions)
}
@ -126,7 +126,7 @@ func TestRunControllerWithService(t *testing.T) {
name := "name"
image := "foo/bar"
replicas := 3
RunController(image, name, replicas, &fakeClient, "", 8000)
RunController(api.NewDefaultContext(), image, name, replicas, &fakeClient, "", 8000)
if len(fakeClient.Actions) != 2 ||
fakeClient.Actions[0].Action != "create-controller" ||
fakeClient.Actions[1].Action != "create-service" {
@ -143,7 +143,7 @@ func TestRunControllerWithService(t *testing.T) {
func TestStopController(t *testing.T) {
fakeClient := client.Fake{}
name := "name"
StopController(name, &fakeClient)
StopController(api.NewDefaultContext(), name, &fakeClient)
if len(fakeClient.Actions) != 2 {
t.Errorf("Unexpected actions: %#v", fakeClient.Actions)
}
@ -162,7 +162,7 @@ func TestResizeController(t *testing.T) {
fakeClient := client.Fake{}
name := "name"
replicas := 17
ResizeController(name, replicas, &fakeClient)
ResizeController(api.NewDefaultContext(), name, replicas, &fakeClient)
if len(fakeClient.Actions) != 2 {
t.Errorf("Unexpected actions: %#v", fakeClient.Actions)
}
@ -180,7 +180,7 @@ func TestResizeController(t *testing.T) {
func TestCloudCfgDeleteController(t *testing.T) {
fakeClient := client.Fake{}
name := "name"
err := DeleteController(name, &fakeClient)
err := DeleteController(api.NewDefaultContext(), name, &fakeClient)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
@ -206,7 +206,7 @@ func TestCloudCfgDeleteControllerWithReplicas(t *testing.T) {
},
}
name := "name"
err := DeleteController(name, &fakeClient)
err := DeleteController(api.NewDefaultContext(), name, &fakeClient)
if len(fakeClient.Actions) != 1 {
t.Errorf("Unexpected actions: %#v", fakeClient.Actions)
}

View File

@ -581,14 +581,14 @@ func TestMountExternalVolumes(t *testing.T) {
{
Name: "host-dir",
Source: &api.VolumeSource{
HostDirectory: &api.HostDirectory{"/dir/path"},
HostDir: &api.HostDir{"/dir/path"},
},
},
},
}
podVolumes, _ := kubelet.mountExternalVolumes(&manifest)
expectedPodVolumes := make(volumeMap)
expectedPodVolumes["host-dir"] = &volume.HostDirectory{"/dir/path"}
expectedPodVolumes["host-dir"] = &volume.HostDir{"/dir/path"}
if len(expectedPodVolumes) != len(podVolumes) {
t.Errorf("Unexpected volumes. Expected %#v got %#v. Manifest was: %#v", expectedPodVolumes, podVolumes, manifest)
}
@ -631,9 +631,9 @@ func TestMakeVolumesAndBinds(t *testing.T) {
}
podVolumes := volumeMap{
"disk": &volume.HostDirectory{"/mnt/disk"},
"disk4": &volume.HostDirectory{"/mnt/host"},
"disk5": &volume.EmptyDirectory{"disk5", "podID", "/var/lib/kubelet"},
"disk": &volume.HostDir{"/mnt/disk"},
"disk4": &volume.HostDir{"/mnt/host"},
"disk5": &volume.EmptyDir{"disk5", "podID", "/var/lib/kubelet"},
}
binds := makeBinds(&pod, &container, podVolumes)

View File

@ -29,10 +29,10 @@ import (
// Watcher is the interface needed to receive changes to services and endpoints.
type Watcher interface {
ListServices(label labels.Selector) (*api.ServiceList, error)
ListEndpoints(label labels.Selector) (*api.EndpointsList, error)
WatchServices(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error)
WatchEndpoints(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error)
ListServices(ctx api.Context, label labels.Selector) (*api.ServiceList, error)
ListEndpoints(ctx api.Context, label labels.Selector) (*api.EndpointsList, error)
WatchServices(ctx api.Context, label, field labels.Selector, resourceVersion uint64) (watch.Interface, error)
WatchEndpoints(ctx api.Context, label, field labels.Selector, resourceVersion uint64) (watch.Interface, error)
}
// SourceAPI implements a configuration source for services and endpoints that
@ -72,8 +72,9 @@ func NewSourceAPI(client Watcher, period time.Duration, services chan<- ServiceU
// runServices loops forever looking for changes to services.
func (s *SourceAPI) runServices(resourceVersion *uint64) {
ctx := api.NewContext()
if *resourceVersion == 0 {
services, err := s.client.ListServices(labels.Everything())
services, err := s.client.ListServices(ctx, labels.Everything())
if err != nil {
glog.Errorf("Unable to load services: %v", err)
time.Sleep(wait.Jitter(s.waitDuration, 0.0))
@ -83,7 +84,7 @@ func (s *SourceAPI) runServices(resourceVersion *uint64) {
s.services <- ServiceUpdate{Op: SET, Services: services.Items}
}
watcher, err := s.client.WatchServices(labels.Everything(), labels.Everything(), *resourceVersion)
watcher, err := s.client.WatchServices(ctx, labels.Everything(), labels.Everything(), *resourceVersion)
if err != nil {
glog.Errorf("Unable to watch for services changes: %v", err)
time.Sleep(wait.Jitter(s.waitDuration, 0.0))
@ -121,8 +122,9 @@ func handleServicesWatch(resourceVersion *uint64, ch <-chan watch.Event, updates
// runEndpoints loops forever looking for changes to endpoints.
func (s *SourceAPI) runEndpoints(resourceVersion *uint64) {
ctx := api.NewContext()
if *resourceVersion == 0 {
endpoints, err := s.client.ListEndpoints(labels.Everything())
endpoints, err := s.client.ListEndpoints(ctx, labels.Everything())
if err != nil {
glog.Errorf("Unable to load endpoints: %v", err)
time.Sleep(wait.Jitter(s.waitDuration, 0.0))
@ -132,7 +134,7 @@ func (s *SourceAPI) runEndpoints(resourceVersion *uint64) {
s.endpoints <- EndpointsUpdate{Op: SET, Endpoints: endpoints.Items}
}
watcher, err := s.client.WatchEndpoints(labels.Everything(), labels.Everything(), *resourceVersion)
watcher, err := s.client.WatchEndpoints(ctx, labels.Everything(), labels.Everything(), *resourceVersion)
if err != nil {
glog.Errorf("Unable to watch for endpoints changes: %v", err)
time.Sleep(wait.Jitter(s.waitDuration, 0.0))

View File

@ -47,14 +47,16 @@ func NewEndpointController(serviceRegistry service.Registry, client *client.Clie
// SyncServiceEndpoints syncs service endpoints.
func (e *EndpointController) SyncServiceEndpoints() error {
services, err := e.client.ListServices(labels.Everything())
ctx := api.NewContext()
services, err := e.client.ListServices(ctx, labels.Everything())
if err != nil {
glog.Errorf("Failed to list services: %v", err)
return err
}
var resultErr error
for _, service := range services.Items {
pods, err := e.client.ListPods(labels.Set(service.Selector).AsSelector())
nsCtx := api.WithNamespace(ctx, service.Namespace)
pods, err := e.client.ListPods(nsCtx, labels.Set(service.Selector).AsSelector())
if err != nil {
glog.Errorf("Error syncing service: %#v, skipping.", service)
resultErr = err
@ -73,7 +75,7 @@ func (e *EndpointController) SyncServiceEndpoints() error {
}
endpoints[ix] = net.JoinHostPort(pod.CurrentState.PodIP, strconv.Itoa(port))
}
currentEndpoints, err := e.client.GetEndpoints(service.ID)
currentEndpoints, err := e.client.GetEndpoints(nsCtx, service.ID)
if err != nil {
// TODO this is brittle as all get out, refactor the client libraries to return a structured error.
if strings.Contains(err.Error(), "(404)") {
@ -93,14 +95,14 @@ func (e *EndpointController) SyncServiceEndpoints() error {
if currentEndpoints.ResourceVersion == 0 {
// No previous endpoints, create them
_, err = e.client.CreateEndpoints(newEndpoints)
_, err = e.client.CreateEndpoints(nsCtx, newEndpoints)
} else {
// Pre-existing
if endpointsEqual(currentEndpoints, endpoints) {
glog.V(2).Infof("endpoints are equal for %s, skipping update", service.ID)
continue
}
_, err = e.client.UpdateEndpoints(newEndpoints)
_, err = e.client.UpdateEndpoints(nsCtx, newEndpoints)
}
if err != nil {
glog.Errorf("Error updating endpoints: %#v", err)

View File

@ -49,32 +49,32 @@ type Cleaner interface {
TearDown() error
}
// HostDirectory volumes represent a bare host directory mount.
// HostDir volumes represent a bare host directory mount.
// The directory in Path will be directly exposed to the container.
type HostDirectory struct {
type HostDir struct {
Path string
}
// SetUp implements interface definitions, even though host directory
// mounts don't require any setup or cleanup.
func (hostVol *HostDirectory) SetUp() error {
func (hostVol *HostDir) SetUp() error {
return nil
}
func (hostVol *HostDirectory) GetPath() string {
func (hostVol *HostDir) GetPath() string {
return hostVol.Path
}
// EmptyDirectory volumes are temporary directories exposed to the pod.
// EmptyDir volumes are temporary directories exposed to the pod.
// These do not persist beyond the lifetime of a pod.
type EmptyDirectory struct {
type EmptyDir struct {
Name string
PodID string
RootDir string
}
// SetUp creates new directory.
func (emptyDir *EmptyDirectory) SetUp() error {
func (emptyDir *EmptyDir) SetUp() error {
path := emptyDir.GetPath()
err := os.MkdirAll(path, 0750)
if err != nil {
@ -83,11 +83,11 @@ func (emptyDir *EmptyDirectory) SetUp() error {
return nil
}
func (emptyDir *EmptyDirectory) GetPath() string {
func (emptyDir *EmptyDir) GetPath() string {
return path.Join(emptyDir.RootDir, emptyDir.PodID, "volumes", "empty", emptyDir.Name)
}
func (emptyDir *EmptyDirectory) renameDirectory() (string, error) {
func (emptyDir *EmptyDir) renameDirectory() (string, error) {
oldPath := emptyDir.GetPath()
newPath, err := ioutil.TempDir(path.Dir(oldPath), emptyDir.Name+".deleting~")
if err != nil {
@ -101,7 +101,7 @@ func (emptyDir *EmptyDirectory) renameDirectory() (string, error) {
}
// TearDown simply deletes everything in the directory.
func (emptyDir *EmptyDirectory) TearDown() error {
func (emptyDir *EmptyDir) TearDown() error {
tmpDir, err := emptyDir.renameDirectory()
if err != nil {
return err
@ -113,14 +113,14 @@ func (emptyDir *EmptyDirectory) TearDown() error {
return nil
}
// createHostDirectory interprets API volume as a HostDirectory.
func createHostDirectory(volume *api.Volume) *HostDirectory {
return &HostDirectory{volume.Source.HostDirectory.Path}
// createHostDir interprets API volume as a HostDir.
func createHostDir(volume *api.Volume) *HostDir {
return &HostDir{volume.Source.HostDir.Path}
}
// createEmptyDirectory interprets API volume as an EmptyDirectory.
func createEmptyDirectory(volume *api.Volume, podID string, rootDir string) *EmptyDirectory {
return &EmptyDirectory{volume.Name, podID, rootDir}
// createEmptyDir interprets API volume as an EmptyDir.
func createEmptyDir(volume *api.Volume, podID string, rootDir string) *EmptyDir {
return &EmptyDir{volume.Name, podID, rootDir}
}
// CreateVolumeBuilder returns a Builder capable of mounting a volume described by an
@ -135,10 +135,10 @@ func CreateVolumeBuilder(volume *api.Volume, podID string, rootDir string) (Buil
var vol Builder
// TODO(jonesdl) We should probably not check every pointer and directly
// resolve these types instead.
if source.HostDirectory != nil {
vol = createHostDirectory(volume)
} else if source.EmptyDirectory != nil {
vol = createEmptyDirectory(volume, podID, rootDir)
if source.HostDir != nil {
vol = createHostDir(volume)
} else if source.EmptyDir != nil {
vol = createEmptyDir(volume, podID, rootDir)
} else {
return nil, ErrUnsupportedVolumeType
}
@ -149,7 +149,7 @@ func CreateVolumeBuilder(volume *api.Volume, podID string, rootDir string) (Buil
func CreateVolumeCleaner(kind string, name string, podID string, rootDir string) (Cleaner, error) {
switch kind {
case "empty":
return &EmptyDirectory{name, podID, rootDir}, nil
return &EmptyDir{name, podID, rootDir}, nil
default:
return nil, ErrUnsupportedVolumeType
}

View File

@ -41,7 +41,7 @@ func TestCreateVolumeBuilders(t *testing.T) {
api.Volume{
Name: "host-dir",
Source: &api.VolumeSource{
HostDirectory: &api.HostDirectory{"/dir/path"},
HostDir: &api.HostDir{"/dir/path"},
},
},
"/dir/path",
@ -52,7 +52,7 @@ func TestCreateVolumeBuilders(t *testing.T) {
api.Volume{
Name: "empty-dir",
Source: &api.VolumeSource{
EmptyDirectory: &api.EmptyDirectory{},
EmptyDir: &api.EmptyDir{},
},
},
path.Join(tempDir, "/my-id/volumes/empty/empty-dir"),
@ -79,7 +79,7 @@ func TestCreateVolumeBuilders(t *testing.T) {
}
continue
}
if tt.volume.Source.HostDirectory == nil && tt.volume.Source.EmptyDirectory == nil {
if tt.volume.Source.HostDir == nil && tt.volume.Source.EmptyDir == nil {
if err != ErrUnsupportedVolumeType {
t.Errorf("Unexpected error: %v", err)
}

View File

@ -59,6 +59,7 @@ func TestClient(t *testing.T) {
}
for apiVersion, values := range testCases {
ctx := api.NewDefaultContext()
deleteAllEtcdKeys()
s := httptest.NewServer(apiserver.Handle(values.Storage, values.Codec, fmt.Sprintf("/api/%s/", apiVersion), values.selfLinker))
client := client.NewOrDie(&client.Config{Host: s.URL, Version: apiVersion})
@ -71,7 +72,7 @@ func TestClient(t *testing.T) {
t.Errorf("expected %#v, got %#v", e, a)
}
pods, err := client.ListPods(labels.Everything())
pods, err := client.ListPods(ctx, labels.Everything())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
@ -92,14 +93,14 @@ func TestClient(t *testing.T) {
},
},
}
got, err := client.CreatePod(pod)
got, err := client.CreatePod(ctx, pod)
if err == nil {
t.Fatalf("unexpected non-error: %v", err)
}
// get a created pod
pod.DesiredState.Manifest.Containers[0].Image = "an-image"
got, err = client.CreatePod(pod)
got, err = client.CreatePod(ctx, pod)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
@ -108,7 +109,7 @@ func TestClient(t *testing.T) {
}
// pod is shown, but not scheduled
pods, err = client.ListPods(labels.Everything())
pods, err = client.ListPods(ctx, labels.Everything())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}