func (o *reconcileClusterOptions) ReplaceChangedRoles(changedRoles []*authorizationapi.ClusterRole) error { for i := range changedRoles { role, err := o.RoleClient.Get(changedRoles[i].Name) if err != nil && !kapierrors.IsNotFound(err) { return err } if kapierrors.IsNotFound(err) { createdRole, err := o.RoleClient.Create(changedRoles[i]) if err != nil { return err } fmt.Fprintf(o.Out, "clusterrole/%s\n", createdRole.Name) continue } role.Rules = changedRoles[i].Rules updatedRole, err := o.RoleClient.Update(role) if err != nil { return err } fmt.Fprintf(o.Out, "clusterrole/%s\n", updatedRole.Name) } return nil }
// Ensure that when scheduler creates a binding for a pod that has already been deleted // by the API server, API server returns not-found error. func TestEtcdCreateBindingNoPod(t *testing.T) { registry, bindingRegistry, _, fakeClient, _ := newStorage(t) ctx := api.NewDefaultContext() fakeClient.TestIndex = true key, _ := registry.KeyFunc(ctx, "foo") fakeClient.Data[key] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: nil, }, E: tools.EtcdErrorNotFound, } // Assume that a pod has undergone the following: // - Create (apiserver) // - Schedule (scheduler) // - Delete (apiserver) _, err := bindingRegistry.Create(ctx, &api.Binding{ ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "foo"}, Target: api.ObjectReference{Name: "machine"}, }) if err == nil { t.Fatalf("Expected not-found-error but got nothing") } if !errors.IsNotFound(etcderrors.InterpretGetError(err, "Pod", "foo")) { t.Fatalf("Unexpected error returned: %#v", err) } _, err = registry.Get(ctx, "foo") if err == nil { t.Fatalf("Expected not-found-error but got nothing") } if !errors.IsNotFound(etcderrors.InterpretGetError(err, "Pod", "foo")) { t.Fatalf("Unexpected error: %v", err) } }
// CancelBuild updates a build status to Cancelled, after its associated pod is deleted. func (bc *BuildController) CancelBuild(build *buildapi.Build) error { if !isBuildCancellable(build) { glog.V(4).Infof("Build %s/%s can be cancelled only if it has pending/running status, not %s.", build.Namespace, build.Name, build.Status.Phase) return nil } glog.V(4).Infof("Cancelling Build %s/%s.", build.Namespace, build.Name) pod, err := bc.PodManager.GetPod(build.Namespace, buildutil.GetBuildPodName(build)) if err != nil { if !errors.IsNotFound(err) { return fmt.Errorf("Failed to get Pod for build %s/%s: %v", build.Namespace, build.Name, err) } } else { err := bc.PodManager.DeletePod(build.Namespace, pod) if err != nil && !errors.IsNotFound(err) { return fmt.Errorf("Couldn't delete Build Pod %s/%s: %v", build.Namespace, pod.Name, err) } } build.Status.Phase = buildapi.BuildPhaseCancelled now := util.Now() build.Status.CompletionTimestamp = &now if err := bc.BuildUpdater.Update(build.Namespace, build); err != nil { return fmt.Errorf("Failed to update Build %s/%s: %v", build.Namespace, build.Name, err) } glog.V(4).Infof("Build %s/%s was successfully cancelled.", build.Namespace, build.Name) return nil }
func TestMinionRegistryREST(t *testing.T) { ms := NewREST(registrytest.NewMinionRegistry([]string{"foo", "bar"}, api.NodeResources{})) ctx := api.NewContext() if obj, err := ms.Get(ctx, "foo"); err != nil || obj.(*api.Node).Name != "foo" { t.Errorf("missing expected object") } if obj, err := ms.Get(ctx, "bar"); err != nil || obj.(*api.Node).Name != "bar" { t.Errorf("missing expected object") } if _, err := ms.Get(ctx, "baz"); !errors.IsNotFound(err) { t.Errorf("has unexpected error: %v", err) } obj, err := ms.Create(ctx, &api.Node{ObjectMeta: api.ObjectMeta{Name: "baz"}}) if err != nil { t.Fatalf("insert failed: %v", err) } if !api.HasObjectMetaSystemFieldValues(&obj.(*api.Node).ObjectMeta) { t.Errorf("storage did not populate object meta field values") } if m, ok := obj.(*api.Node); !ok || m.Name != "baz" { t.Errorf("insert return value was weird: %#v", obj) } if obj, err := ms.Get(ctx, "baz"); err != nil || obj.(*api.Node).Name != "baz" { t.Errorf("insert didn't actually insert") } obj, err = ms.Delete(ctx, "bar") if err != nil { t.Fatalf("delete failed") } if s, ok := obj.(*api.Status); !ok || s.Status != api.StatusSuccess { t.Errorf("delete return value was weird: %#v", obj) } if _, err := ms.Get(ctx, "bar"); !errors.IsNotFound(err) { t.Errorf("delete didn't actually delete: %v", err) } _, err = ms.Delete(ctx, "bar") if err != ErrDoesNotExist { t.Fatalf("delete returned wrong error") } list, err := ms.List(ctx, labels.Everything(), fields.Everything()) if err != nil { t.Errorf("got error calling List") } expect := []api.Node{ { ObjectMeta: api.ObjectMeta{Name: "foo"}, }, { ObjectMeta: api.ObjectMeta{Name: "baz"}, }, } nodeList := list.(*api.NodeList) if len(expect) != len(nodeList.Items) || !contains(nodeList, "foo") || !contains(nodeList, "baz") { t.Errorf("Unexpected list value: %#v", list) } }
// Resolve will attempt to find an imagestream with a name that matches the passed in value func (r ImageStreamResolver) Resolve(value string) (*ComponentMatch, error) { ref, err := imageapi.ParseDockerImageReference(value) if err != nil || len(ref.Registry) != 0 { return nil, fmt.Errorf("image repositories must be of the form [<namespace>/]<name>[:<tag>|@<digest>]") } namespaces := r.Namespaces if len(ref.Namespace) != 0 { namespaces = []string{ref.Namespace} } searchTag := ref.Tag if len(searchTag) == 0 { searchTag = imageapi.DefaultImageTag } for _, namespace := range namespaces { glog.V(4).Infof("checking ImageStream %s/%s with ref %q", namespace, ref.Name, searchTag) repo, err := r.Client.ImageStreams(namespace).Get(ref.Name) if err != nil { if errors.IsNotFound(err) || errors.IsForbidden(err) { continue } return nil, err } ref.Namespace = namespace latest := imageapi.LatestTaggedImage(repo, searchTag) if latest == nil { // continue searching in the next namespace glog.V(2).Infof("no image recorded for %s/%s:%s", repo.Namespace, repo.Name, searchTag) continue } imageStreamImage, err := r.ImageStreamImages.ImageStreamImages(namespace).Get(ref.Name, latest.Image) if err != nil { if errors.IsNotFound(err) { // continue searching in the next namespace glog.V(2).Infof("tag %q is set, but image %q has been removed", searchTag, latest.Image) continue } return nil, err } imageData := imageStreamImage.Image ref.Registry = "" return &ComponentMatch{ Value: ref.String(), Argument: fmt.Sprintf("--image=%q", ref.String()), Name: ref.Name, Description: fmt.Sprintf("Image repository %s (tag %q) in project %s, tracks %q", repo.Name, searchTag, repo.Namespace, repo.Status.DockerImageRepository), Builder: IsBuilderImage(&imageData.DockerImageMetadata), Score: 0, ImageStream: repo, Image: &imageData.DockerImageMetadata, ImageTag: searchTag, }, nil } return nil, ErrNoMatch{value: value} }
// resolveImageStreamReference looks up the ImageStream[Tag/Image] and converts it to a // docker pull spec that can be used in an Image field. func (g *BuildGenerator) resolveImageStreamReference(ctx kapi.Context, from kapi.ObjectReference, defaultNamespace string) (string, error) { var namespace string if len(from.Namespace) != 0 { namespace = from.Namespace } else { namespace = defaultNamespace } glog.V(4).Infof("Resolving ImageStreamReference %s of Kind %s in namespace %s", from.Name, from.Kind, namespace) switch from.Kind { case "ImageStream": // NOTE: The 'ImageStream' reference should be used only for the 'output' image is, err := g.Client.GetImageStream(kapi.WithNamespace(ctx, namespace), from.Name) if err != nil { glog.V(2).Infof("Error getting ImageStream %s/%s: %v", namespace, from.Name, err) return "", err } image, err := imageapi.DockerImageReferenceForStream(is) if err != nil { glog.V(2).Infof("Error resolving Docker image reference for %s/%s: %v", namespace, from.Name, err) return "", err } return image.String(), nil case "ImageStreamImage": imageStreamImage, err := g.Client.GetImageStreamImage(kapi.WithNamespace(ctx, namespace), from.Name) if err != nil { glog.V(2).Infof("Error ImageStreamReference %s in namespace %s: %v", from.Name, namespace, err) if errors.IsNotFound(err) { return "", err } return "", fatalError{err} } image := imageStreamImage.Image glog.V(4).Infof("Resolved ImageStreamReference %s to image %s with reference %s in namespace %s", from.Name, image.Name, image.DockerImageReference, namespace) return image.DockerImageReference, nil case "ImageStreamTag": imageStreamTag, err := g.Client.GetImageStreamTag(kapi.WithNamespace(ctx, namespace), from.Name) if err != nil { glog.V(2).Infof("Error resolving ImageStreamTag reference %s in namespace %s: %v", from.Name, namespace, err) if errors.IsNotFound(err) { return "", err } return "", fatalError{err} } image := imageStreamTag.Image glog.V(4).Infof("Resolved ImageStreamTag %s to image %s with reference %s in namespace %s", from.Name, image.Name, image.DockerImageReference, namespace) return image.DockerImageReference, nil case "DockerImage": return from.Name, nil default: return "", fatalError{fmt.Errorf("Unknown From Kind %s", from.Kind)} } }
func getReferencedServiceAccountToken(c *client.Client, ns string, name string, shouldWait bool) (string, string, error) { tokenName := "" token := "" findToken := func() (bool, error) { user, err := c.ServiceAccounts(ns).Get(name) if errors.IsNotFound(err) { return false, nil } if err != nil { return false, err } for _, ref := range user.Secrets { secret, err := c.Secrets(ns).Get(ref.Name) if errors.IsNotFound(err) { continue } if err != nil { return false, err } if secret.Type != api.SecretTypeServiceAccountToken { continue } name := secret.Annotations[api.ServiceAccountNameKey] uid := secret.Annotations[api.ServiceAccountUIDKey] tokenData := secret.Data[api.ServiceAccountTokenKey] if name == user.Name && uid == string(user.UID) && len(tokenData) > 0 { tokenName = secret.Name token = string(tokenData) return true, nil } } return false, nil } if shouldWait { err := wait.Poll(time.Second, 10*time.Second, findToken) if err != nil { return "", "", err } } else { ok, err := findToken() if err != nil { return "", "", err } if !ok { return "", "", fmt.Errorf("No token found for %s/%s", ns, name) } } return tokenName, token, nil }
// syncNamespace makes namespace life-cycle decisions func syncNamespace(kubeClient client.Interface, namespace api.Namespace) (err error) { if namespace.DeletionTimestamp == nil { return nil } // if there is a deletion timestamp, and the status is not terminating, then update status if !namespace.DeletionTimestamp.IsZero() && namespace.Status.Phase != api.NamespaceTerminating { newNamespace := api.Namespace{} newNamespace.ObjectMeta = namespace.ObjectMeta newNamespace.Status = namespace.Status newNamespace.Status.Phase = api.NamespaceTerminating result, err := kubeClient.Namespaces().Status(&newNamespace) if err != nil { return err } // work with the latest copy so we can proceed to clean up right away without another interval namespace = *result } // if the namespace is already finalized, delete it if finalized(namespace) { err = kubeClient.Namespaces().Delete(namespace.Name) if err != nil && !errors.IsNotFound(err) { return err } return nil } // there may still be content for us to remove err = deleteAllContent(kubeClient, namespace.Name) if err != nil { return err } // we have removed content, so mark it finalized by us result, err := finalize(kubeClient, namespace) if err != nil { return err } // now check if all finalizers have reported that we delete now if finalized(*result) { err = kubeClient.Namespaces().Delete(namespace.Name) if err != nil && !errors.IsNotFound(err) { return err } } return nil }
func (factory *ConfigFactory) makeDefaultErrorFunc(backoff *podBackoff, podQueue *cache.FIFO) func(pod *api.Pod, err error) { return func(pod *api.Pod, err error) { if err == scheduler.ErrNoNodesAvailable { glog.V(4).Infof("Unable to schedule %v %v: no nodes are registered to the cluster; waiting", pod.Namespace, pod.Name) } else { glog.Errorf("Error scheduling %v %v: %v; retrying", pod.Namespace, pod.Name, err) } backoff.gc() // Retry asynchronously. // Note that this is extremely rudimentary and we need a more real error handling path. go func() { defer util.HandleCrash() podID := pod.Name podNamespace := pod.Namespace backoff.wait(podID) // Get the pod again; it may have changed/been scheduled already. pod = &api.Pod{} err := factory.Client.Get().Namespace(podNamespace).Resource("pods").Name(podID).Do().Into(pod) if err != nil { if !errors.IsNotFound(err) { glog.Errorf("Error getting pod %v for retry: %v; abandoning", podID, err) } return } if pod.Spec.NodeName == "" { podQueue.Add(pod) } }() } }
func (s *ServiceController) persistUpdate(service *api.Service) error { var err error for i := 0; i < clientRetryCount; i++ { _, err = s.kubeClient.Services(service.Namespace).Update(service) if err == nil { return nil } // If the object no longer exists, we don't want to recreate it. Just bail // out so that we can process the delete, which we should soon be receiving // if we haven't already. if errors.IsNotFound(err) { glog.Infof("Not persisting update to service that no longer exists: %v", err) return nil } // TODO: Try to resolve the conflict if the change was unrelated to load // balancers and public IPs. For now, just rely on the fact that we'll // also process the update that caused the resource version to change. if errors.IsConflict(err) { glog.Infof("Not persisting update to service that has been changed since we received it: %v", err) return nil } glog.Warningf("Failed to persist updated PublicIPs to service %s after creating its external load balancer: %v", service.Name, err) time.Sleep(clientRetryInterval) } return err }
// ensurePolicyBindingToMaster returns a PolicyBinding object that has a PolicyRef pointing to the Policy in the passed namespace. func (m *VirtualStorage) ensurePolicyBindingToMaster(ctx kapi.Context, policyNamespace, policyBindingName string) (*authorizationapi.PolicyBinding, error) { policyBinding, err := m.BindingRegistry.GetPolicyBinding(ctx, policyBindingName) if err != nil { if !kapierrors.IsNotFound(err) { return nil, err } // if we have no policyBinding, go ahead and make one. creating one here collapses code paths below. We only take this hit once policyBinding = policybindingregistry.NewEmptyPolicyBinding(kapi.NamespaceValue(ctx), policyNamespace, policyBindingName) if err := m.BindingRegistry.CreatePolicyBinding(ctx, policyBinding); err != nil { return nil, err } policyBinding, err = m.BindingRegistry.GetPolicyBinding(ctx, policyBindingName) if err != nil { return nil, err } } if policyBinding.RoleBindings == nil { policyBinding.RoleBindings = make(map[string]*authorizationapi.RoleBinding) } return policyBinding, nil }
// setEndpoints sets the endpoints for the given service. // in a multi-master scenario only the master will be publishing an endpoint. // see SchedulerServer.bootstrap. func (m *SchedulerServer) setEndpoints(serviceName string, ip net.IP, port int) error { // The setting we want to find. want := []api.EndpointSubset{{ Addresses: []api.EndpointAddress{{IP: ip.String()}}, Ports: []api.EndpointPort{{Port: port, Protocol: api.ProtocolTCP}}, }} ctx := api.NewDefaultContext() e, err := m.client.Endpoints(api.NamespaceValue(ctx)).Get(serviceName) createOrUpdate := m.client.Endpoints(api.NamespaceValue(ctx)).Update if err != nil { if errors.IsNotFound(err) { createOrUpdate = m.client.Endpoints(api.NamespaceValue(ctx)).Create } e = &api.Endpoints{ ObjectMeta: api.ObjectMeta{ Name: serviceName, Namespace: api.NamespaceDefault, }, } } if !reflect.DeepEqual(e.Subsets, want) { e.Subsets = want glog.Infof("setting endpoints for master service %q to %#v", serviceName, e) _, err = createOrUpdate(e) return err } // We didn't make any changes, no need to actually call update. return nil }
// EnsurePolicy returns the policy object for the specified namespace. If one does not exist, it is created for you. Permission to // create, update, or delete roles in a namespace implies the ability to create a Policy object itself. func (m *VirtualStorage) EnsurePolicy(ctx kapi.Context) (*authorizationapi.Policy, error) { policy, err := m.PolicyStorage.GetPolicy(ctx, authorizationapi.PolicyName) if err != nil { if !kapierrors.IsNotFound(err) { return nil, err } // if we have no policy, go ahead and make one. creating one here collapses code paths below. We only take this hit once policy = NewEmptyPolicy(kapi.NamespaceValue(ctx)) if err := m.PolicyStorage.CreatePolicy(ctx, policy); err != nil { return nil, err } policy, err = m.PolicyStorage.GetPolicy(ctx, authorizationapi.PolicyName) if err != nil { return nil, err } } if policy.Roles == nil { policy.Roles = make(map[string]*authorizationapi.Role) } return policy, nil }
func TestUpdateError(t *testing.T) { ctx := kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "unittest"), &user.DefaultInfo{Name: "system:admin"}) storage := makeTestStorage() obj, err := storage.Create(ctx, &authorizationapi.RoleBinding{ ObjectMeta: kapi.ObjectMeta{Name: "my-different"}, RoleRef: kapi.ObjectReference{Name: "admin"}, }) if err != nil { t.Errorf("unexpected error: %v", err) return } original := obj.(*authorizationapi.RoleBinding) roleBinding := &authorizationapi.RoleBinding{ ObjectMeta: kapi.ObjectMeta{Name: "my-roleBinding", ResourceVersion: original.ResourceVersion}, RoleRef: kapi.ObjectReference{Name: "admin"}, } _, _, err = storage.Update(ctx, roleBinding) if err == nil { t.Errorf("Missing expected error") return } if !kapierrors.IsNotFound(err) { t.Errorf("Unexpected error %v", err) } }
func TestGetEndpointsMissingService(t *testing.T) { registry := ®istrytest.ServiceRegistry{ Err: errors.NewNotFound("service", "foo"), } storage := NewREST(registry) ctx := api.NewContext() // returns service not found _, err := storage.Get(ctx, "foo") if !errors.IsNotFound(err) || !reflect.DeepEqual(err, errors.NewNotFound("service", "foo")) { t.Errorf("expected NotFound error, got %#v", err) } // returns empty endpoints registry.Err = nil registry.Service = &api.Service{ ObjectMeta: api.ObjectMeta{Name: "foo"}, } obj, err := storage.Get(ctx, "foo") if err != nil { t.Fatalf("unexpected error: %v", err) } if obj.(*api.Endpoints).Endpoints != nil { t.Errorf("unexpected endpoints: %#v", obj) } }
// findResource tries to find a deployment or deploymentconfig named // targetName using a resource.Builder. For compatibility, if the resource // name is unprefixed, treat it as an rc first and a dc second. func (o *RollbackOptions) findResource(targetName string) (runtime.Object, error) { candidates := []string{} if strings.Index(targetName, "/") == -1 { candidates = append(candidates, "rc/"+targetName) candidates = append(candidates, "dc/"+targetName) } else { candidates = append(candidates, targetName) } var obj runtime.Object for _, name := range candidates { r := o.getBuilder(). NamespaceParam(o.Namespace). ResourceTypeOrNameArgs(false, name). SingleResourceType(). Do() if r.Err() != nil { return nil, r.Err() } resultObj, err := r.Object() if err != nil { // If the resource wasn't found, try another candidate. if kerrors.IsNotFound(err) { continue } return nil, err } obj = resultObj break } if obj == nil { return nil, fmt.Errorf("%s is not a valid deployment or deploymentconfig", targetName) } return obj, nil }
func TestDeleteObjectNotFound(t *testing.T) { f, tf, codec := NewAPIFactory() tf.Printer = &testPrinter{} tf.Client = &client.FakeRESTClient{ Codec: codec, Client: client.HTTPClientFunc(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { case p == "/namespaces/test/replicationcontrollers/redis-master" && m == "DELETE": return &http.Response{StatusCode: 404, Body: stringBody("")}, nil default: t.Fatalf("unexpected request: %#v\n%#v", req.URL, req) return nil, nil } }), } tf.Namespace = "test" buf := bytes.NewBuffer([]byte{}) cmd := NewCmdDelete(f, buf) cmd.Flags().Set("filename", "../../../examples/guestbook/redis-master-controller.yaml") cmd.Flags().Set("cascade", "false") filenames := cmd.Flags().Lookup("filename").Value.(*util.StringList) err := RunDelete(f, buf, cmd, []string{}, *filenames) if err == nil || !errors.IsNotFound(err) { t.Errorf("unexpected error: expected NotFound, got %v", err) } }
// Resolve searches for a template and returns a match with the object representation func (r TemplateResolver) Resolve(value string) (*ComponentMatch, error) { checked := util.NewStringSet() for _, namespace := range r.Namespaces { if checked.Has(namespace) { continue } checked.Insert(namespace) glog.V(4).Infof("checking template %s/%s", namespace, value) repo, err := r.Client.Templates(namespace).Get(value) if err != nil { if errors.IsNotFound(err) || errors.IsForbidden(err) { continue } return nil, err } return &ComponentMatch{ Value: value, Argument: fmt.Sprintf("--template=%q", value), Name: value, Description: fmt.Sprintf("Template %s in project %s", repo.Name, repo.Namespace), Score: 0, Template: repo, }, nil } return nil, ErrNoMatch{value: value} }
// Visit implements Visitor func (r *Selector) Visit(fn VisitorFunc) error { list, err := NewHelper(r.Client, r.Mapping).List(r.Namespace, r.Selector) if err != nil { if errors.IsBadRequest(err) || errors.IsNotFound(err) { if r.Selector.Empty() { glog.V(2).Infof("Unable to list %q: %v", r.Mapping.Resource, err) } else { glog.V(2).Infof("Unable to find %q that match the selector %q: %v", r.Mapping.Resource, r.Selector, err) } return nil } return err } accessor := r.Mapping.MetadataAccessor resourceVersion, _ := accessor.ResourceVersion(list) info := &Info{ Client: r.Client, Mapping: r.Mapping, Namespace: r.Namespace, Object: list, ResourceVersion: resourceVersion, } return fn(info) }
func (p *provisioningIdentityMapper) getOrCreateUserForIdentity(ctx kapi.Context, identity *userapi.Identity) (*userapi.User, error) { preferredUserName := getPreferredUserName(identity) // Iterate through the max allowed generated usernames // If an existing user references this identity, associate the identity with that user and return // Otherwise, create a user with the first generated user name that does not already exist and return. // Names are created in a deterministic order, so the first one that isn't present gets created. // In the case of a race, one will get to persist the user object and the other will fail. for sequence := 0; sequence < MaxGenerateAttempts; sequence++ { // Get the username we want potentialUserName := p.generator(preferredUserName, sequence) // See if it already exists persistedUser, err := p.user.GetUser(ctx, potentialUserName) if err != nil && !kerrs.IsNotFound(err) { // Fail on errors other than "not found" return nil, err } if err != nil && kerrs.IsNotFound(err) { // Try to create a user with the available name desiredUser := &userapi.User{ ObjectMeta: kapi.ObjectMeta{Name: potentialUserName}, Identities: []string{identity.Name}, } // Initialize from the identity p.initializer.InitializeUser(identity, desiredUser) // Create the user createdUser, err := p.user.CreateUser(ctx, desiredUser) if err != nil { return nil, err } return createdUser, nil } if util.NewStringSet(persistedUser.Identities...).Has(identity.Name) { // If the existing user references our identity, we're done return persistedUser, nil } } return nil, errors.New("Could not create user, max attempts exceeded") }
func (t *Tester) TestUpdateFailsOnNotFound(valid runtime.Object) { _, _, err := t.storage.(rest.Updater).Update(api.NewDefaultContext(), valid) if err == nil { t.Errorf("Expected an error, but we didn't get one") } else if !errors.IsNotFound(err) { t.Errorf("Expected NotFound error, got '%v'", err) } }
func TestEtcdDelete(t *testing.T) { podA := &api.Pod{ ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"}, Spec: api.PodSpec{Host: "machine"}, } nodeWithPodA := tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Value: runtime.EncodeOrDie(testapi.Codec(), podA), ModifiedIndex: 1, CreatedIndex: 1, }, }, E: nil, } emptyNode := tools.EtcdResponseWithError{ R: &etcd.Response{}, E: tools.EtcdErrorNotFound, } key := "foo" table := map[string]struct { existing tools.EtcdResponseWithError expect tools.EtcdResponseWithError errOK func(error) bool }{ "normal": { existing: nodeWithPodA, expect: emptyNode, errOK: func(err error) bool { return err == nil }, }, "notExisting": { existing: emptyNode, expect: emptyNode, errOK: func(err error) bool { return errors.IsNotFound(err) }, }, } for name, item := range table { fakeClient, registry := NewTestGenericEtcdRegistry(t) path := etcdtest.AddPrefix("pods/foo") fakeClient.Data[path] = item.existing obj, err := registry.Delete(api.NewContext(), key, nil) if !item.errOK(err) { t.Errorf("%v: unexpected error: %v (%#v)", name, err, obj) } if item.expect.E != nil { item.expect.E.(*etcd.EtcdError).Index = fakeClient.ChangeIndex } if e, a := item.expect, fakeClient.Data[path]; !api.Semantic.DeepDerivative(e, a) { t.Errorf("%v:\n%s", name, util.ObjectDiff(e, a)) } } }
// this pod may be out of sync with respect to the API server registry: // this pod | apiserver registry // -------------|---------------------- // host=.* | 404 ; pod was deleted // host=.* | 5xx ; failed to sync, try again later? // host="" | host="" ; perhaps no updates to process? // host="" | host="..." ; pod has been scheduled and assigned, is there a task assigned? (check TaskIdKey in binding?) // host="..." | host="" ; pod is no longer scheduled, does it need to be re-queued? // host="..." | host="..." ; perhaps no updates to process? // // TODO(jdef) this needs an integration test func (s *schedulingPlugin) reconcilePod(oldPod api.Pod) { log.V(1).Infof("reconcile pod %v", oldPod.Name) ctx := api.WithNamespace(api.NewDefaultContext(), oldPod.Namespace) pod, err := s.client.Pods(api.NamespaceValue(ctx)).Get(oldPod.Name) if err != nil { if errors.IsNotFound(err) { // attempt to delete if err = s.deleter.deleteOne(&Pod{Pod: &oldPod}); err != nil && err != noSuchPodErr && err != noSuchTaskErr { log.Errorf("failed to delete pod: %v: %v", oldPod.Name, err) } } else { //TODO(jdef) other errors should probably trigger a retry (w/ backoff). //For now, drop the pod on the floor log.Warning("aborting reconciliation for pod %v: %v", oldPod.Name, err) } return } if oldPod.Spec.NodeName != pod.Spec.NodeName { if pod.Spec.NodeName == "" { // pod is unscheduled. // it's possible that we dropped the pod in the scheduler error handler // because of task misalignment with the pod (task.Has(podtask.Launched) == true) podKey, err := podtask.MakePodKey(ctx, pod.Name) if err != nil { log.Error(err) return } s.api.Lock() defer s.api.Unlock() if _, state := s.api.tasks().ForPod(podKey); state != podtask.StateUnknown { //TODO(jdef) reconcile the task log.Errorf("task already registered for pod %v", pod.Name) return } now := time.Now() log.V(3).Infof("reoffering pod %v", podKey) s.qr.reoffer(&Pod{ Pod: pod, deadline: &now, }) } else { // pod is scheduled. // not sure how this happened behind our backs. attempt to reconstruct // at least a partial podtask.T record. //TODO(jdef) reconcile the task log.Errorf("pod already scheduled: %v", pod.Name) } } else { //TODO(jdef) for now, ignore the fact that the rest of the spec may be different //and assume that our knowledge of the pod aligns with that of the apiserver log.Error("pod reconciliation does not support updates; not yet implemented") } }
func CreateOrUpdateDefaultOAuthClients(masterPublicAddr string, assetPublicAddresses []string, clientRegistry clientregistry.Registry) { clientsToEnsure := []*oauthapi.OAuthClient{ { ObjectMeta: kapi.ObjectMeta{ Name: OSWebConsoleClientBase.Name, }, Secret: OSWebConsoleClientBase.Secret, RespondWithChallenges: OSWebConsoleClientBase.RespondWithChallenges, RedirectURIs: assetPublicAddresses, }, { ObjectMeta: kapi.ObjectMeta{ Name: OSBrowserClientBase.Name, }, Secret: OSBrowserClientBase.Secret, RespondWithChallenges: OSBrowserClientBase.RespondWithChallenges, RedirectURIs: []string{masterPublicAddr + path.Join(OpenShiftOAuthAPIPrefix, tokenrequest.DisplayTokenEndpoint)}, }, { ObjectMeta: kapi.ObjectMeta{ Name: OSCliClientBase.Name, }, Secret: OSCliClientBase.Secret, RespondWithChallenges: OSCliClientBase.RespondWithChallenges, RedirectURIs: []string{masterPublicAddr + path.Join(OpenShiftOAuthAPIPrefix, tokenrequest.DisplayTokenEndpoint)}, }, } ctx := kapi.NewContext() for _, currClient := range clientsToEnsure { existing, err := clientRegistry.GetClient(ctx, currClient.Name) if err == nil { // Update the existing resource version currClient.ResourceVersion = existing.ResourceVersion // Add in any redirects from the existing one // This preserves any additional customized redirects in the default clients redirects := util.NewStringSet(currClient.RedirectURIs...) for _, redirect := range existing.RedirectURIs { if !redirects.Has(redirect) { currClient.RedirectURIs = append(currClient.RedirectURIs, redirect) redirects.Insert(redirect) } } if _, err := clientRegistry.UpdateClient(ctx, currClient); err != nil { glog.Errorf("Error updating OAuthClient %v: %v", currClient.Name, err) } } else if kerrs.IsNotFound(err) { if _, err = clientRegistry.CreateClient(ctx, currClient); err != nil { glog.Errorf("Error creating OAuthClient %v: %v", currClient.Name, err) } } else { glog.Errorf("Error getting OAuthClient %v: %v", currClient.Name, err) } } }
// Describe returns the description of a DeploymentConfig func (d *DeploymentConfigDescriber) Describe(namespace, name string) (string, error) { deploymentConfig, err := d.client.getDeploymentConfig(namespace, name) if err != nil { return "", err } events, err := d.client.listEvents(deploymentConfig) if err != nil { return "", err } return tabbedString(func(out *tabwriter.Writer) error { formatMeta(out, deploymentConfig.ObjectMeta) if deploymentConfig.LatestVersion == 0 { formatString(out, "Latest Version", "Not deployed") } else { formatString(out, "Latest Version", strconv.Itoa(deploymentConfig.LatestVersion)) } printTriggers(deploymentConfig.Triggers, out) formatString(out, "Strategy", deploymentConfig.Template.Strategy.Type) printStrategy(deploymentConfig.Template.Strategy, out) printReplicationControllerSpec(deploymentConfig.Template.ControllerTemplate, out) deploymentName := deployutil.LatestDeploymentNameForConfig(deploymentConfig) deployment, err := d.client.getDeployment(namespace, deploymentName) if err != nil { if kerrors.IsNotFound(err) { formatString(out, "Latest Deployment", "<none>") } else { formatString(out, "Latest Deployment", fmt.Sprintf("error: %v", err)) } } else { header := fmt.Sprintf("Deployment #%d (latest)", deployutil.DeploymentVersionFor(deployment)) printDeploymentRc(deployment, d.client, out, header, true) } deploymentsHistory, err := d.client.listDeployments(namespace, labels.Everything()) if err == nil { sorted := rcSorter{} sorted = append(sorted, deploymentsHistory.Items...) sort.Sort(sorted) for _, item := range sorted { if item.Name != deploymentName && deploymentConfig.Name == deployutil.DeploymentConfigNameFor(&item) { header := fmt.Sprintf("Deployment #%d", deployutil.DeploymentVersionFor(&item)) printDeploymentRc(&item, d.client, out, header, false) } } } if events != nil { kctl.DescribeEvents(events, out) } return nil }) }
// resolveImageStreamDockerRepository looks up the ImageStream[Tag/Image] and converts it to a // the docker repository reference with no tag information func (g *BuildGenerator) resolveImageStreamDockerRepository(ctx kapi.Context, from kapi.ObjectReference, defaultNamespace string) (string, error) { namespace := defaultNamespace if len(from.Namespace) > 0 { namespace = from.Namespace } glog.V(4).Infof("Resolving ImageStreamReference %s of Kind %s in namespace %s", from.Name, from.Kind, namespace) switch from.Kind { case "ImageStreamImage": imageStreamImage, err := g.Client.GetImageStreamImage(kapi.WithNamespace(ctx, namespace), from.Name) if err != nil { glog.V(2).Infof("Error ImageStreamReference %s in namespace %s: %v", from.Name, namespace, err) if errors.IsNotFound(err) { return "", err } return "", fatalError{err} } image := imageStreamImage.Image glog.V(4).Infof("Resolved ImageStreamReference %s to image %s with reference %s in namespace %s", from.Name, image.Name, image.DockerImageReference, namespace) return image.DockerImageReference, nil case "ImageStreamTag": name := strings.Split(from.Name, ":")[0] is, err := g.Client.GetImageStream(kapi.WithNamespace(ctx, namespace), name) if err != nil { glog.V(2).Infof("Error getting ImageStream %s/%s: %v", namespace, name, err) if errors.IsNotFound(err) { return "", err } return "", fatalError{err} } image, err := imageapi.DockerImageReferenceForStream(is) if err != nil { glog.V(2).Infof("Error resolving Docker image reference for %s/%s: %v", namespace, name, err) return "", err } glog.V(4).Infof("Resolved ImageStreamTag %s/%s to repository %s", namespace, from.Name, image) return image.String(), nil case "DockerImage": return from.Name, nil default: return "", fatalError{fmt.Errorf("Unknown From Kind %s", from.Kind)} } }
func LoadExistingNextReplicationController(c *client.Client, namespace, newName string) (*api.ReplicationController, error) { if len(newName) == 0 { return nil, nil } newRc, err := c.ReplicationControllers(namespace).Get(newName) if err != nil && errors.IsNotFound(err) { return nil, nil } return newRc, err }
// GetClient loads the client by id (client_id) func (s *storage) GetClient(id string) (osin.Client, error) { c, err := s.client.GetClient(kapi.NewContext(), id) if err != nil { if kerrors.IsNotFound(err) { return nil, nil } return nil, err } return &clientWrapper{id, c}, nil }
// Describe returns the description of the latest deployments for a config func (d *LatestDeploymentsDescriber) Describe(namespace, name string) (string, error) { config, err := d.client.getDeploymentConfig(namespace, name) if err != nil { return "", err } var deployments []kapi.ReplicationController if d.count == -1 || d.count > 1 { list, err := d.client.listDeployments(namespace, labels.Everything()) if err != nil && !kerrors.IsNotFound(err) { return "", err } deployments = list.Items } else { deploymentName := deployutil.LatestDeploymentNameForConfig(config) deployment, err := d.client.getDeployment(config.Namespace, deploymentName) if err != nil && !kerrors.IsNotFound(err) { return "", err } if deployment != nil { deployments = []kapi.ReplicationController{*deployment} } } g := graph.New() dcNode := deploygraph.EnsureDeploymentConfigNode(g, config) for i := range deployments { kubegraph.EnsureReplicationControllerNode(g, &deployments[i]) } deployedges.AddTriggerEdges(g, dcNode) deployedges.AddDeploymentEdges(g, dcNode) activeDeployment, inactiveDeployments := deployedges.RelevantDeployments(g, dcNode) return tabbedString(func(out *tabwriter.Writer) error { descriptions := describeDeployments(dcNode, activeDeployment, inactiveDeployments, d.count) for i, description := range descriptions { descriptions[i] = fmt.Sprintf("%v %v", name, description) } printLines(out, "", 0, descriptions...) return nil }) }
// List returns an empty list but adds delete events to the store for all Builds that have been deleted but still have pods. func (lw *buildDeleteLW) List() (runtime.Object, error) { glog.V(5).Info("Checking for deleted builds") podList, err := listPods(lw.KubeClient) if err != nil { glog.V(4).Infof("Failed to find any pods due to error %v", err) return nil, err } for _, pod := range podList.Items { buildName, exists := buildutil.GetBuildLabel(&pod) if !exists { continue } glog.V(5).Infof("Found build pod %s/%s", pod.Namespace, pod.Name) build, err := lw.Client.Builds(pod.Namespace).Get(buildName) if err != nil && !kerrors.IsNotFound(err) { glog.V(4).Infof("Error getting build for pod %s/%s: %v", pod.Namespace, pod.Name, err) return nil, err } if err != nil && kerrors.IsNotFound(err) { build = nil } if build == nil { deletedBuild := &buildapi.Build{ ObjectMeta: kapi.ObjectMeta{ Name: buildName, Namespace: pod.Namespace, }, } glog.V(4).Infof("No build found for build pod %s/%s, deleting pod", pod.Namespace, pod.Name) err := lw.store.Delete(deletedBuild) if err != nil { glog.V(4).Infof("Error queuing delete event: %v", err) } } else { glog.V(5).Infof("Found build %s/%s for pod %s", build.Namespace, build.Name, pod.Name) } } return &buildapi.BuildList{}, nil }