func (l *lifecycle) Admit(a admission.Attributes) (err error) { // prevent deletion of immortal namespaces if a.GetOperation() == admission.Delete && a.GetKind().GroupKind() == api.Kind("Namespace") && l.immortalNamespaces.Has(a.GetName()) { return errors.NewForbidden(a.GetResource().GroupResource(), a.GetName(), fmt.Errorf("this namespace may not be deleted")) } // if we're here, then we've already passed authentication, so we're allowed to do what we're trying to do // if we're here, then the API server has found a route, which means that if we have a non-empty namespace // its a namespaced resource. if len(a.GetNamespace()) == 0 || a.GetKind().GroupKind() == api.Kind("Namespace") { // if a namespace is deleted, we want to prevent all further creates into it // while it is undergoing termination. to reduce incidences where the cache // is slow to update, we forcefully remove the namespace from our local cache. // this will cause a live lookup of the namespace to get its latest state even // before the watch notification is received. if a.GetOperation() == admission.Delete { l.store.Delete(&api.Namespace{ ObjectMeta: api.ObjectMeta{ Name: a.GetName(), }, }) } return nil } namespaceObj, exists, err := l.store.Get(&api.Namespace{ ObjectMeta: api.ObjectMeta{ Name: a.GetNamespace(), Namespace: "", }, }) if err != nil { return errors.NewInternalError(err) } // refuse to operate on non-existent namespaces if !exists { // in case of latency in our caches, make a call direct to storage to verify that it truly exists or not namespaceObj, err = l.client.Core().Namespaces().Get(a.GetNamespace()) if err != nil { if errors.IsNotFound(err) { return err } return errors.NewInternalError(err) } } // ensure that we're not trying to create objects in terminating namespaces if a.GetOperation() == admission.Create { namespace := namespaceObj.(*api.Namespace) if namespace.Status.Phase != api.NamespaceTerminating { return nil } // TODO: This should probably not be a 403 return admission.NewForbidden(a, fmt.Errorf("Unable to create new content in namespace %s because it is being terminated.", a.GetNamespace())) } return nil }
func (e *exists) Admit(a admission.Attributes) (err error) { // if we're here, then we've already passed authentication, so we're allowed to do what we're trying to do // if we're here, then the API server has found a route, which means that if we have a non-empty namespace // its a namespaced resource. if len(a.GetNamespace()) == 0 || a.GetKind().GroupKind() == api.Kind("Namespace") { return nil } namespace := &api.Namespace{ ObjectMeta: api.ObjectMeta{ Name: a.GetNamespace(), Namespace: "", }, Status: api.NamespaceStatus{}, } _, exists, err := e.store.Get(namespace) if err != nil { return errors.NewInternalError(err) } if exists { return nil } // in case of latency in our caches, make a call direct to storage to verify that it truly exists or not _, err = e.client.Core().Namespaces().Get(a.GetNamespace()) if err != nil { if errors.IsNotFound(err) { return err } return errors.NewInternalError(err) } return nil }
func (m *VirtualStorage) confirmNoEscalation(ctx kapi.Context, roleBinding *authorizationapi.RoleBinding) error { modifyingRole, err := m.getReferencedRole(roleBinding.RoleRef) if err != nil { return err } ruleResolver := rulevalidation.NewDefaultRuleResolver( m.PolicyRegistry, m.BindingRegistry, m.ClusterPolicyRegistry, m.ClusterPolicyBindingRegistry, ) ownerLocalRules, err := ruleResolver.GetEffectivePolicyRules(ctx) if err != nil { return kapierrors.NewInternalError(err) } masterContext := kapi.WithNamespace(ctx, "") ownerGlobalRules, err := ruleResolver.GetEffectivePolicyRules(masterContext) if err != nil { return kapierrors.NewInternalError(err) } ownerRules := make([]authorizationapi.PolicyRule, 0, len(ownerGlobalRules)+len(ownerLocalRules)) ownerRules = append(ownerRules, ownerLocalRules...) ownerRules = append(ownerRules, ownerGlobalRules...) ownerRightsCover, missingRights := rulevalidation.Covers(ownerRules, modifyingRole.Rules) if !ownerRightsCover { user, _ := kapi.UserFrom(ctx) return kapierrors.NewUnauthorized(fmt.Sprintf("attempt to grant extra privileges: %v user=%v ownerrules=%v", missingRights, user, ownerRules)) } return 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) }
// objectMetaAndKind retrieves kind and ObjectMeta from a runtime object, or returns an error. func objectMetaAndKind(typer runtime.ObjectTyper, obj runtime.Object) (*api.ObjectMeta, unversioned.GroupVersionKind, error) { objectMeta, err := api.ObjectMetaFor(obj) if err != nil { return nil, unversioned.GroupVersionKind{}, errors.NewInternalError(err) } kinds, _, err := typer.ObjectKinds(obj) if err != nil { return nil, unversioned.GroupVersionKind{}, errors.NewInternalError(err) } return objectMeta, kinds[0], nil }
// objectMetaAndKind retrieves kind and ObjectMeta from a runtime object, or returns an error. func objectMetaAndKind(typer runtime.ObjectTyper, obj runtime.Object) (*api.ObjectMeta, string, error) { objectMeta, err := api.ObjectMetaFor(obj) if err != nil { return nil, "", errors.NewInternalError(err) } _, kind, err := typer.ObjectVersionAndKind(obj) if err != nil { return nil, "", errors.NewInternalError(err) } return objectMeta, kind, nil }
func (l *lifecycle) Admit(a admission.Attributes) (err error) { // prevent deletion of immortal namespaces if a.GetOperation() == admission.Delete && a.GetKind() == "Namespace" && l.immortalNamespaces.Has(a.GetName()) { return errors.NewForbidden(a.GetKind(), a.GetName(), fmt.Errorf("this namespace may not be deleted")) } gvk, err := api.RESTMapper.KindFor(a.GetResource()) if err != nil { return errors.NewInternalError(err) } mapping, err := api.RESTMapper.RESTMapping(gvk.GroupKind(), gvk.Version) if err != nil { return errors.NewInternalError(err) } if mapping.Scope.Name() != meta.RESTScopeNameNamespace { return nil } namespaceObj, exists, err := l.store.Get(&api.Namespace{ ObjectMeta: api.ObjectMeta{ Name: a.GetNamespace(), Namespace: "", }, }) if err != nil { return errors.NewInternalError(err) } // refuse to operate on non-existent namespaces if !exists { // in case of latency in our caches, make a call direct to storage to verify that it truly exists or not namespaceObj, err = l.client.Namespaces().Get(a.GetNamespace()) if err != nil { if errors.IsNotFound(err) { return err } return errors.NewInternalError(err) } } // ensure that we're not trying to create objects in terminating namespaces if a.GetOperation() == admission.Create { namespace := namespaceObj.(*api.Namespace) if namespace.Status.Phase != api.NamespaceTerminating { return nil } // TODO: This should probably not be a 403 return admission.NewForbidden(a, fmt.Errorf("Unable to create new content in namespace %s because it is being terminated.", a.GetNamespace())) } return nil }
// TODO: add other common fields that require global validation. func validateCommonFields(obj, old runtime.Object) utilvalidation.ErrorList { allErrs := utilvalidation.ErrorList{} objectMeta, err := api.ObjectMetaFor(obj) if err != nil { return append(allErrs, errors.NewInternalError(err)) } oldObjectMeta, err := api.ObjectMetaFor(old) if err != nil { return append(allErrs, errors.NewInternalError(err)) } allErrs = append(allErrs, validation.ValidateObjectMetaUpdate(objectMeta, oldObjectMeta)...) return allErrs }
// Clone returns clone of a Build func (g *BuildGenerator) Clone(ctx kapi.Context, request *buildapi.BuildRequest) (*buildapi.Build, error) { glog.V(4).Infof("Generating build from build %s/%s", request.Namespace, request.Name) build, err := g.Client.GetBuild(ctx, request.Name) if err != nil { return nil, err } var buildConfig *buildapi.BuildConfig if build.Status.Config != nil { buildConfig, err = g.Client.GetBuildConfig(ctx, build.Status.Config.Name) if err != nil && !errors.IsNotFound(err) { return nil, err } if buildutil.IsPaused(buildConfig) { return nil, errors.NewInternalError(&GeneratorFatalError{fmt.Sprintf("can't instantiate from BuildConfig %s/%s: BuildConfig is paused", buildConfig.Namespace, buildConfig.Name)}) } } newBuild := generateBuildFromBuild(build, buildConfig) glog.V(4).Infof("Build %s/%s has been generated from Build %s/%s", newBuild.Namespace, newBuild.ObjectMeta.Name, build.Namespace, build.ObjectMeta.Name) // Copy build trigger information to the build object. newBuild.Spec.TriggeredBy = request.TriggeredBy // need to update the BuildConfig because LastVersion changed if buildConfig != nil { if err := g.Client.UpdateBuildConfig(ctx, buildConfig); err != nil { glog.V(4).Infof("Failed to update BuildConfig %s/%s so no Build will be created", buildConfig.Namespace, buildConfig.Name) return nil, err } } return g.createBuild(ctx, newBuild) }
// 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 } strategy.PrepareForUpdate(obj, old) // Ensure some common fields, like UID, are validated for all resources. errs, err := validateCommonFields(obj, old) if err != nil { return errors.NewInternalError(err) } errs = append(errs, strategy.ValidateUpdate(ctx, obj, old)...) if len(errs) > 0 { return errors.NewInvalid(kind.GroupKind(), objectMeta.Name, errs) } strategy.Canonicalize(obj) return nil }
func getAttrs(obj runtime.Object) (objLabels labels.Set, objFields fields.Set, err error) { event, ok := obj.(*api.Event) if !ok { return nil, nil, errors.NewInternalError(fmt.Errorf("object is not of type event: %#v", obj)) } l := event.Labels if l == nil { l = labels.Set{} } objectMetaFieldsSet := generic.ObjectMetaFieldsSet(event.ObjectMeta, true) specificFieldsSet := fields.Set{ "involvedObject.kind": event.InvolvedObject.Kind, "involvedObject.namespace": event.InvolvedObject.Namespace, "involvedObject.name": event.InvolvedObject.Name, "involvedObject.uid": string(event.InvolvedObject.UID), "involvedObject.apiVersion": event.InvolvedObject.APIVersion, "involvedObject.resourceVersion": event.InvolvedObject.ResourceVersion, "involvedObject.fieldPath": event.InvolvedObject.FieldPath, "reason": event.Reason, "source": event.Source.Component, "type": event.Type, } return l, generic.MergeFieldsSets(objectMetaFieldsSet, specificFieldsSet), nil }
// TestHandle_fatalError ensures that in internal (not API) failure to make a // deployment from an updated config results in a fatal error. func TestHandle_fatalError(t *testing.T) { configController := &DeploymentConfigController{ makeDeployment: func(config *deployapi.DeploymentConfig) (*kapi.ReplicationController, error) { return nil, fmt.Errorf("couldn't make deployment") }, deploymentClient: &deploymentClientImpl{ createDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) { t.Fatalf("unexpected call to create") return nil, kerrors.NewInternalError(fmt.Errorf("test error")) }, listDeploymentsForConfigFunc: func(namespace, configName string) (*kapi.ReplicationControllerList, error) { return &kapi.ReplicationControllerList{}, nil }, updateDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) { t.Fatalf("unexpected update call with deployment %v", deployment) return nil, nil }, }, osClient: testclient.NewSimpleFake(deploytest.OkDeploymentConfig(1)), } err := configController.Handle(deploytest.OkDeploymentConfig(1)) if err == nil { t.Fatalf("expected error") } if _, isFatal := err.(fatalError); !isFatal { t.Fatalf("expected a fatal error, got: %v", err) } }
// TestHandle_nonfatalLookupError ensures that an API failure to look up the // existing deployment for an updated config results in a nonfatal error. func TestHandle_nonfatalLookupError(t *testing.T) { configController := &DeploymentConfigController{ makeDeployment: func(config *deployapi.DeploymentConfig) (*kapi.ReplicationController, error) { return deployutil.MakeDeployment(config, api.Codec) }, deploymentClient: &deploymentClientImpl{ createDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) { t.Fatalf("unexpected call with deployment %v", deployment) return nil, nil }, listDeploymentsForConfigFunc: func(namespace, configName string) (*kapi.ReplicationControllerList, error) { return nil, kerrors.NewInternalError(fmt.Errorf("fatal test error")) }, updateDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) { t.Fatalf("unexpected update call with deployment %v", deployment) return nil, nil }, }, osClient: testclient.NewSimpleFake(), } err := configController.Handle(deploytest.OkDeploymentConfig(1)) if err == nil { t.Fatalf("expected error") } if _, isFatal := err.(fatalError); isFatal { t.Fatalf("expected a retryable error, got a fatal error: %v", err) } }
func TestCreateGeneratorErrorDepr(t *testing.T) { rest := DeprecatedREST{ generator: Client{ GRFn: func(from, to *deployapi.DeploymentConfig, spec *deployapi.DeploymentConfigRollbackSpec) (*deployapi.DeploymentConfig, error) { return nil, kerrors.NewInternalError(fmt.Errorf("something terrible happened")) }, RCFn: func(ctx kapi.Context, name string) (*kapi.ReplicationController, error) { deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion)) return deployment, nil }, DCFn: func(ctx kapi.Context, name string) (*deployapi.DeploymentConfig, error) { return deploytest.OkDeploymentConfig(1), nil }, }, codec: kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion), } _, err := rest.Create(kapi.NewDefaultContext(), &deployapi.DeploymentConfigRollback{ Spec: deployapi.DeploymentConfigRollbackSpec{ From: kapi.ObjectReference{ Name: "deployment", Namespace: kapi.NamespaceDefault, }, }, }) if err == nil || !strings.Contains(err.Error(), "something terrible happened") { t.Errorf("Unexpected error: %v", err) } }
// NewNotFound is a utility function to return a well-formatted admission control error response func NewNotFound(a Attributes) error { name, resource, err := extractResourceName(a) if err != nil { return apierrors.NewInternalError(err) } return apierrors.NewNotFound(resource, name) }
// NewNotFound is a utility function to return a well-formatted admission control error response func NewNotFound(a Attributes) error { name, kind, err := extractKindName(a) if err != nil { return apierrors.NewInternalError(err) } return apierrors.NewNotFound(kind.Kind, name) }
// extract the PodSpec from the pod templates for each object we care about func (o *podNodeConstraints) getPodSpec(attr admission.Attributes) (kapi.PodSpec, error) { switch r := attr.GetObject().(type) { case *kapi.Pod: return r.Spec, nil case *kapi.PodTemplate: return r.Template.Spec, nil case *kapi.ReplicationController: return r.Spec.Template.Spec, nil case *extensions.Deployment: return r.Spec.Template.Spec, nil case *extensions.ReplicaSet: return r.Spec.Template.Spec, nil case *batch.Job: return r.Spec.Template.Spec, nil case *batch.ScheduledJob: return r.Spec.JobTemplate.Spec.Template.Spec, nil case *batch.JobTemplate: return r.Template.Spec.Template.Spec, nil case *deployapi.DeploymentConfig: return r.Spec.Template.Spec, nil case *securityapi.PodSecurityPolicySubjectReview: return r.Spec.PodSpec, nil case *securityapi.PodSecurityPolicySelfSubjectReview: return r.Spec.PodSpec, nil case *securityapi.PodSecurityPolicyReview: return r.Spec.PodSpec, nil } return kapi.PodSpec{}, kapierrors.NewInternalError(fmt.Errorf("No PodSpec available for supplied admission attribute")) }
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 }
// TestHandle_cleanupPodFail ensures that a failed attempt to clean up the // deployer pod for a completed deployment results in an actionable error. func TestHandle_cleanupPodFail(t *testing.T) { fake := &ktestclient.Fake{} fake.AddReactor("delete", "pods", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { return true, nil, kerrors.NewInternalError(fmt.Errorf("deployer pod internal error")) }) fake.AddReactor("create", "pods", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { t.Fatalf("unexpected call to create pod") return true, nil, nil }) fake.AddReactor("update", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { t.Fatalf("unexpected deployment update") return true, nil, nil }) // Verify error config := deploytest.OkDeploymentConfig(1) deployment, _ := deployutil.MakeDeployment(config, codec) deployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(deployapi.DeploymentStatusComplete) controller := okDeploymentController(fake, deployment, nil, true) err := controller.Handle(deployment) if err == nil { t.Fatal("expected an actionable error") } if _, isActionable := err.(actionableError); !isActionable { t.Fatalf("expected an actionable error, got %#v", err) } }
// extract the PodSpec from the pod templates for each object we care about func (o *podNodeConstraints) getPodSpec(attr admission.Attributes) (kapi.PodSpec, error) { spec, _, err := meta.GetPodSpec(attr.GetObject()) if err != nil { return kapi.PodSpec{}, kapierrors.NewInternalError(err) } return *spec, nil }
// Create instantiates a deployment config func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { req, ok := obj.(*deployapi.DeploymentRequest) if !ok { return nil, errors.NewInternalError(fmt.Errorf("wrong object passed for requesting a new rollout: %#v", obj)) } configObj, err := r.store.Get(ctx, req.Name) if err != nil { return nil, err } config := configObj.(*deployapi.DeploymentConfig) old := config if errs := validation.ValidateRequestForDeploymentConfig(req, config); len(errs) > 0 { return nil, errors.NewInvalid(deployapi.Kind("DeploymentRequest"), req.Name, errs) } // We need to process the deployment config before we can determine if it is possible to trigger // a deployment. if req.Latest { if err := processTriggers(config, r.isn, req.Force); err != nil { return nil, err } } canTrigger, causes, err := canTrigger(config, r.rn, r.decoder, req.Force) if err != nil { return nil, err } // If we cannot trigger then there is nothing to do here. if !canTrigger { return &unversioned.Status{ Message: fmt.Sprintf("deployment config %q cannot be instantiated", config.Name), Code: int32(204), }, nil } glog.V(4).Infof("New deployment for %q caused by %#v", config.Name, causes) config.Status.Details = new(deployapi.DeploymentDetails) config.Status.Details.Causes = causes switch causes[0].Type { case deployapi.DeploymentTriggerOnConfigChange: config.Status.Details.Message = "config change" case deployapi.DeploymentTriggerOnImageChange: config.Status.Details.Message = "image change" case deployapi.DeploymentTriggerManual: config.Status.Details.Message = "manual change" } config.Status.LatestVersion++ userInfo, _ := kapi.UserFrom(ctx) attrs := admission.NewAttributesRecord(config, old, deployapi.Kind("DeploymentConfig").WithVersion(""), config.Namespace, config.Name, deployapi.Resource("DeploymentConfig").WithVersion(""), "", admission.Update, userInfo) if err := r.admit.Admit(attrs); err != nil { return nil, err } updated, _, err := r.store.Update(ctx, config.Name, rest.DefaultUpdatedObjectInfo(config, kapi.Scheme)) return updated, err }
// transformResponse converts an API response into a structured API object func (r *Request) transformResponse(resp *http.Response, req *http.Request) Result { var body []byte if resp.Body != nil { if data, err := ioutil.ReadAll(resp.Body); err == nil { body = data } } glogBody("Response Body", body) // verify the content type is accurate contentType := resp.Header.Get("Content-Type") decoder := r.serializers.Decoder if len(contentType) > 0 && (decoder == nil || (len(r.content.ContentType) > 0 && contentType != r.content.ContentType)) { mediaType, params, err := mime.ParseMediaType(contentType) if err != nil { return Result{err: errors.NewInternalError(err)} } decoder, err = r.serializers.RenegotiatedDecoder(mediaType, params) if err != nil { // if we fail to negotiate a decoder, treat this as an unstructured error switch { case resp.StatusCode == http.StatusSwitchingProtocols: // no-op, we've been upgraded case resp.StatusCode < http.StatusOK || resp.StatusCode > http.StatusPartialContent: return Result{err: r.transformUnstructuredResponseError(resp, req, body)} } return Result{ body: body, contentType: contentType, statusCode: resp.StatusCode, } } } switch { case resp.StatusCode == http.StatusSwitchingProtocols: // no-op, we've been upgraded case resp.StatusCode < http.StatusOK || resp.StatusCode > http.StatusPartialContent: // calculate an unstructured error from the response which the Result object may use if the caller // did not return a structured error. retryAfter, _ := retryAfterSeconds(resp) err := r.newUnstructuredResponseError(body, isTextResponse(resp), resp.StatusCode, req.Method, retryAfter) return Result{ body: body, contentType: contentType, statusCode: resp.StatusCode, decoder: decoder, err: err, } } return Result{ body: body, contentType: contentType, statusCode: resp.StatusCode, decoder: decoder, } }
// ServeHTTP implements rest.HookHandler func (w *WebHook) ServeHTTP(writer 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 := w.plugins[hookType] if !ok { return errors.NewNotFound(buildapi.Resource("buildconfighook"), hookType) } config, err := w.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, envvars, proceed, err := plugin.Extract(config, secret, "", req) if !proceed { 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 webhook.MethodNotSupported: return errors.NewMethodNotSupported(buildapi.Resource("buildconfighook"), req.Method) } if _, ok := err.(*errors.StatusError); !ok && err != nil { return errors.NewInternalError(fmt.Errorf("hook failed: %v", err)) } return err } warning := err buildTriggerCauses := generateBuildTriggerInfo(revision, hookType, secret) request := &buildapi.BuildRequest{ TriggeredBy: buildTriggerCauses, ObjectMeta: kapi.ObjectMeta{Name: name}, Revision: revision, Env: envvars, } if _, err := w.instantiator.Instantiate(config.Namespace, request); err != nil { return errors.NewInternalError(fmt.Errorf("could not generate a build: %v", err)) } return warning }
func TestApplyRetryWithSMPatchVersion_1_5(t *testing.T) { initTestErrorHandler(t) nameRC, currentRC := readAndSetFinalizersReplicationController(t, filenameRC) pathRC := "/namespaces/test/replicationcontrollers/" + nameRC firstPatch := true retry := false f, tf, _, ns := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.Client = &fake.RESTClient{ NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { case p == pathRC && m == "GET": bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC)) return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil case p == pathRC && m == "PATCH": if firstPatch { if !isSMPatchVersion_1_5(t, req) { t.Fatalf("apply didn't try to send SMPatchVersion_1_5 for the first time") } firstPatch = false statusErr := kubeerr.NewInternalError(fmt.Errorf("Server encountered internal error.")) bodyBytes, _ := json.Marshal(statusErr) bodyErr := ioutil.NopCloser(bytes.NewReader(bodyBytes)) return &http.Response{StatusCode: http.StatusInternalServerError, Header: defaultHeader(), Body: bodyErr}, nil } retry = true if isSMPatchVersion_1_5(t, req) { t.Fatalf("apply didn't try to send SMPatchVersion_1_0 after SMPatchVersion_1_5 patch encounter an Internal Error (500)") } bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC)) return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil default: t.Fatalf("unexpected request: %#v\n%#v", req.URL, req) return nil, nil } }), } tf.Namespace = "test" tf.ClientConfig = defaultClientConfig() buf := bytes.NewBuffer([]byte{}) cmd := NewCmdApply(f, buf) cmd.Flags().Set("filename", filenameRC) cmd.Flags().Set("output", "name") cmd.Run(cmd, []string{}) if !retry { t.Fatalf("apply didn't retry when get Internal Error (500)") } // uses the name from the file, not the response expectRC := "replicationcontroller/" + nameRC + "\n" if buf.String() != expectRC { t.Fatalf("unexpected output: %s\nexpected: %s", buf.String(), expectRC) } }
func (s routeStrategy) PrepareForCreate(ctx kapi.Context, obj runtime.Object) { route := obj.(*api.Route) route.Status = api.RouteStatus{} err := s.allocateHost(route) if err != nil { // TODO: this will be changed when moved to a controller utilruntime.HandleError(errors.NewInternalError(fmt.Errorf("allocation error: %v for route: %#v", err, obj))) } }
func imageImportStatus(err error, kind, position string) unversioned.Status { switch t := err.(type) { case client.APIStatus: return t.Status() case *fielderrors.ValidationError: return kapierrors.NewInvalid(kind, position, fielderrors.ValidationErrorList{t}).(client.APIStatus).Status() default: return kapierrors.NewInternalError(err).(client.APIStatus).Status() } }
// returnApplicationPodName returns the best candidate pod for the target deployment in order to // view its logs. func (r *REST) returnApplicationPodName(target *kapi.ReplicationController) (string, error) { selector := labels.Set(target.Spec.Selector).AsSelector() sortBy := func(pods []*kapi.Pod) sort.Interface { return controller.ByLogging(pods) } pod, _, err := kcmdutil.GetFirstPod(r.pn, target.Namespace, selector, r.timeout, sortBy) if err != nil { return "", errors.NewInternalError(err) } return pod.Name, nil }
func imageImportStatus(err error, kind, position string) unversioned.Status { switch t := err.(type) { case kapierrors.APIStatus: return t.Status() case *field.Error: return kapierrors.NewInvalid(api.Kind(kind), position, field.ErrorList{t}).ErrStatus default: return kapierrors.NewInternalError(err).ErrStatus } }
// NewForbidden is a utility function to return a well-formatted admission control error response func NewForbidden(a Attributes, internalError error) error { // do not double wrap an error of same type if apierrors.IsForbidden(internalError) { return internalError } name, kind, err := extractKindName(a) if err != nil { return apierrors.NewInternalError(utilerrors.NewAggregate([]error{internalError, err})) } return apierrors.NewForbidden(kind.Kind, name, internalError) }
func (r *RollbackREST) rollbackDeployment(ctx api.Context, deploymentID string, config *extensions.RollbackConfig, annotations map[string]string) error { if _, err := r.setDeploymentRollback(ctx, deploymentID, config, annotations); err != nil { err = storeerr.InterpretGetError(err, extensions.Resource("deployments"), deploymentID) err = storeerr.InterpretUpdateError(err, extensions.Resource("deployments"), deploymentID) if _, ok := err.(*errors.StatusError); !ok { err = errors.NewInternalError(err) } return err } return nil }