func streamLocation(getter ResourceGetter, connInfo client.ConnectionInfoGetter, ctx api.Context, name string, opts runtime.Object, container, path string) (*url.URL, http.RoundTripper, error) { pod, err := getPod(getter, ctx, name) if err != nil { return nil, nil, err } // Try to figure out a container if container == "" { if len(pod.Spec.Containers) == 1 { container = pod.Spec.Containers[0].Name } else { return nil, nil, errors.NewBadRequest(fmt.Sprintf("a container name must be specified for pod %s", name)) } } nodeHost := pod.Spec.NodeName if len(nodeHost) == 0 { // If pod has not been assigned a host, return an empty location return nil, nil, errors.NewBadRequest(fmt.Sprintf("pod %s does not have a host assigned", name)) } nodeScheme, nodePort, nodeTransport, err := connInfo.GetConnectionInfo(nodeHost) if err != nil { return nil, nil, err } params := url.Values{} if err := streamParams(params, opts); err != nil { return nil, nil, err } loc := &url.URL{ Scheme: nodeScheme, Host: fmt.Sprintf("%s:%d", nodeHost, nodePort), Path: fmt.Sprintf("/%s/%s/%s/%s", path, pod.Namespace, name, container), RawQuery: params.Encode(), } return loc, nodeTransport, nil }
// NoNamespaceKeyFunc is the default function for constructing etcd paths to a resource relative to prefix enforcing namespace rules. // If a namespace is on context, it errors. func NoNamespaceKeyFunc(ctx api.Context, prefix string, name string) (string, error) { ns, ok := api.NamespaceFrom(ctx) if ok && len(ns) > 0 { return "", kubeerr.NewBadRequest("Namespace parameter is not allowed.") } if len(name) == 0 { return "", kubeerr.NewBadRequest("Name parameter required.") } return path.Join(prefix, name), nil }
// transformDecodeError adds additional information when a decode fails. func transformDecodeError(typer runtime.ObjectTyper, baseErr error, into runtime.Object, body []byte) error { _, kind, err := typer.ObjectVersionAndKind(into) if err != nil { return err } if version, dataKind, err := typer.DataVersionAndKind(body); err == nil && len(dataKind) > 0 { return errors.NewBadRequest(fmt.Sprintf("%s in version %s cannot be handled as a %s: %v", dataKind, version, kind, baseErr)) } return errors.NewBadRequest(fmt.Sprintf("the object provided is unrecognized (must be of type %s): %v", kind, baseErr)) }
// NamespaceKeyFunc is the default function for constructing etcd paths to a resource relative to prefix enforcing namespace rules. // If no namespace is on context, it errors. func NamespaceKeyFunc(ctx api.Context, prefix string, name string) (string, error) { key := NamespaceKeyRootFunc(ctx, prefix) ns, ok := api.NamespaceFrom(ctx) if !ok || len(ns) == 0 { return "", kubeerr.NewBadRequest("Namespace parameter required.") } if len(name) == 0 { return "", kubeerr.NewBadRequest("Name parameter required.") } key = key + "/" + name return key, nil }
// checkName checks the provided name against the request func checkName(obj runtime.Object, name, namespace string, namer ScopeNamer) error { if objNamespace, objName, err := namer.ObjectName(obj); err == nil { if objName != name { return errors.NewBadRequest("the name of the object does not match the name on the URL") } if len(namespace) > 0 { if len(objNamespace) > 0 && objNamespace != namespace { return errors.NewBadRequest("the namespace of the object does not match the namespace on the request") } } } return nil }
// Get returns a streamer resource with the contents of the build log func (r *REST) Get(ctx kapi.Context, name string, opts runtime.Object) (runtime.Object, error) { buildLogOpts, ok := opts.(*api.BuildLogOptions) if !ok { return nil, errors.NewBadRequest("did not get an expected options.") } build, err := r.BuildRegistry.GetBuild(ctx, name) if err != nil { return nil, errors.NewNotFound("build", name) } switch build.Status { // Build has not launched, wait til it runs case api.BuildStatusNew, api.BuildStatusPending: if buildLogOpts.NoWait { glog.V(4).Infof("Build %s/%s is in %s state, nothing to retrieve", build.Namespace, name, build.Status) // return empty content if not waiting for build return &genericrest.LocationStreamer{}, nil } glog.V(4).Infof("Build %s/%s is in %s state, waiting for Build to start", build.Namespace, name, build.Status) err := r.waitForBuild(ctx, build) if err != nil { return nil, err } // The build was cancelled case api.BuildStatusCancelled: return nil, errors.NewBadRequest(fmt.Sprintf("build %s/%s was cancelled", build.Namespace, build.Name)) // An error occurred launching the build, return an error case api.BuildStatusError: return nil, errors.NewBadRequest(fmt.Sprintf("build %s/%s is in an error state", build.Namespace, build.Name)) case api.BuildStatusNoOpenshift: return nil, errors.NewBadRequest(fmt.Sprintf("build %s/%s cannot proceeed. You need to upgrade to OpenShift in order to take advantage of this feature", build.Namespace, build.Name)) } // The container should be the default build container, so setting it to blank buildPodName := buildutil.GetBuildPodName(build) logOpts := &kapi.PodLogOptions{ Follow: buildLogOpts.Follow, } location, transport, err := pod.LogLocation(r.PodGetter, r.ConnectionInfo, ctx, buildPodName, logOpts) if err != nil { return nil, errors.NewBadRequest(err.Error()) } return &genericrest.LocationStreamer{ Location: location, Transport: transport, ContentType: "text/plain", Flush: buildLogOpts.Follow, }, nil }
// ParseNameAndID splits a string into its name component and ID component, and returns an error // if the string is not in the right form. func ParseNameAndID(input string) (name string, id string, err error) { segments := strings.Split(input, "@") switch len(segments) { case 2: name = segments[0] id = segments[1] if len(name) == 0 || len(id) == 0 { err = errors.NewBadRequest("ImageStreamImages must be retrieved with <name>@<id>") } default: err = errors.NewBadRequest("ImageStreamImages must be retrieved with <name>@<id>") } return }
// nameAndTag splits a string into its name component and tag component, and returns an error // if the string is not in the right form. func nameAndTag(id string) (name string, tag string, err error) { segments := strings.Split(id, ":") switch len(segments) { case 2: name = segments[0] tag = segments[1] if len(name) == 0 || len(tag) == 0 { err = errors.NewBadRequest("ImageStreamTags must be retrieved with <name>:<tag>") } default: err = errors.NewBadRequest("ImageStreamTags must be retrieved with <name>:<tag>") } return }
// ExecLocation returns the exec URL for a pod container. If opts.Container is blank // and only one container is present in the pod, that container is used. func ExecLocation(getter ResourceGetter, connInfo client.ConnectionInfoGetter, ctx api.Context, name string, opts *api.PodExecOptions) (*url.URL, http.RoundTripper, error) { pod, err := getPod(getter, ctx, name) if err != nil { return nil, nil, err } // Try to figure out a container container := opts.Container if container == "" { if len(pod.Spec.Containers) == 1 { container = pod.Spec.Containers[0].Name } else { return nil, nil, errors.NewBadRequest(fmt.Sprintf("a container name must be specified for pod %s", name)) } } nodeHost := pod.Spec.NodeName if len(nodeHost) == 0 { // If pod has not been assigned a host, return an empty location return nil, nil, errors.NewBadRequest(fmt.Sprintf("pod %s does not have a host assigned", name)) } nodeScheme, nodePort, nodeTransport, err := connInfo.GetConnectionInfo(nodeHost) if err != nil { return nil, nil, err } params := url.Values{} if opts.Stdin { params.Add(api.ExecStdinParam, "1") } if opts.Stdout { params.Add(api.ExecStdoutParam, "1") } if opts.Stderr { params.Add(api.ExecStderrParam, "1") } if opts.TTY { params.Add(api.ExecTTYParam, "1") } for _, c := range opts.Command { params.Add("command", c) } loc := &url.URL{ Scheme: nodeScheme, Host: fmt.Sprintf("%s:%d", nodeHost, nodePort), Path: fmt.Sprintf("/exec/%s/%s/%s", pod.Namespace, name, container), RawQuery: params.Encode(), } return loc, nodeTransport, nil }
// Update replaces a given Route instance with an existing instance in rs.registry. func (rs *REST) Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bool, error) { route, ok := obj.(*api.Route) if !ok { return nil, false, errors.NewBadRequest(fmt.Sprintf("not a route: %#v", obj)) } if !kapi.ValidNamespace(ctx, &route.ObjectMeta) { return nil, false, errors.NewConflict("route", route.Namespace, fmt.Errorf("Route.Namespace does not match the provided context")) } old, err := rs.Get(ctx, route.Name) if err != nil { return nil, false, err } if errs := validation.ValidateRouteUpdate(route, old.(*api.Route)); len(errs) > 0 { return nil, false, errors.NewInvalid("route", route.Name, errs) } // TODO: Convert to generic etcd // TODO: Call ValidateRouteUpdate->ValidateObjectMetaUpdate // TODO: In the UpdateStrategy.PrepareForUpdate, set the HostGeneratedAnnotationKey annotation to "false" if the updated route object modifies the host err = rs.registry.UpdateRoute(ctx, route) if err != nil { return nil, false, err } out, err := rs.registry.GetRoute(ctx, route.Name) return out, false, err }
// ResourceLocation returns an URL and transport which one can use to send traffic for the specified node. func ResourceLocation(getter ResourceGetter, connection client.ConnectionInfoGetter, ctx api.Context, id string) (*url.URL, http.RoundTripper, error) { name, portReq, valid := util.SplitPort(id) if !valid { return nil, nil, errors.NewBadRequest(fmt.Sprintf("invalid node request %q", id)) } nodeObj, err := getter.Get(ctx, name) if err != nil { return nil, nil, err } node := nodeObj.(*api.Node) hostIP, err := nodeutil.GetNodeHostIP(node) if err != nil { return nil, nil, err } host := hostIP.String() if portReq == "" || strconv.Itoa(ports.KubeletPort) == portReq { scheme, port, transport, err := connection.GetConnectionInfo(host) if err != nil { return nil, nil, err } return &url.URL{ Scheme: scheme, Host: net.JoinHostPort( host, strconv.FormatUint(uint64(port), 10), ), }, transport, nil } return &url.URL{Host: net.JoinHostPort(host, portReq)}, nil, nil }
// ResourceLocation returns a URL to which one can send traffic for the specified node. func ResourceLocation(getter ResourceGetter, connection client.ConnectionInfoGetter, ctx api.Context, id string) (*url.URL, http.RoundTripper, error) { name, portReq, valid := util.SplitPort(id) if !valid { return nil, nil, errors.NewBadRequest(fmt.Sprintf("invalid node request %q", id)) } nodeObj, err := getter.Get(ctx, name) if err != nil { return nil, nil, err } node := nodeObj.(*api.Node) host := node.Name // TODO: use node's IP, don't expect the name to resolve. if portReq != "" { return &url.URL{Host: net.JoinHostPort(host, portReq)}, nil, nil } scheme, port, transport, err := connection.GetConnectionInfo(host) if err != nil { return nil, nil, err } return &url.URL{ Scheme: scheme, Host: net.JoinHostPort( host, strconv.FormatUint(uint64(port), 10), ), }, transport, nil }
// Create registers a given new ResourceAccessReview instance to r.registry. func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { resourceAccessReview, ok := obj.(*authorizationapi.ResourceAccessReview) if !ok { return nil, errors.NewBadRequest(fmt.Sprintf("not a resourceAccessReview: %#v", obj)) } if err := kutilerrors.NewAggregate(authorizationvalidation.ValidateResourceAccessReview(resourceAccessReview)); err != nil { return nil, err } namespace := kapi.NamespaceValue(ctx) attributes := &authorizer.DefaultAuthorizationAttributes{ Verb: resourceAccessReview.Verb, Resource: resourceAccessReview.Resource, } users, groups, err := r.authorizer.GetAllowedSubjects(ctx, attributes) if err != nil { return nil, err } response := &authorizationapi.ResourceAccessReviewResponse{ Namespace: namespace, Users: users, Groups: groups, } return response, nil }
// ServeHTTP handles the proxy request func (h *UpgradeAwareProxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { h.err = nil if len(h.Location.Scheme) == 0 { h.Location.Scheme = "http" } if h.tryUpgrade(w, req) { return } if h.UpgradeRequired { h.err = errors.NewBadRequest("Upgrade request required") return } if h.Transport == nil { h.Transport = h.defaultProxyTransport(req.URL) } loc := *h.Location loc.RawQuery = req.URL.RawQuery newReq, err := http.NewRequest(req.Method, loc.String(), req.Body) if err != nil { h.err = err return } newReq.Header = req.Header proxy := httputil.NewSingleHostReverseProxy(&url.URL{Scheme: h.Location.Scheme, Host: h.Location.Host}) proxy.Transport = h.Transport proxy.FlushInterval = h.FlushInterval proxy.ServeHTTP(w, newReq) }
func (g *podGetter) Get(ctx kapi.Context, name string) (runtime.Object, error) { ns, ok := kapi.NamespaceFrom(ctx) if !ok { return nil, errors.NewBadRequest("namespace parameter required.") } return g.podsNamespacer.Pods(ns).Get(name) }
// ResourceLocation returns a URL to which one can send traffic for the specified service. func (rs *REST) ResourceLocation(ctx api.Context, id string) (*url.URL, http.RoundTripper, error) { // Allow ID as "svcname" or "svcname:port". svcName, portStr, valid := util.SplitPort(id) if !valid { return nil, nil, errors.NewBadRequest(fmt.Sprintf("invalid service request %q", id)) } eps, err := rs.endpoints.GetEndpoints(ctx, svcName) if err != nil { return nil, nil, err } if len(eps.Subsets) == 0 { return nil, nil, fmt.Errorf("no endpoints available for %q", svcName) } // Pick a random Subset to start searching from. ssSeed := rand.Intn(len(eps.Subsets)) // Find a Subset that has the port. for ssi := 0; ssi < len(eps.Subsets); ssi++ { ss := &eps.Subsets[(ssSeed+ssi)%len(eps.Subsets)] for i := range ss.Ports { if ss.Ports[i].Name == portStr { // Pick a random address. ip := ss.Addresses[rand.Intn(len(ss.Addresses))].IP port := ss.Ports[i].Port // We leave off the scheme ('http://') because we have no idea what sort of server // is listening at this endpoint. return &url.URL{ Host: net.JoinHostPort(ip, strconv.Itoa(port)), }, nil, nil } } } return nil, nil, fmt.Errorf("no endpoints available for %q", id) }
// ResourceLocation returns a URL to which one can send traffic for the specified pod. func ResourceLocation(getter ResourceGetter, ctx api.Context, id string) (*url.URL, http.RoundTripper, error) { // Allow ID as "podname" or "podname:port". If port is not specified, // try to use the first defined port on the pod. name, port, valid := util.SplitPort(id) if !valid { return nil, nil, errors.NewBadRequest(fmt.Sprintf("invalid pod request %q", id)) } // TODO: if port is not a number but a "(container)/(portname)", do a name lookup. pod, err := getPod(getter, ctx, name) if err != nil { return nil, nil, err } // Try to figure out a port. if port == "" { for i := range pod.Spec.Containers { if len(pod.Spec.Containers[i].Ports) > 0 { port = fmt.Sprintf("%d", pod.Spec.Containers[i].Ports[0].ContainerPort) break } } } // We leave off the scheme ('http://') because we have no idea what sort of server // is listening at this endpoint. loc := &url.URL{} if port == "" { loc.Host = pod.Status.PodIP } else { loc.Host = net.JoinHostPort(pod.Status.PodIP, port) } return loc, nil, nil }
// Create registers a given new ResourceAccessReview instance to r.registry. func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { subjectAccessReview, ok := obj.(*authorizationapi.SubjectAccessReview) if !ok { return nil, kerrors.NewBadRequest(fmt.Sprintf("not a subjectAccessReview: %#v", obj)) } if err := kutilerrors.NewAggregate(authorizationvalidation.ValidateSubjectAccessReview(subjectAccessReview)); err != nil { return nil, err } var userToCheck user.Info if (len(subjectAccessReview.User) == 0) && (len(subjectAccessReview.Groups) == 0) { // if no user or group was specified, use the info from the context ctxUser, exists := kapi.UserFrom(ctx) if !exists { return nil, kerrors.NewBadRequest("user missing from context") } userToCheck = ctxUser } else { userToCheck = &user.DefaultInfo{ Name: subjectAccessReview.User, Groups: subjectAccessReview.Groups.List(), } } namespace := kapi.NamespaceValue(ctx) requestContext := kapi.WithUser(ctx, userToCheck) attributes := &authorizer.DefaultAuthorizationAttributes{ Verb: subjectAccessReview.Verb, Resource: subjectAccessReview.Resource, } allowed, reason, err := r.authorizer.Authorize(requestContext, attributes) if err != nil { return nil, err } response := &authorizationapi.SubjectAccessReviewResponse{ Namespace: namespace, Allowed: allowed, Reason: reason, } return response, nil }
// Update associates an identity with a user. // Both the identity and user must already exist. // If the identity is associated with another user already, it is disassociated. func (s *REST) Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bool, error) { mapping, ok := obj.(*api.UserIdentityMapping) if !ok { return nil, false, kerrs.NewBadRequest("invalid type") } Strategy.PrepareForUpdate(mapping, nil) return s.createOrUpdate(ctx, mapping, false) }
func parseSelectorQueryParams(query url.Values, version, apiResource string) (label labels.Selector, field fields.Selector, err error) { labelString := query.Get(api.LabelSelectorQueryParam(version)) label, err = labels.Parse(labelString) if err != nil { return nil, nil, errors.NewBadRequest(fmt.Sprintf("The 'labels' selector parameter (%s) could not be parsed: %v", labelString, err)) } convertToInternalVersionFunc := func(label, value string) (newLabel, newValue string, err error) { return api.Scheme.ConvertFieldLabel(version, apiResource, label, value) } fieldString := query.Get(api.FieldSelectorQueryParam(version)) field, err = fields.ParseAndTransformSelector(fieldString, convertToInternalVersionFunc) if err != nil { return nil, nil, errors.NewBadRequest(fmt.Sprintf("The 'fields' selector parameter (%s) could not be parsed: %v", fieldString, err)) } return label, field, nil }
// Create associates a user and identity if they both exist, and the identity is not already mapped to a user func (s *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { mapping, ok := obj.(*api.UserIdentityMapping) if !ok { return nil, kerrs.NewBadRequest("invalid type") } Strategy.PrepareForCreate(mapping) createdMapping, _, err := s.createOrUpdate(ctx, obj, true) return createdMapping, err }
// transformResponse converts an API response into a structured API object. func (r *Request) transformResponse(resp *http.Response, req *http.Request) ([]byte, bool, error) { defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, false, err } // Did the server give us a status response? isStatusResponse := false var status api.Status if err := r.codec.DecodeInto(body, &status); err == nil && status.Status != "" { isStatusResponse = true } switch { case resp.StatusCode == http.StatusSwitchingProtocols: // no-op, we've been upgraded case resp.StatusCode < http.StatusOK || resp.StatusCode > http.StatusPartialContent: if !isStatusResponse { var err error = &UnexpectedStatusError{ Request: req, Response: resp, Body: string(body), } // TODO: handle other error classes we know about switch resp.StatusCode { case http.StatusConflict: if req.Method == "POST" { err = errors.NewAlreadyExists(r.resource, r.resourceName) } else { err = errors.NewConflict(r.resource, r.resourceName, err) } case http.StatusNotFound: err = errors.NewNotFound(r.resource, r.resourceName) case http.StatusBadRequest: err = errors.NewBadRequest(err.Error()) } return nil, false, err } return nil, false, errors.FromObject(&status) } // If the server gave us a status back, look at what it was. if isStatusResponse && status.Status != api.StatusSuccess { // "Working" requests need to be handled specially. // "Failed" requests are clearly just an error and it makes sense to return them as such. return nil, false, errors.FromObject(&status) } created := resp.StatusCode == http.StatusCreated return body, created, err }
// ServeHTTP handles the proxy request func (h *UpgradeAwareProxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { h.err = nil if len(h.Location.Scheme) == 0 { h.Location.Scheme = "http" } if h.tryUpgrade(w, req) { return } if h.UpgradeRequired { h.err = errors.NewBadRequest("Upgrade request required") return } loc := *h.Location loc.RawQuery = req.URL.RawQuery // If original request URL ended in '/', append a '/' at the end of the // of the proxy URL if !strings.HasSuffix(loc.Path, "/") && strings.HasSuffix(req.URL.Path, "/") { loc.Path += "/" } // From pkg/apiserver/proxy.go#ServeHTTP: // Redirect requests with an empty path to a location that ends with a '/' // This is essentially a hack for https://github.com/GoogleCloudPlatform/kubernetes/issues/4958. // Note: Keep this code after tryUpgrade to not break that flow. if len(loc.Path) == 0 { var queryPart string if len(req.URL.RawQuery) > 0 { queryPart = "?" + req.URL.RawQuery } w.Header().Set("Location", req.URL.Path+"/"+queryPart) w.WriteHeader(http.StatusMovedPermanently) return } if h.Transport == nil { h.Transport = h.defaultProxyTransport(req.URL) } newReq, err := http.NewRequest(req.Method, loc.String(), req.Body) if err != nil { h.err = err return } newReq.Header = req.Header proxy := httputil.NewSingleHostReverseProxy(&url.URL{Scheme: h.Location.Scheme, Host: h.Location.Host}) proxy.Transport = h.Transport proxy.FlushInterval = h.FlushInterval proxy.ServeHTTP(w, newReq) }
// queryToObject converts query parameters into a structured internal object by // kind. The caller must cast the returned object to the matching internal Kind // to use it. // TODO: add appropriate structured error responses func queryToObject(query url.Values, scope RequestScope, kind string) (runtime.Object, error) { versioned, err := scope.Creater.New(scope.ServerAPIVersion, kind) if err != nil { // programmer error return nil, err } if err := scope.Convertor.Convert(&query, versioned); err != nil { return nil, errors.NewBadRequest(err.Error()) } out, err := scope.Convertor.ConvertToVersion(versioned, "") if err != nil { // programmer error return nil, err } return out, nil }
func (m *VirtualStorage) updateRoleBinding(ctx kapi.Context, obj runtime.Object, allowEscalation bool) (*authorizationapi.RoleBinding, bool, error) { roleBinding, ok := obj.(*authorizationapi.RoleBinding) if !ok { return nil, false, kapierrors.NewBadRequest(fmt.Sprintf("obj is not a role: %#v", obj)) } old, err := m.Get(ctx, roleBinding.Name) if err != nil { return nil, false, err } if err := rest.BeforeUpdate(m.UpdateStrategy, ctx, obj, old); err != nil { return nil, false, err } if err := m.validateReferentialIntegrity(ctx, roleBinding); err != nil { return nil, false, err } if !allowEscalation { if err := m.confirmNoEscalation(ctx, roleBinding); err != nil { return nil, false, err } } policyBinding, err := m.getPolicyBindingForPolicy(ctx, roleBinding.RoleRef.Namespace, allowEscalation) if err != nil { return nil, false, err } previousRoleBinding, exists := policyBinding.RoleBindings[roleBinding.Name] if !exists { return nil, false, kapierrors.NewNotFound("RoleBinding", roleBinding.Name) } if previousRoleBinding.RoleRef != roleBinding.RoleRef { return nil, false, errors.New("roleBinding.RoleRef may not be modified") } roleBinding.ResourceVersion = policyBinding.ResourceVersion policyBinding.RoleBindings[roleBinding.Name] = roleBinding policyBinding.LastModified = util.Now() if err := m.BindingRegistry.UpdatePolicyBinding(ctx, policyBinding); err != nil { return nil, false, err } return roleBinding, false, nil }
// BeforeUpdate ensures that common operations for all resources are performed on update. It only returns // errors that can be converted to api.Status. It will invoke update validation with the provided existing // and updated objects. func BeforeUpdate(strategy RESTUpdateStrategy, ctx api.Context, obj, old runtime.Object) error { objectMeta, kind, kerr := objectMetaAndKind(strategy, obj) if kerr != nil { return kerr } if strategy.NamespaceScoped() { if !api.ValidNamespace(ctx, objectMeta) { return errors.NewBadRequest("the namespace of the provided object does not match the namespace sent on the request") } } else { objectMeta.Namespace = api.NamespaceNone } if errs := strategy.ValidateUpdate(obj, old); len(errs) > 0 { return errors.NewInvalid(kind, objectMeta.Name, errs) } return nil }
func (d *denyExecOnPrivileged) Admit(a admission.Attributes) (err error) { connectRequest, ok := a.GetObject().(*rest.ConnectRequest) if !ok { return errors.NewBadRequest("a connect request was received, but could not convert the request object.") } // Only handle exec requests on pods if connectRequest.ResourcePath != "pods/exec" { return nil } pod, err := d.client.Pods(a.GetNamespace()).Get(connectRequest.Name) if err != nil { return admission.NewForbidden(a, err) } if isPrivileged(pod) { return admission.NewForbidden(a, fmt.Errorf("Cannot exec into a privileged container")) } return nil }
// Create processes a Template and creates a new list of objects func (s *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { tpl, ok := obj.(*api.Template) if !ok { return nil, errors.NewBadRequest("not a template") } if errs := templatevalidation.ValidateProcessedTemplate(tpl); len(errs) > 0 { return nil, errors.NewInvalid("template", tpl.Name, errs) } generators := map[string]generator.Generator{ "expression": generator.NewExpressionValueGenerator(rand.New(rand.NewSource(time.Now().UnixNano()))), } processor := template.NewProcessor(generators) if errs := processor.Process(tpl); len(errs) > 0 { glog.V(1).Infof(utilerr.NewAggregate(errs).Error()) return nil, errors.NewInvalid("template", tpl.Name, errs) } return tpl, nil }
// ServeHTTP implements rest.HookHandler func (c *controller) ServeHTTP(w http.ResponseWriter, req *http.Request, ctx kapi.Context, name, subpath string) error { parts := strings.Split(subpath, "/") if len(parts) < 2 { return errors.NewBadRequest(fmt.Sprintf("unexpected hook subpath %s", subpath)) } secret, hookType := parts[0], parts[1] plugin, ok := c.plugins[hookType] if !ok { return errors.NewNotFound("BuildConfigHook", hookType) } config, err := c.registry.GetBuildConfig(ctx, name) if err != nil { // clients should not be able to find information about build configs in the system unless the config exists // and the secret matches return errors.NewUnauthorized(fmt.Sprintf("the webhook %q for %q did not accept your secret", hookType, name)) } revision, proceed, err := plugin.Extract(config, secret, "", req) switch err { case webhook.ErrSecretMismatch, webhook.ErrHookNotEnabled: return errors.NewUnauthorized(fmt.Sprintf("the webhook %q for %q did not accept your secret", hookType, name)) case nil: default: return errors.NewInternalError(fmt.Errorf("hook failed: %v", err)) } if !proceed { return nil } request := &buildapi.BuildRequest{ ObjectMeta: kapi.ObjectMeta{Name: name}, Revision: revision, } if _, err := c.instantiator.Instantiate(config.Namespace, request); err != nil { return errors.NewInternalError(fmt.Errorf("could not generate a build: %v", err)) } return nil }
// ResourceLocation returns a URL to which one can send traffic for the specified pod. func (rs *REST) ResourceLocation(ctx api.Context, id string) (string, error) { // Allow ID as "podname" or "podname:port". If port is not specified, // try to use the first defined port on the pod. parts := strings.Split(id, ":") if len(parts) > 2 { return "", errors.NewBadRequest(fmt.Sprintf("invalid pod request %q", id)) } name := parts[0] port := "" if len(parts) == 2 { // TODO: if port is not a number but a "(container)/(portname)", do a name lookup. port = parts[1] } obj, err := rs.Get(ctx, name) if err != nil { return "", err } pod := obj.(*api.Pod) if pod == nil { return "", nil } // Try to figure out a port. if port == "" { for i := range pod.Spec.Containers { if len(pod.Spec.Containers[i].Ports) > 0 { port = fmt.Sprintf("%d", pod.Spec.Containers[i].Ports[0].ContainerPort) break } } } // We leave off the scheme ('http://') because we have no idea what sort of server // is listening at this endpoint. loc := pod.Status.PodIP if port != "" { loc += fmt.Sprintf(":%s", port) } return loc, nil }