// DeleteController deletes a replication controller named 'name', requires that the controller // already be stopped. func DeleteController(ctx api.Context, name string, client client.Interface) error { // TODO remove ctx in favor of just namespace string controller, err := client.ReplicationControllers(api.Namespace(ctx)).Get(name) if err != nil { return err } if controller.Spec.Replicas != 0 { return fmt.Errorf("controller has non-zero replicas (%d), please stop it first", controller.Spec.Replicas) } return client.ReplicationControllers(api.Namespace(ctx)).Delete(name) }
// TestValidNamespace validates that namespace rules are enforced on a resource prior to create or update func TestValidNamespace(t *testing.T) { ctx := api.NewDefaultContext() namespace, _ := api.NamespaceFrom(ctx) resource := api.ReplicationController{} if !api.ValidNamespace(ctx, &resource.ObjectMeta) { t.Errorf("expected success") } if namespace != resource.Namespace { t.Errorf("expected resource to have the default namespace assigned during validation") } resource = api.ReplicationController{ObjectMeta: api.ObjectMeta{Namespace: "other"}} if api.ValidNamespace(ctx, &resource.ObjectMeta) { t.Errorf("Expected error that resource and context errors do not match because resource has different namespace") } ctx = api.NewContext() if api.ValidNamespace(ctx, &resource.ObjectMeta) { t.Errorf("Expected error that resource and context errors do not match since context has no namespace") } ctx = api.NewContext() ns := api.Namespace(ctx) if ns != "" { t.Errorf("Expected the empty string") } }
// RunController creates a new replication controller named 'name' which creates 'replicas' pods running 'image'. func RunController(ctx api.Context, image, name string, replicas int, client client.Interface, portSpec string, servicePort int) error { // TODO replace ctx with a namespace string 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) } ports, err := portsFromString(portSpec) if err != nil { return err } controller := &api.ReplicationController{ ObjectMeta: api.ObjectMeta{ Name: name, }, Spec: api.ReplicationControllerSpec{ Replicas: replicas, Selector: map[string]string{ "name": name, }, Template: &api.PodTemplateSpec{ ObjectMeta: api.ObjectMeta{ Labels: map[string]string{ "name": name, }, }, Spec: api.PodSpec{ Containers: []api.Container{ { Name: strings.ToLower(name), Image: image, Ports: ports, }, }, }, }, }, } controllerOut, err := client.ReplicationControllers(api.Namespace(ctx)).Create(controller) if err != nil { return err } data, err := yaml.Marshal(controllerOut) if err != nil { return err } fmt.Print(string(data)) if servicePort > 0 { svc, err := createService(ctx, name, servicePort, client) if err != nil { return err } data, err = yaml.Marshal(svc) if err != nil { return err } fmt.Printf(string(data)) } return nil }
// ResizeController resizes a controller named 'name' by setting replicas to 'replicas'. func ResizeController(ctx api.Context, name string, replicas int, client client.Interface) error { // TODO ctx is not needed, and should just be a namespace controller, err := client.ReplicationControllers(api.Namespace(ctx)).Get(name) if err != nil { return err } controller.Spec.Replicas = replicas controllerOut, err := client.ReplicationControllers(api.Namespace(ctx)).Update(controller) if err != nil { return err } data, err := yaml.Marshal(controllerOut) if err != nil { return err } fmt.Print(string(data)) return nil }
// 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. // 'imageName' is the new image to update for the template. This will work // 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(ctx api.Context, name string, client client.Interface, updatePeriod time.Duration, imageName string) error { // TODO ctx is not needed as input to this function, should just be 'namespace' controller, err := client.ReplicationControllers(api.Namespace(ctx)).Get(name) if err != nil { return err } if len(imageName) != 0 { controller.Spec.Template.Spec.Containers[0].Image = imageName controller, err = client.ReplicationControllers(controller.Namespace).Update(controller) if err != nil { return err } } s := labels.Set(controller.Spec.Selector).AsSelector() podList, err := client.Pods(api.Namespace(ctx)).List(s) if err != nil { return err } expected := len(podList.Items) if expected == 0 { return nil } 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.Pods(pod.Namespace).Delete(pod.Name) if err != nil { return err } time.Sleep(updatePeriod) } return wait.Poll(time.Second*5, time.Second*300, func() (bool, error) { podList, err := client.Pods(api.Namespace(ctx)).List(s) if err != nil { return false, err } return len(podList.Items) == expected, nil }) }
// Implement ResourceWatcher. func (storage *SimpleRESTStorage) Watch(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) { storage.requestedLabelSelector = label storage.requestedFieldSelector = field storage.requestedResourceVersion = resourceVersion storage.requestedResourceNamespace = api.Namespace(ctx) if err := storage.errors["watch"]; err != nil { return nil, err } storage.fakeWatch = watch.NewFake() return storage.fakeWatch, nil }
// Implement Redirector. func (storage *SimpleRESTStorage) ResourceLocation(ctx api.Context, id string) (string, error) { // validate that the namespace context on the request matches the expected input storage.requestedResourceNamespace = api.Namespace(ctx) if storage.expectedResourceNamespace != storage.requestedResourceNamespace { return "", fmt.Errorf("Expected request namespace %s, but got namespace %s", storage.expectedResourceNamespace, storage.requestedResourceNamespace) } storage.requestedResourceLocationID = id if err := storage.errors["resourceLocation"]; err != nil { return "", err } return storage.resourceLocation, nil }
func TestRESTCreate(t *testing.T) { table := []struct { ctx api.Context event *api.Event valid bool }{ { ctx: api.NewDefaultContext(), event: testEvent("foo"), valid: true, }, { ctx: api.NewContext(), event: testEvent("bar"), valid: true, }, { ctx: api.WithNamespace(api.NewContext(), "nondefault"), event: testEvent("bazzzz"), valid: false, }, } for _, item := range table { _, rest := NewTestREST() c, err := rest.Create(item.ctx, item.event) if !item.valid { if err == nil { ctxNS := api.Namespace(item.ctx) t.Errorf("unexpected non-error for %v (%v, %v)", item.event.Name, ctxNS, item.event.Namespace) } continue } if err != nil { t.Errorf("%v: Unexpected error %v", item.event.Name, err) continue } if !api.HasObjectMetaSystemFieldValues(&item.event.ObjectMeta) { t.Errorf("storage did not populate object meta field values") } if e, a := item.event, (<-c).Object; !reflect.DeepEqual(e, a) { t.Errorf("diff: %s", util.ObjectDiff(e, a)) } // Ensure we implement the interface _ = apiserver.ResourceWatcher(rest) } }
func createService(ctx api.Context, name string, port int, client client.Interface) (*api.Service, error) { // TODO remove context in favor of just namespace string svc := &api.Service{ ObjectMeta: api.ObjectMeta{ Name: name, Labels: map[string]string{ "name": name, }, }, Spec: api.ServiceSpec{ Port: port, Selector: map[string]string{ "name": name, }, }, } svc, err := client.Services(api.Namespace(ctx)).Create(svc) return svc, err }
func (rs *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) { event, ok := obj.(*api.Event) if !ok { return nil, fmt.Errorf("invalid object type") } if api.Namespace(ctx) != "" { if !api.ValidNamespace(ctx, &event.ObjectMeta) { return nil, errors.NewConflict("event", event.Namespace, fmt.Errorf("event.namespace does not match the provided context")) } } if errs := validation.ValidateEvent(event); len(errs) > 0 { return nil, errors.NewInvalid("event", event.Name, errs) } api.FillObjectMetaSystemFields(ctx, &event.ObjectMeta) return apiserver.MakeAsync(func() (runtime.Object, error) { err := rs.registry.Create(ctx, event.Name, event) if err != nil { return nil, err } return rs.registry.Get(ctx, event.Name) }), nil }
func executeAPIRequest(ctx api.Context, method string, c *client.Client) bool { storage, path, hasSuffix := storagePathFromArg(flag.Arg(1)) validStorage := checkStorage(storage) verb := "" setBody := false var version string printer := getPrinter() switch method { case "get": verb = "GET" if !validStorage || !hasSuffix { glog.Fatalf("usage: kubecfg [OPTIONS] %s <%s>[/<id>]", method, prettyWireStorage()) } case "list": verb = "GET" if !validStorage || hasSuffix { glog.Fatalf("usage: kubecfg [OPTIONS] %s <%s>", method, prettyWireStorage()) } case "delete": verb = "DELETE" if !validStorage || !hasSuffix { glog.Fatalf("usage: kubecfg [OPTIONS] %s <%s>/<id>", method, prettyWireStorage()) } case "create": verb = "POST" setBody = true if !validStorage || hasSuffix { glog.Fatalf("usage: kubecfg [OPTIONS] %s <%s>", method, prettyWireStorage()) } case "update": obj, err := c.Verb("GET").Namespace(api.Namespace(ctx)).Suffix(path).Do().Get() if err != nil { glog.Fatalf("error obtaining resource version for update: %v", err) } meta, err := meta.Accessor(obj) if err != nil { glog.Fatalf("error finding json base for update: %v", err) } version = meta.ResourceVersion() verb = "PUT" setBody = true if !validStorage || !hasSuffix { glog.Fatalf("usage: kubecfg [OPTIONS] %s <%s>/<id>", method, prettyWireStorage()) } case "print": data := readConfig(storage, c) obj, err := latest.Codec.Decode(data) if err != nil { glog.Fatalf("error setting resource version: %v", err) } printer.PrintObj(obj, os.Stdout) return true default: return false } r := c.Verb(verb).Namespace(api.Namespace(ctx)).Suffix(path) if len(*selector) > 0 { r.ParseSelectorParam("labels", *selector) } if len(*fieldSelector) > 0 { r.ParseSelectorParam("fields", *fieldSelector) } if setBody { if len(version) > 0 { data := readConfig(storage, c) obj, err := latest.Codec.Decode(data) if err != nil { glog.Fatalf("error setting resource version: %v", err) } jsonBase, err := meta.Accessor(obj) if err != nil { glog.Fatalf("error setting resource version: %v", err) } jsonBase.SetResourceVersion(version) data, err = c.RESTClient.Codec.Encode(obj) if err != nil { glog.Fatalf("error setting resource version: %v", err) } r.Body(data) } else { r.Body(readConfig(storage, c)) } } result := r.Do() obj, err := result.Get() if err != nil { glog.Fatalf("Got request error: %v\n", err) return false } if err = printer.PrintObj(obj, os.Stdout); err != nil { body, _ := result.Raw() glog.Fatalf("Failed to print: %v\nRaw received object:\n%#v\n\nBody received: %v", err, obj, string(body)) } fmt.Print("\n") return true }
// Bind just does a POST binding RPC. func (b *binder) Bind(binding *api.Binding) error { glog.V(2).Infof("Attempting to bind %v to %v", binding.PodID, binding.Host) ctx := api.WithNamespace(api.NewContext(), binding.Namespace) return b.Post().Namespace(api.Namespace(ctx)).Resource("bindings").Body(binding).Do().Error() }
// UpdatePodStatus PUT pod RPC func (s *status) UpdatePodStatus(pod *api.Pod) error { glog.V(2).Infof("Attempting to update pod (%s) status to %s", pod.Name, pod.Status.Phase) ctx := api.WithNamespace(api.NewContext(), pod.Namespace) return s.Put().Namespace(api.Namespace(ctx)).Path("pods").Path(pod.Name).Body(pod).Do().Error() }