Skip to content

Commit

Permalink
Merge pull request kubernetes#4779 from smarterclayton/status_endpoints
Browse files Browse the repository at this point in the history
Minimal status mutation change
  • Loading branch information
bgrant0607 committed Mar 3, 2015
2 parents fbfbc7e + 3d29008 commit fca9fd6
Show file tree
Hide file tree
Showing 7 changed files with 202 additions and 67 deletions.
17 changes: 17 additions & 0 deletions pkg/api/validation/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,23 @@ func ValidatePodUpdate(newPod, oldPod *api.Pod) errs.ValidationErrorList {
return allErrs
}

// ValidatePodStatusUpdate tests to see if the update is legal for an end user to make. newPod is updated with fields
// that cannot be changed.
func ValidatePodStatusUpdate(newPod, oldPod *api.Pod) errs.ValidationErrorList {
allErrs := errs.ValidationErrorList{}

allErrs = append(allErrs, ValidateObjectMetaUpdate(&oldPod.ObjectMeta, &newPod.ObjectMeta).Prefix("metadata")...)

// TODO: allow change when bindings are properly decoupled from pods
if newPod.Status.Host != oldPod.Status.Host {
allErrs = append(allErrs, errs.NewFieldInvalid("status.host", newPod.Status.Host, "pod host cannot be changed directly"))
}

newPod.Spec = oldPod.Spec

return allErrs
}

var supportedSessionAffinityType = util.NewStringSet(string(api.AffinityTypeClientIP), string(api.AffinityTypeNone))

// ValidateService tests if required fields in the service are set.
Expand Down
42 changes: 30 additions & 12 deletions pkg/apiserver/api_installer.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,16 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage RESTStorage
codec := a.group.codec
admit := a.group.admit
context := a.group.context
resource := path

var resource, subresource string
switch parts := strings.Split(path, "/"); len(parts) {
case 2:
resource, subresource = parts[0], parts[1]
case 1:
resource = parts[0]
default:
return fmt.Errorf("api_installer allows only one or two segment paths (resource or resource/subresource)")
}

object := storage.New()
// TODO: add scheme to APIInstaller rather than using api.Scheme
Expand Down Expand Up @@ -143,14 +152,17 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage RESTStorage

// Get the list of actions for the given scope.
if scope.Name() != meta.RESTScopeNameNamespace {
itemPath := path + "/{name}"
itemPath := resource + "/{name}"
if len(subresource) > 0 {
itemPath = itemPath + "/" + subresource
}
nameParams := append(params, nameParam)
namer := rootScopeNaming{scope, a.group.linker, gpath.Join(a.prefix, itemPath)}

// Handler for standard REST verbs (GET, PUT, POST and DELETE).
actions = appendIf(actions, action{"LIST", path, params, namer}, isLister)
actions = appendIf(actions, action{"POST", path, params, namer}, isCreater)
actions = appendIf(actions, action{"WATCHLIST", "/watch/" + path, params, namer}, allowWatchList)
actions = appendIf(actions, action{"LIST", resource, params, namer}, isLister)
actions = appendIf(actions, action{"POST", resource, params, namer}, isCreater)
actions = appendIf(actions, action{"WATCHLIST", "/watch/" + resource, params, namer}, allowWatchList)

actions = appendIf(actions, action{"GET", itemPath, nameParams, namer}, isGetter)
actions = appendIf(actions, action{"PUT", itemPath, nameParams, namer}, isUpdater)
Expand All @@ -165,10 +177,13 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage RESTStorage
if scope.ParamPath() {
// Handler for standard REST verbs (GET, PUT, POST and DELETE).
namespaceParam := ws.PathParameter(scope.ParamName(), scope.ParamDescription()).DataType("string")
namespacedPath := scope.ParamName() + "/{" + scope.ParamName() + "}/" + path
namespacedPath := scope.ParamName() + "/{" + scope.ParamName() + "}/" + resource
namespaceParams := []*restful.Parameter{namespaceParam}

itemPath := namespacedPath + "/{name}"
if len(subresource) > 0 {
itemPath = itemPath + "/" + subresource
}
nameParams := append(namespaceParams, nameParam)
namer := scopeNaming{scope, a.group.linker, gpath.Join(a.prefix, itemPath), false}

Expand All @@ -186,22 +201,25 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage RESTStorage

// list across namespace.
namer = scopeNaming{scope, a.group.linker, gpath.Join(a.prefix, itemPath), true}
actions = appendIf(actions, action{"LIST", path, params, namer}, isLister)
actions = appendIf(actions, action{"WATCHLIST", "/watch/" + path, params, namer}, allowWatchList)
actions = appendIf(actions, action{"LIST", resource, params, namer}, isLister)
actions = appendIf(actions, action{"WATCHLIST", "/watch/" + resource, params, namer}, allowWatchList)

} else {
// Handler for standard REST verbs (GET, PUT, POST and DELETE).
// v1beta1/v1beta2 format where namespace was a query parameter
namespaceParam := ws.QueryParameter(scope.ParamName(), scope.ParamDescription()).DataType("string")
namespaceParams := []*restful.Parameter{namespaceParam}

itemPath := path + "/{name}"
itemPath := resource + "/{name}"
if len(subresource) > 0 {
itemPath = itemPath + "/" + subresource
}
nameParams := append(namespaceParams, nameParam)
namer := legacyScopeNaming{scope, a.group.linker, gpath.Join(a.prefix, itemPath)}

actions = appendIf(actions, action{"LIST", path, namespaceParams, namer}, isLister)
actions = appendIf(actions, action{"POST", path, namespaceParams, namer}, isCreater)
actions = appendIf(actions, action{"WATCHLIST", "/watch/" + path, namespaceParams, namer}, allowWatchList)
actions = appendIf(actions, action{"LIST", resource, namespaceParams, namer}, isLister)
actions = appendIf(actions, action{"POST", resource, namespaceParams, namer}, isCreater)
actions = appendIf(actions, action{"WATCHLIST", "/watch/" + resource, namespaceParams, namer}, allowWatchList)

actions = appendIf(actions, action{"GET", itemPath, nameParams, namer}, isGetter)
actions = appendIf(actions, action{"PUT", itemPath, nameParams, namer}, isUpdater)
Expand Down
7 changes: 4 additions & 3 deletions pkg/master/master.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ func logStackOnRecover(panicReason interface{}, httpWriter http.ResponseWriter)
func (m *Master) init(c *Config) {

boundPodFactory := &pod.BasicBoundPodFactory{}
podStorage, bindingStorage := podetcd.NewREST(c.EtcdHelper, boundPodFactory)
podStorage, bindingStorage, podStatusStorage := podetcd.NewREST(c.EtcdHelper, boundPodFactory)
podRegistry := pod.NewRegistry(podStorage)

eventRegistry := event.NewEtcdRegistry(c.EtcdHelper, uint64(c.EventTTL.Seconds()))
Expand Down Expand Up @@ -406,8 +406,9 @@ func (m *Master) init(c *Config) {

// TODO: Factor out the core API registration
m.storage = map[string]apiserver.RESTStorage{
"pods": podStorage,
"bindings": bindingStorage,
"pods": podStorage,
"pods/status": podStatusStorage,
"bindings": bindingStorage,

"replicationControllers": controller.NewREST(registry, podRegistry),
"services": service.NewREST(m.serviceRegistry, c.Cloud, m.nodeRegistry, m.portalNet, c.ClusterName),
Expand Down
2 changes: 1 addition & 1 deletion pkg/registry/etcd/etcd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func NewTestEtcdRegistry(client tools.EtcdClient) *Registry {

func NewTestEtcdRegistryWithPods(client tools.EtcdClient) *Registry {
helper := tools.EtcdHelper{client, latest.Codec, tools.RuntimeVersionAdapter{latest.ResourceVersioner}}
podStorage, _ := podetcd.NewREST(helper, nil)
podStorage, _, _ := podetcd.NewREST(helper, nil)
registry := NewRegistry(helper, pod.NewRegistry(podStorage))
return registry
}
Expand Down
36 changes: 26 additions & 10 deletions pkg/registry/pod/etcd/etcd.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,8 @@ type REST struct {
}

// NewREST returns a RESTStorage object that will work against pods.
func NewREST(h tools.EtcdHelper, factory pod.BoundPodFactory) (*REST, *BindingREST) {
func NewREST(h tools.EtcdHelper, factory pod.BoundPodFactory) (*REST, *BindingREST, *StatusREST) {
prefix := "/registry/pods"
bindings := &podLifecycle{h}
store := &etcdgeneric.Etcd{
NewFunc: func() runtime.Object { return &api.Pod{} },
NewListFunc: func() runtime.Object { return &api.PodList{} },
Expand All @@ -56,17 +55,20 @@ func NewREST(h tools.EtcdHelper, factory pod.BoundPodFactory) (*REST, *BindingRE
},
EndpointName: "pods",

CreateStrategy: pod.Strategy,
Helper: h,
}
statusStore := *store

UpdateStrategy: pod.Strategy,
AfterUpdate: bindings.AfterUpdate,
bindings := &podLifecycle{h}
store.CreateStrategy = pod.Strategy
store.UpdateStrategy = pod.Strategy
store.AfterUpdate = bindings.AfterUpdate
store.ReturnDeletedObject = true
store.AfterDelete = bindings.AfterDelete

ReturnDeletedObject: true,
AfterDelete: bindings.AfterDelete,
statusStore.UpdateStrategy = pod.StatusStrategy

Helper: h,
}
return &REST{store: store}, &BindingREST{store: store, factory: factory}
return &REST{store: store}, &BindingREST{store: store, factory: factory}, &StatusREST{store: &statusStore}
}

// WithPodStatus returns a rest object that decorates returned responses with extra
Expand Down Expand Up @@ -250,3 +252,17 @@ func (h *podLifecycle) AfterDelete(obj runtime.Object) error {
return pods, nil
})
}

// StatusREST implements the REST endpoint for changing the status of a pod.
type StatusREST struct {
store *etcdgeneric.Etcd
}

func (r *StatusREST) New() runtime.Object {
return &api.Pod{}
}

// Update alters the status subset of an object.
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
return r.store.Update(ctx, obj)
}
Loading

0 comments on commit fca9fd6

Please sign in to comment.