func GetEffectivePolicyRules(ctx kapi.Context, ruleResolver rulevalidation.AuthorizationRuleResolver, clusterPolicyGetter client.ClusterPolicyLister) ([]authorizationapi.PolicyRule, []error) { namespace := kapi.NamespaceValue(ctx) if len(namespace) == 0 { return nil, []error{kapierrors.NewBadRequest(fmt.Sprintf("namespace is required on this type: %v", namespace))} } user, exists := kapi.UserFrom(ctx) if !exists { return nil, []error{kapierrors.NewBadRequest(fmt.Sprintf("user missing from context"))} } var errors []error var rules []authorizationapi.PolicyRule namespaceRules, err := ruleResolver.RulesFor(user, namespace) if err != nil { errors = append(errors, err) } for _, rule := range namespaceRules { rules = append(rules, rulevalidation.BreakdownRule(rule)...) } if scopes := user.GetExtra()[authorizationapi.ScopesKey]; len(scopes) > 0 { rules, err = filterRulesByScopes(rules, scopes, namespace, clusterPolicyGetter) if err != nil { return nil, []error{kapierrors.NewInternalError(err)} } } if compactedRules, err := rulevalidation.CompactRules(rules); err == nil { rules = compactedRules } sort.Sort(authorizationapi.SortableRuleSlice(rules)) return rules, errors }
func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { localSubjectAccessReview, ok := obj.(*authorizationapi.LocalSubjectAccessReview) if !ok { return nil, kapierrors.NewBadRequest(fmt.Sprintf("not a LocaLocalSubjectAccessReview: %#v", obj)) } if errs := authorizationvalidation.ValidateLocalSubjectAccessReview(localSubjectAccessReview); len(errs) > 0 { return nil, kapierrors.NewInvalid(authorizationapi.Kind(localSubjectAccessReview.Kind), "", errs) } namespace := kapi.NamespaceValue(ctx) if len(namespace) == 0 { return nil, kapierrors.NewBadRequest(fmt.Sprintf("namespace is required on this type: %v", namespace)) } if namespace != localSubjectAccessReview.Namespace { return nil, kapierrors.NewBadRequest(fmt.Sprintf("spec.resourceAttributes.namespace must match namespace: %v", namespace)) } authorizationAttributes := authorizationutil.AuthorizationAttributesFrom(localSubjectAccessReview.Spec) allowed, reason, evaluationErr := r.authorizer.Authorize(authorizationAttributes) localSubjectAccessReview.Status = authorizationapi.SubjectAccessReviewStatus{ Allowed: allowed, Reason: reason, } if evaluationErr != nil { localSubjectAccessReview.Status.EvaluationError = evaluationErr.Error() } return localSubjectAccessReview, nil }
// Create transforms a LocalSAR into an ClusterSAR that is requesting a namespace. That collapses the code paths. // LocalSubjectAccessReview exists to allow clean expression of policy. func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { localSAR, ok := obj.(*authorizationapi.LocalSubjectAccessReview) if !ok { return nil, kapierrors.NewBadRequest(fmt.Sprintf("not a localSubjectAccessReview: %#v", obj)) } if errs := authorizationvalidation.ValidateLocalSubjectAccessReview(localSAR); len(errs) > 0 { return nil, kapierrors.NewInvalid(authorizationapi.Kind(localSAR.Kind), "", errs) } if namespace := kapi.NamespaceValue(ctx); len(namespace) == 0 { return nil, kapierrors.NewBadRequest(fmt.Sprintf("namespace is required on this type: %v", namespace)) } else if (len(localSAR.Action.Namespace) > 0) && (namespace != localSAR.Action.Namespace) { return nil, field.Invalid(field.NewPath("namespace"), localSAR.Action.Namespace, fmt.Sprintf("namespace must be: %v", namespace)) } // transform this into a SubjectAccessReview clusterSAR := &authorizationapi.SubjectAccessReview{ Action: localSAR.Action, User: localSAR.User, Groups: localSAR.Groups, Scopes: localSAR.Scopes, } clusterSAR.Action.Namespace = kapi.NamespaceValue(ctx) return r.clusterSARRegistry.CreateSubjectAccessReview(kapi.WithNamespace(ctx, ""), clusterSAR) }
func (r *REST) Create(ctx api.Context, obj runtime.Object) (runtime.Object, error) { selfSAR, ok := obj.(*authorizationapi.SelfSubjectAccessReview) if !ok { return nil, apierrors.NewBadRequest(fmt.Sprintf("not a SelfSubjectAccessReview: %#v", obj)) } if errs := authorizationvalidation.ValidateSelfSubjectAccessReview(selfSAR); len(errs) > 0 { return nil, apierrors.NewInvalid(authorizationapi.Kind(selfSAR.Kind), "", errs) } userToCheck, exists := api.UserFrom(ctx) if !exists { return nil, apierrors.NewBadRequest("no user present on request") } var authorizationAttributes authorizer.AttributesRecord if selfSAR.Spec.ResourceAttributes != nil { authorizationAttributes = authorizationutil.ResourceAttributesFrom(userToCheck, *selfSAR.Spec.ResourceAttributes) } else { authorizationAttributes = authorizationutil.NonResourceAttributesFrom(userToCheck, *selfSAR.Spec.NonResourceAttributes) } allowed, reason, evaluationErr := r.authorizer.Authorize(authorizationAttributes) selfSAR.Status = authorizationapi.SubjectAccessReviewStatus{ Allowed: allowed, Reason: reason, } if evaluationErr != nil { selfSAR.Status.EvaluationError = evaluationErr.Error() } return selfSAR, nil }
func (r *ScaleREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { rc, err := r.registry.GetController(ctx, name) if err != nil { return nil, false, errors.NewNotFound(autoscaling.Resource("replicationcontrollers/scale"), name) } oldScale := scaleFromRC(rc) obj, err := objInfo.UpdatedObject(ctx, oldScale) if err != nil { return nil, false, err } if obj == nil { return nil, false, errors.NewBadRequest("nil update passed to Scale") } scale, ok := obj.(*autoscaling.Scale) if !ok { return nil, false, errors.NewBadRequest(fmt.Sprintf("wrong object passed to Scale update: %v", obj)) } if errs := validation.ValidateScale(scale); len(errs) > 0 { return nil, false, errors.NewInvalid(autoscaling.Kind("Scale"), scale.Name, errs) } rc.Spec.Replicas = scale.Spec.Replicas rc.ResourceVersion = scale.ResourceVersion rc, err = r.registry.UpdateController(ctx, rc) if err != nil { return nil, false, err } return scaleFromRC(rc), false, nil }
func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) { if obj == nil { return nil, false, errors.NewBadRequest(fmt.Sprintf("nil update passed to Scale")) } scale, ok := obj.(*extensions.Scale) if !ok { return nil, false, errors.NewBadRequest(fmt.Sprintf("expected input object type to be Scale, but %T", obj)) } if errs := extvalidation.ValidateScale(scale); len(errs) > 0 { return nil, false, errors.NewInvalid(extensions.Kind("Scale"), scale.Name, errs) } deployment, err := r.registry.GetDeployment(ctx, scale.Name) if err != nil { return nil, false, errors.NewNotFound(extensions.Resource("deployments/scale"), scale.Name) } deployment.Spec.Replicas = scale.Spec.Replicas deployment.ResourceVersion = scale.ResourceVersion deployment, err = r.registry.UpdateDeployment(ctx, deployment) if err != nil { return nil, false, err } newScale, err := scaleFromDeployment(deployment) if err != nil { return nil, false, errors.NewBadRequest(fmt.Sprintf("%v", err)) } return newScale, false, nil }
func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) { if obj == nil { return nil, false, errors.NewBadRequest(fmt.Sprintf("nil update passed to Scale")) } scale, ok := obj.(*extensions.Scale) if !ok { return nil, false, errors.NewBadRequest(fmt.Sprintf("wrong object passed to Scale update: %v", obj)) } if errs := extvalidation.ValidateScale(scale); len(errs) > 0 { return nil, false, errors.NewInvalid(extensions.Kind("Scale"), scale.Name, errs) } rs, err := r.registry.GetReplicaSet(ctx, scale.Name) if err != nil { return nil, false, errors.NewNotFound(extensions.Resource("replicasets/scale"), scale.Name) } rs.Spec.Replicas = scale.Spec.Replicas rs.ResourceVersion = scale.ResourceVersion rs, err = r.registry.UpdateReplicaSet(ctx, rs) if err != nil { return nil, false, err } newScale, err := scaleFromReplicaSet(rs) if err != nil { return nil, false, errors.NewBadRequest(fmt.Sprintf("%v", err)) } return newScale, false, err }
// Admit will deny pods that have a RunAsUser set that isn't the uid of the user requesting it func (p *plugin) Admit(a admission.Attributes) (err error) { if a.GetResource() != string(api.ResourcePods) { return nil } pod, ok := a.GetObject().(*api.Pod) if !ok { return apierrors.NewBadRequest("Resource was marked with kind Pod but was unable to be converted") } user := a.GetUserInfo() if user == nil { return apierrors.NewBadRequest("uidenforcer admission controller can not be used if there is no user set") } for i := 0; i < len(pod.Spec.Containers); i++ { container := &pod.Spec.Containers[i] uid, ok := strconv.ParseInt(user.GetUID(), 10, 32) if ok == nil { if container.SecurityContext == nil { container.SecurityContext = &api.SecurityContext{ RunAsUser: &uid, } } else { container.SecurityContext.RunAsUser = &uid } } else { return apierrors.NewBadRequest("Requesting user's uid is not an integer") } } return nil }
func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) { if obj == nil { return nil, false, errors.NewBadRequest(fmt.Sprintf("nil update passed to Scale")) } scale, ok := obj.(*experimental.Scale) if !ok { return nil, false, errors.NewBadRequest(fmt.Sprintf("wrong object passed to Scale update: %v", obj)) } rc, err := (*r.registry).GetController(ctx, scale.Name) if err != nil { return nil, false, errors.NewNotFound("scale", scale.Name) } rc.Spec.Replicas = scale.Spec.Replicas rc, err = (*r.registry).UpdateController(ctx, rc) if err != nil { return nil, false, errors.NewConflict("scale", scale.Name, err) } return &experimental.Scale{ ObjectMeta: api.ObjectMeta{ Name: rc.Name, Namespace: rc.Namespace, CreationTimestamp: rc.CreationTimestamp, }, Spec: experimental.ScaleSpec{ Replicas: rc.Spec.Replicas, }, Status: experimental.ScaleStatus{ Replicas: rc.Status.Replicas, Selector: rc.Spec.Selector, }, }, false, nil }
// Create registers a given new ResourceAccessReview instance to r.registry. func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { rulesReview, ok := obj.(*authorizationapi.SubjectRulesReview) if !ok { return nil, kapierrors.NewBadRequest(fmt.Sprintf("not a SubjectRulesReview: %#v", obj)) } namespace := kapi.NamespaceValue(ctx) if len(namespace) == 0 { return nil, kapierrors.NewBadRequest(fmt.Sprintf("namespace is required on this type: %v", namespace)) } userToCheck := &user.DefaultInfo{ Name: rulesReview.Spec.User, Groups: rulesReview.Spec.Groups, Extra: map[string][]string{}, } if len(rulesReview.Spec.Scopes) > 0 { userToCheck.Extra[authorizationapi.ScopesKey] = rulesReview.Spec.Scopes } rules, errors := GetEffectivePolicyRules(kapi.WithUser(ctx, userToCheck), r.ruleResolver, r.clusterPolicyGetter) ret := &authorizationapi.SubjectRulesReview{ Status: authorizationapi.SubjectRulesReviewStatus{ Rules: rules, }, } if len(errors) != 0 { ret.Status.EvaluationError = kutilerrors.NewAggregate(errors).Error() } return ret, nil }
// Update scales the DeploymentConfig for the given Scale subresource, returning the updated Scale. func (r *ScaleREST) Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bool, error) { if obj == nil { return nil, false, errors.NewBadRequest(fmt.Sprintf("nil update passed to Scale")) } scale, ok := obj.(*extensions.Scale) if !ok { return nil, false, errors.NewBadRequest(fmt.Sprintf("wrong object passed to Scale update: %v", obj)) } // fake an existing object to validate existing := &extensions.Scale{ ObjectMeta: kapi.ObjectMeta{ Name: scale.Name, CreationTimestamp: scale.CreationTimestamp, }, } if existing.Namespace, ok = kapi.NamespaceFrom(ctx); !ok { existing.Namespace = scale.Namespace } if errs := extvalidation.ValidateScaleUpdate(scale, existing); len(errs) > 0 { return nil, false, errors.NewInvalid("scale", scale.Name, errs) } deploymentConfig, err := r.registry.GetDeploymentConfig(ctx, scale.Name) if err != nil { return nil, false, errors.NewNotFound("scale", scale.Name) } scaleRet := &extensions.Scale{ ObjectMeta: kapi.ObjectMeta{ Name: deploymentConfig.Name, Namespace: deploymentConfig.Namespace, CreationTimestamp: deploymentConfig.CreationTimestamp, }, Spec: extensions.ScaleSpec{ Replicas: scale.Spec.Replicas, }, Status: extensions.ScaleStatus{ Selector: deploymentConfig.Spec.Selector, }, } // TODO(directxman12): this is going to be a bit out of sync, since we are calculating it // here and not as part of the deploymentconfig loop -- is there a better way of doing it? totalReplicas, err := r.replicasForDeploymentConfig(deploymentConfig.Namespace, deploymentConfig.Name) if err != nil { return nil, false, err } oldReplicas := deploymentConfig.Spec.Replicas deploymentConfig.Spec.Replicas = scale.Spec.Replicas if err := r.registry.UpdateDeploymentConfig(ctx, deploymentConfig); err != nil { return nil, false, err } scaleRet.Status.Replicas = totalReplicas + (scale.Spec.Replicas - oldReplicas) return scaleRet, false, nil }
func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) { if obj == nil { return nil, false, errors.NewBadRequest(fmt.Sprintf("nil update passed to Scale")) } scale, ok := obj.(*extensions.Scale) if !ok { return nil, false, errors.NewBadRequest(fmt.Sprintf("wrong object passed to Scale update: %v", obj)) } if errs := extvalidation.ValidateScale(scale); len(errs) > 0 { return nil, false, errors.NewInvalid(extensions.Kind("Scale"), scale.Name, errs) } rc, err := (*r.registry).GetController(ctx, scale.Name) if err != nil { return nil, false, errors.NewNotFound(extensions.Resource("replicationcontrollers/scale"), scale.Name) } rc.Spec.Replicas = scale.Spec.Replicas rc.ResourceVersion = scale.ResourceVersion rc, err = (*r.registry).UpdateController(ctx, rc) if err != nil { return nil, false, errors.NewConflict(extensions.Resource("replicationcontrollers/scale"), scale.Name, err) } return scaleFromRC(rc), false, nil }
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 }
// Create registers a given new PodSecurityPolicyReview instance to r.registry. func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { pspr, ok := obj.(*securityapi.PodSecurityPolicyReview) if !ok { return nil, kapierrors.NewBadRequest(fmt.Sprintf("not a PodSecurityPolicyReview: %#v", obj)) } if errs := securityvalidation.ValidatePodSecurityPolicyReview(pspr); len(errs) > 0 { return nil, kapierrors.NewInvalid(kapi.Kind("PodSecurityPolicyReview"), "", errs) } ns, ok := kapi.NamespaceFrom(ctx) if !ok { return nil, kapierrors.NewBadRequest("namespace parameter required.") } serviceAccounts, err := getServiceAccounts(pspr.Spec, r.saCache, ns) if err != nil { return nil, kapierrors.NewBadRequest(err.Error()) } if len(serviceAccounts) == 0 { glog.Errorf("No service accounts for namespace %s", ns) return nil, kapierrors.NewBadRequest(fmt.Sprintf("unable to find ServiceAccount for namespace: %s", ns)) } errs := []error{} newStatus := securityapi.PodSecurityPolicyReviewStatus{} for _, sa := range serviceAccounts { userInfo := serviceaccount.UserInfo(ns, sa.Name, "") saConstraints, err := r.sccMatcher.FindApplicableSCCs(userInfo) if err != nil { errs = append(errs, fmt.Errorf("unable to find SecurityContextConstraints for ServiceAccount %s: %v", sa.Name, err)) continue } oscc.DeduplicateSecurityContextConstraints(saConstraints) sort.Sort(oscc.ByPriority(saConstraints)) var namespace *kapi.Namespace for _, constraint := range saConstraints { var ( provider kscc.SecurityContextConstraintsProvider err error ) pspsrs := securityapi.PodSecurityPolicySubjectReviewStatus{} if provider, namespace, err = oscc.CreateProviderFromConstraint(ns, namespace, constraint, r.client); err != nil { errs = append(errs, fmt.Errorf("unable to create provider for service account %s: %v", sa.Name, err)) continue } _, err = podsecuritypolicysubjectreview.FillPodSecurityPolicySubjectReviewStatus(&pspsrs, provider, pspr.Spec.Template.Spec, constraint) if err != nil { glog.Errorf("unable to fill PodSecurityPolicyReviewStatus from constraint %v", err) continue } sapsprs := securityapi.ServiceAccountPodSecurityPolicyReviewStatus{pspsrs, sa.Name} newStatus.AllowedServiceAccounts = append(newStatus.AllowedServiceAccounts, sapsprs) } } if len(errs) > 0 { return nil, kapierrors.NewBadRequest(fmt.Sprintf("%s", kerrors.NewAggregate(errs))) } pspr.Status = newStatus return pspr, nil }
// LogLocation returns the log URL for a pod container. If opts.Container is blank // and only one container is present in the pod, that container is used. func LogLocation(getter ResourceGetter, connInfo client.ConnectionInfoGetter, ctx api.Context, name string, opts *api.PodLogOptions) (*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 a container was provided, it must be valid container := opts.Container if len(container) == 0 { 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)) } } else { if !podHasContainerWithName(pod, container) { return nil, nil, errors.NewBadRequest(fmt.Sprintf("container %s is not valid for pod %s", container, name)) } } nodeHost := pod.Spec.NodeName if len(nodeHost) == 0 { // If pod has not been assigned a host, return an empty location return nil, nil, nil } nodeScheme, nodePort, nodeTransport, err := connInfo.GetConnectionInfo(nodeHost) if err != nil { return nil, nil, err } params := url.Values{} if opts.Follow { params.Add("follow", "true") } if opts.Previous { params.Add("previous", "true") } if opts.Timestamps { params.Add("timestamps", "true") } if opts.SinceSeconds != nil { params.Add("sinceSeconds", strconv.FormatInt(*opts.SinceSeconds, 10)) } if opts.SinceTime != nil { params.Add("sinceTime", opts.SinceTime.Format(time.RFC3339)) } if opts.TailLines != nil { params.Add("tailLines", strconv.FormatInt(*opts.TailLines, 10)) } if opts.LimitBytes != nil { params.Add("limitBytes", strconv.FormatInt(*opts.LimitBytes, 10)) } loc := &url.URL{ Scheme: nodeScheme, Host: fmt.Sprintf("%s:%d", nodeHost, nodePort), Path: fmt.Sprintf("/containerLogs/%s/%s/%s", pod.Namespace, pod.Name, container), RawQuery: params.Encode(), } return loc, nodeTransport, nil }
func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { istag, ok := obj.(*imageapi.ImageStreamTag) if !ok { return nil, kapierrors.NewBadRequest(fmt.Sprintf("obj is not an ImageStreamTag: %#v", obj)) } if err := rest.BeforeCreate(Strategy, ctx, obj); err != nil { return nil, err } namespace, ok := kapi.NamespaceFrom(ctx) if !ok { return nil, kapierrors.NewBadRequest("a namespace must be specified to import images") } imageStreamName, imageTag, ok := imageapi.SplitImageStreamTag(istag.Name) if !ok { return nil, fmt.Errorf("%q must be of the form <stream_name>:<tag>", istag.Name) } target, err := r.imageStreamRegistry.GetImageStream(ctx, imageStreamName) if err != nil { if !kapierrors.IsNotFound(err) { return nil, err } // try to create the target if it doesn't exist target = &imageapi.ImageStream{ ObjectMeta: kapi.ObjectMeta{ Name: imageStreamName, Namespace: namespace, }, } } if target.Spec.Tags == nil { target.Spec.Tags = make(map[string]imageapi.TagReference) } // The user wants to symlink a tag. _, exists := target.Spec.Tags[imageTag] if exists { return nil, kapierrors.NewAlreadyExists(imageapi.Resource("imagestreamtag"), istag.Name) } target.Spec.Tags[imageTag] = *istag.Tag // Check the stream creation timestamp and make sure we will not // create a new image stream while deleting. if target.CreationTimestamp.IsZero() { _, err = r.imageStreamRegistry.CreateImageStream(ctx, target) } else { _, err = r.imageStreamRegistry.UpdateImageStream(ctx, target) } if err != nil { return nil, err } return istag, nil }
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 a container was provided, it must be valid if container == "" { switch len(pod.Spec.Containers) { case 1: container = pod.Spec.Containers[0].Name case 0: return nil, nil, errors.NewBadRequest(fmt.Sprintf("a container name must be specified for pod %s", name)) default: containerNames := getContainerNames(pod.Spec.Containers) initContainerNames := getContainerNames(pod.Spec.InitContainers) err := fmt.Sprintf("a container name must be specified for pod %s, choose one of: [%s]", name, containerNames) if len(initContainerNames) > 0 { err += fmt.Sprintf(" or one of the init containers: [%s]", initContainerNames) } return nil, nil, errors.NewBadRequest(err) } } else { if !podHasContainerWithName(pod, container) { return nil, nil, errors.NewBadRequest(fmt.Sprintf("container %s is not valid for pod %s", container, name)) } } nodeName := types.NodeName(pod.Spec.NodeName) if len(nodeName) == 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)) } nodeInfo, err := connInfo.GetConnectionInfo(ctx, nodeName) 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: nodeInfo.Scheme, Host: net.JoinHostPort(nodeInfo.Hostname, nodeInfo.Port), Path: fmt.Sprintf("/%s/%s/%s/%s", path, pod.Namespace, pod.Name, container), RawQuery: params.Encode(), } return loc, nodeInfo.Transport, nil }
// Instantiate returns a new Build object based on a BuildRequest object func (g *BuildGenerator) Instantiate(ctx kapi.Context, request *buildapi.BuildRequest) (*buildapi.Build, error) { glog.V(4).Infof("Generating Build from %s", describeBuildRequest(request)) bc, err := g.Client.GetBuildConfig(ctx, request.Name) if err != nil { return nil, err } if buildutil.IsPaused(bc) { return nil, errors.NewBadRequest(fmt.Sprintf("can't instantiate from BuildConfig %s/%s: BuildConfig is paused", bc.Namespace, bc.Name)) } if err := g.checkLastVersion(bc, request.LastVersion); err != nil { return nil, errors.NewBadRequest(err.Error()) } if err := g.updateImageTriggers(ctx, bc, request.From, request.TriggeredByImage); err != nil { if _, ok := err.(errors.APIStatus); ok { return nil, err } return nil, errors.NewInternalError(err) } newBuild, err := g.generateBuildFromConfig(ctx, bc, request.Revision, request.Binary) if err != nil { if _, ok := err.(errors.APIStatus); ok { return nil, err } return nil, errors.NewInternalError(err) } // Add labels and annotations from the buildrequest. Existing // label/annotations will take precedence because we don't want system // annotations/labels (eg buildname) to get stomped on. newBuild.Annotations = policy.MergeMaps(request.Annotations, newBuild.Annotations) newBuild.Labels = policy.MergeMaps(request.Labels, newBuild.Labels) // Copy build trigger information to the build object. newBuild.Spec.TriggeredBy = request.TriggeredBy if len(request.Env) > 0 { updateBuildEnv(&newBuild.Spec.Strategy, request.Env) } glog.V(4).Infof("Build %s/%s has been generated from %s/%s BuildConfig", newBuild.Namespace, newBuild.ObjectMeta.Name, bc.Namespace, bc.ObjectMeta.Name) // need to update the BuildConfig because LastVersion and possibly // LastTriggeredImageID changed if err := g.Client.UpdateBuildConfig(ctx, bc); err != nil { glog.V(4).Infof("Failed to update BuildConfig %s/%s so no Build will be created", bc.Namespace, bc.Name) return nil, err } // Ideally we would create the build *before* updating the BC to ensure // that we don't set the LastTriggeredImageID on the BC and then fail to // create the corresponding build, however doing things in that order // allows for a race condition in which two builds get kicked off. Doing // it in this order ensures that we catch the race while updating the BC. return g.createBuild(ctx, newBuild) }
// NoNamespaceKeyFunc is the default function for constructing etcd paths to a resource relative to prefix enforcing // If a namespace is on context, it errors. func NoNamespaceKeyFunc(ctx kapi.Context, prefix string, name string) (string, error) { ns, ok := kapi.NamespaceFrom(ctx) if ok && len(ns) > 0 { return "", kerrors.NewBadRequest("Namespace parameter is not allowed.") } if len(name) == 0 { return "", kerrors.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, gvk *unversioned.GroupVersionKind) error { objGVK, err := typer.ObjectKind(into) if err != nil { return err } if gvk != nil && len(gvk.Kind) > 0 { return errors.NewBadRequest(fmt.Sprintf("%s in version %q cannot be handled as a %s: %v", gvk.Kind, gvk.Version, objGVK.Kind, baseErr)) } return errors.NewBadRequest(fmt.Sprintf("the object provided is unrecognized (must be of type %s): %v", objGVK.Kind, baseErr)) }
// NoNamespaceKeyFunc is the default function for constructing storage paths to a resource relative to prefix without a namespace func NoNamespaceKeyFunc(ctx api.Context, prefix string, name string) (string, error) { if len(name) == 0 { return "", kubeerr.NewBadRequest("Name parameter required.") } if msgs := validation.IsValidPathSegmentName(name); len(msgs) != 0 { return "", kubeerr.NewBadRequest(fmt.Sprintf("Name parameter invalid: %q: %s", name, strings.Join(msgs, ";"))) } key := prefix + "/" + name return key, nil }
// NoNamespaceKeyFunc is the default function for constructing etcd paths to a resource relative to prefix without a namespace func NoNamespaceKeyFunc(ctx api.Context, prefix string, name string) (string, error) { if len(name) == 0 { return "", kubeerr.NewBadRequest("Name parameter required.") } if ok, msg := validation.IsValidPathSegmentName(name); !ok { return "", kubeerr.NewBadRequest(fmt.Sprintf("Name parameter invalid: %v.", msg)) } key := prefix + "/" + name return key, 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)) }
// Create registers a given new PodSecurityPolicySubjectReview instance to r.registry. func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { pspsr, ok := obj.(*securityapi.PodSecurityPolicySubjectReview) if !ok { return nil, kapierrors.NewBadRequest(fmt.Sprintf("not a PodSecurityPolicySubjectReview: %#v", obj)) } ns, ok := kapi.NamespaceFrom(ctx) if !ok { return nil, kapierrors.NewBadRequest("namespace parameter required.") } if errs := securityvalidation.ValidatePodSecurityPolicySubjectReview(pspsr); len(errs) > 0 { return nil, kapierrors.NewInvalid(kapi.Kind("PodSecurityPolicySubjectReview"), "", errs) } userInfo := &user.DefaultInfo{Name: pspsr.Spec.User, Groups: pspsr.Spec.Groups} matchedConstraints, err := r.sccMatcher.FindApplicableSCCs(userInfo) if err != nil { return nil, kapierrors.NewBadRequest(fmt.Sprintf("unable to find SecurityContextConstraints: %v", err)) } saName := pspsr.Spec.Template.Spec.ServiceAccountName if len(saName) > 0 { saUserInfo := serviceaccount.UserInfo(ns, saName, "") saConstraints, err := r.sccMatcher.FindApplicableSCCs(saUserInfo) if err != nil { return nil, kapierrors.NewBadRequest(fmt.Sprintf("unable to find SecurityContextConstraints: %v", err)) } matchedConstraints = append(matchedConstraints, saConstraints...) } oscc.DeduplicateSecurityContextConstraints(matchedConstraints) sort.Sort(oscc.ByPriority(matchedConstraints)) var namespace *kapi.Namespace for _, constraint := range matchedConstraints { var ( provider kscc.SecurityContextConstraintsProvider err error ) if provider, namespace, err = oscc.CreateProviderFromConstraint(ns, namespace, constraint, r.client); err != nil { glog.Errorf("Unable to create provider for constraint: %v", err) continue } filled, err := FillPodSecurityPolicySubjectReviewStatus(&pspsr.Status, provider, pspsr.Spec.Template.Spec, constraint) if err != nil { glog.Errorf("unable to fill PodSecurityPolicySubjectReviewStatus from constraint %v", err) continue } if filled { return pspsr, nil } } return pspsr, 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, kapierrors.NewBadRequest(fmt.Sprintf("not a subjectAccessReview: %#v", obj)) } if err := kutilerrors.NewAggregate(authorizationvalidation.ValidateSubjectAccessReview(subjectAccessReview)); err != nil { return nil, err } // if a namespace is present on the request, then the namespace on the on the SAR is overwritten. // This is to support backwards compatibility. To have gotten here in this state, it means that // the authorizer decided that a user could run an SAR against this namespace if namespace := kapi.NamespaceValue(ctx); len(namespace) > 0 { subjectAccessReview.Action.Namespace = namespace } else if err := r.isAllowed(ctx, subjectAccessReview); err != nil { // this check is mutually exclusive to the condition above. localSAR and localRAR both clear the namespace before delegating their calls // We only need to check if the SAR is allowed **again** if the authorizer didn't already approve the request for a legacy call. 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, kapierrors.NewBadRequest("user missing from context") } userToCheck = ctxUser } else { userToCheck = &user.DefaultInfo{ Name: subjectAccessReview.User, Groups: subjectAccessReview.Groups.List(), } } requestContext := kapi.WithNamespace(kapi.WithUser(ctx, userToCheck), subjectAccessReview.Action.Namespace) attributes := authorizer.ToDefaultAuthorizationAttributes(subjectAccessReview.Action) allowed, reason, err := r.authorizer.Authorize(requestContext, attributes) if err != nil { return nil, err } response := &authorizationapi.SubjectAccessReviewResponse{ Namespace: subjectAccessReview.Action.Namespace, Allowed: allowed, Reason: reason, } return response, nil }
// transformDecodeError adds additional information when a decode fails. func transformDecodeError(typer runtime.ObjectTyper, baseErr error, into runtime.Object, gvk *unversioned.GroupVersionKind, body []byte) error { objGVKs, _, err := typer.ObjectKinds(into) if err != nil { return err } objGVK := objGVKs[0] if gvk != nil && len(gvk.Kind) > 0 { return errors.NewBadRequest(fmt.Sprintf("%s in version %q cannot be handled as a %s: %v", gvk.Kind, gvk.Version, objGVK.Kind, baseErr)) } summary := summarizeData(body, 30) return errors.NewBadRequest(fmt.Sprintf("the object provided is unrecognized (must be of type %s): %v (%s)", objGVK.Kind, baseErr, summary)) }
// 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 }
// Create generates a new DeploymentConfig representing a rollback. func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { namespace, ok := kapi.NamespaceFrom(ctx) if !ok { return nil, kerrors.NewBadRequest("namespace parameter required.") } rollback, ok := obj.(*deployapi.DeploymentConfigRollback) if !ok { return nil, kerrors.NewBadRequest(fmt.Sprintf("not a rollback spec: %#v", obj)) } if errs := validation.ValidateDeploymentConfigRollback(rollback); len(errs) > 0 { return nil, kerrors.NewInvalid(deployapi.Kind("DeploymentConfigRollback"), rollback.Name, errs) } from, err := r.dn.DeploymentConfigs(namespace).Get(rollback.Name) if err != nil { return nil, newInvalidError(rollback, fmt.Sprintf("cannot get deployment config %q: %v", rollback.Name, err)) } switch from.Status.LatestVersion { case 0: return nil, newInvalidError(rollback, "cannot rollback an undeployed config") case 1: return nil, newInvalidError(rollback, fmt.Sprintf("no previous deployment exists for %q", deployutil.LabelForDeploymentConfig(from))) } revision := from.Status.LatestVersion - 1 if rollback.Spec.Revision > 0 { revision = rollback.Spec.Revision } // Find the target deployment and decode its config. name := deployutil.DeploymentNameForConfigVersion(from.Name, revision) targetDeployment, err := r.rn.ReplicationControllers(namespace).Get(name) if err != nil { return nil, newInvalidError(rollback, err.Error()) } to, err := deployutil.DecodeDeploymentConfig(targetDeployment, r.codec) if err != nil { return nil, newInvalidError(rollback, fmt.Sprintf("couldn't decode deployment config from deployment: %v", err)) } if from.Annotations == nil && len(rollback.UpdatedAnnotations) > 0 { from.Annotations = make(map[string]string) } for key, value := range rollback.UpdatedAnnotations { from.Annotations[key] = value } return r.generator.GenerateRollback(from, to, &rollback.Spec) }
// 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 = kapierrors.NewBadRequest("ImageStreamTags must be retrieved with <name>:<tag>") } default: err = kapierrors.NewBadRequest("ImageStreamTags must be retrieved with <name>:<tag>") } return }