func TestDeleteNamespaceWithCompleteFinalizers(t *testing.T) { now := util.Now() fakeEtcdClient, helper := newHelper(t) fakeEtcdClient.ChangeIndex = 1 key := etcdtest.AddPrefix("/namespaces/foo") fakeEtcdClient.Data[key] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Value: runtime.EncodeOrDie(latest.Codec, &api.Namespace{ ObjectMeta: api.ObjectMeta{ Name: "foo", DeletionTimestamp: &now, }, Spec: api.NamespaceSpec{ Finalizers: []api.FinalizerName{}, }, Status: api.NamespaceStatus{Phase: api.NamespaceActive}, }), ModifiedIndex: 1, CreatedIndex: 1, }, }, } storage, _, _ := NewStorage(helper) _, err := storage.Delete(api.NewContext(), "foo", nil) if err != nil { t.Fatalf("unexpected error: %v", err) } }
func TestGetEventExisting(t *testing.T) { // Arrange eventTime := util.Now() event := api.Event{ Reason: "do I exist", Message: "I do, oh my", InvolvedObject: api.ObjectReference{ Kind: "Pod", Name: "clever.name.here", Namespace: "spaceOfName", UID: "D933D32AFB2A238", APIVersion: "version", }, Source: api.EventSource{ Component: "qinglet", Host: "kublet.node4", }, Count: 1, FirstTimestamp: eventTime, LastTimestamp: eventTime, } addOrUpdateEvent(&event) // Act existingEvent := getEvent(&event) // Assert compareEventWithHistoryEntry(&event, &existingEvent, t) }
func TestAddOrUpdateEventNoExisting(t *testing.T) { // Arrange eventTime := util.Now() event := api.Event{ Reason: "my reasons are many", Message: "my message is love", InvolvedObject: api.ObjectReference{ Kind: "Pod", Name: "awesome.name", Namespace: "betterNamespace", UID: "C934D34AFB20242", APIVersion: "version", }, Source: api.EventSource{ Component: "qinglet", Host: "kublet.node1", }, Count: 1, FirstTimestamp: eventTime, LastTimestamp: eventTime, } // Act result := addOrUpdateEvent(&event) // Assert compareEventWithHistoryEntry(&event, &result, t) }
func TestNamespaceStatusStrategy(t *testing.T) { ctx := api.NewDefaultContext() if StatusStrategy.NamespaceScoped() { t.Errorf("Namespaces should not be namespace scoped") } if StatusStrategy.AllowCreateOnUpdate() { t.Errorf("Namespaces should not allow create on update") } now := util.Now() oldNamespace := &api.Namespace{ ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "10"}, Spec: api.NamespaceSpec{Finalizers: []api.FinalizerName{"qingyuan"}}, Status: api.NamespaceStatus{Phase: api.NamespaceActive}, } namespace := &api.Namespace{ ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "9", DeletionTimestamp: &now}, Status: api.NamespaceStatus{Phase: api.NamespaceTerminating}, } StatusStrategy.PrepareForUpdate(namespace, oldNamespace) if namespace.Status.Phase != api.NamespaceTerminating { t.Errorf("Namespace status updates should allow change of phase: %v", namespace.Status.Phase) } if len(namespace.Spec.Finalizers) != 1 || namespace.Spec.Finalizers[0] != api.FinalizerQingYuan { t.Errorf("PrepareForUpdate should have preserved old finalizers") } errs := StatusStrategy.ValidateUpdate(ctx, namespace, oldNamespace) if len(errs) != 0 { t.Errorf("Unexpected error %v", errs) } if namespace.ResourceVersion != "9" { t.Errorf("Incoming resource version on update should not be mutated") } }
func TestAddOrUpdateEventExisting(t *testing.T) { // Arrange event1Time := util.Unix(2324, 2342) event2Time := util.Now() event1 := api.Event{ Reason: "something happened", Message: "can you believe it?", ObjectMeta: api.ObjectMeta{ ResourceVersion: "rs1", }, InvolvedObject: api.ObjectReference{ Kind: "Scheduler", Name: "anOkName", Namespace: "someNamespace", UID: "C934D3234CD0242", APIVersion: "version", }, Source: api.EventSource{ Component: "qinglet", Host: "kublet.node2", }, Count: 1, FirstTimestamp: event1Time, LastTimestamp: event1Time, } event2 := api.Event{ Reason: "something happened", Message: "can you believe it?", ObjectMeta: api.ObjectMeta{ ResourceVersion: "rs2", }, InvolvedObject: api.ObjectReference{ Kind: "Scheduler", Name: "anOkName", Namespace: "someNamespace", UID: "C934D3234CD0242", APIVersion: "version", }, Source: api.EventSource{ Component: "qinglet", Host: "kublet.node2", }, Count: 3, FirstTimestamp: event1Time, LastTimestamp: event2Time, } // Act addOrUpdateEvent(&event1) result1 := addOrUpdateEvent(&event2) result2 := getEvent(&event1) // Assert compareEventWithHistoryEntry(&event2, &result1, t) compareEventWithHistoryEntry(&event2, &result2, t) }
func TestChangedStatusKeepsStartTime(t *testing.T) { syncer := newTestStatusManager() now := util.Now() firstStatus := getRandomPodStatus() firstStatus.StartTime = &now syncer.SetPodStatus(testPod, firstStatus) syncer.SetPodStatus(testPod, getRandomPodStatus()) verifyUpdates(t, syncer, 2) finalStatus, _ := syncer.GetPodStatus(qingcontainer.GetPodFullName(testPod)) if finalStatus.StartTime.IsZero() { t.Errorf("StartTime should not be zero") } if !finalStatus.StartTime.Time.Equal(now.Time) { t.Errorf("Expected %v, but got %v", now.Time, finalStatus.StartTime.Time) } }
func TestEventList(t *testing.T) { ns := api.NamespaceDefault objReference := &api.ObjectReference{ Kind: "foo", Namespace: ns, Name: "objref1", UID: "uid", APIVersion: "apiv1", ResourceVersion: "1", } timeStamp := util.Now() eventList := &api.EventList{ Items: []api.Event{ { InvolvedObject: *objReference, FirstTimestamp: timeStamp, LastTimestamp: timeStamp, Count: 1, }, }, } c := &testClient{ Request: testRequest{ Method: "GET", Path: testapi.ResourcePath("events", ns, ""), Body: nil, }, Response: Response{StatusCode: 200, Body: eventList}, } response, err := c.Setup().Events(ns).List(labels.Everything(), fields.Everything()) if err != nil { t.Errorf("%#v should be nil.", err) } if len(response.Items) != 1 { t.Errorf("%#v response.Items should have len 1.", response.Items) } responseEvent := response.Items[0] if e, r := eventList.Items[0].InvolvedObject, responseEvent.InvolvedObject; !reflect.DeepEqual(e, r) { t.Errorf("%#v != %#v.", e, r) } }
func makeEvent(ref *api.ObjectReference, reason, message string) *api.Event { t := util.Now() namespace := ref.Namespace if namespace == "" { namespace = api.NamespaceDefault } return &api.Event{ ObjectMeta: api.ObjectMeta{ Name: fmt.Sprintf("%v.%x", ref.Name, t.UnixNano()), Namespace: namespace, }, InvolvedObject: *ref, Reason: reason, Message: message, FirstTimestamp: t, LastTimestamp: t, Count: 1, } }
func TestNewStatusPreservesPodStartTime(t *testing.T) { syncer := newTestStatusManager() pod := &api.Pod{ ObjectMeta: api.ObjectMeta{ UID: "12345678", Name: "foo", Namespace: "new", }, Status: api.PodStatus{}, } now := util.Now() startTime := util.NewTime(now.Time.Add(-1 * time.Minute)) pod.Status.StartTime = &startTime syncer.SetPodStatus(pod, getRandomPodStatus()) status, _ := syncer.GetPodStatus(qingcontainer.GetPodFullName(pod)) if !status.StartTime.Time.Equal(startTime.Time) { t.Errorf("Unexpected start time, expected %v, actual %v", startTime, status.StartTime) } }
func (t *Tester) TestCreateResetsUserData(valid runtime.Object) { objectMeta, err := api.ObjectMetaFor(valid) if err != nil { t.Fatalf("object does not have ObjectMeta: %v\n%#v", err, valid) } now := util.Now() objectMeta.UID = "bad-uid" objectMeta.CreationTimestamp = now obj, err := t.storage.(rest.Creater).Create(t.TestContext(), valid) if err != nil { t.Fatalf("Unexpected error: %v", err) } if obj == nil { t.Fatalf("Unexpected object from result: %#v", obj) } if objectMeta.UID == "bad-uid" || objectMeta.CreationTimestamp == now { t.Errorf("ObjectMeta did not reset basic fields: %#v", objectMeta) } }
func (s *statusManager) SetPodStatus(pod *api.Pod, status api.PodStatus) { podFullName := qingcontainer.GetPodFullName(pod) s.podStatusesLock.Lock() defer s.podStatusesLock.Unlock() oldStatus, found := s.podStatuses[podFullName] // ensure that the start time does not change across updates. if found && oldStatus.StartTime != nil { status.StartTime = oldStatus.StartTime } // if the status has no start time, we need to set an initial time // TODO(yujuhong): Consider setting StartTime when generating the pod // status instead, which would allow statusManager to become a simple cache // again. if status.StartTime.IsZero() { if pod.Status.StartTime.IsZero() { // the pod did not have a previously recorded value so set to now now := util.Now() status.StartTime = &now } else { // the pod had a recorded value, but the qinglet restarted so we need to rebuild cache // based on last observed value status.StartTime = pod.Status.StartTime } } // TODO: Holding a lock during blocking operations is dangerous. Refactor so this isn't necessary. // The intent here is to prevent concurrent updates to a pod's status from // clobbering each other so the phase of a pod progresses monotonically. // Currently this routine is not called for the same pod from multiple // workers and/or the qinglet but dropping the lock before sending the // status down the channel feels like an easy way to get a bullet in foot. if !found || !isStatusEqual(&oldStatus, &status) { s.podStatuses[podFullName] = status s.podStatusChannel <- podStatusSyncRequest{pod, status} } else { glog.V(3).Infof("Ignoring same pod status for %q - old: %+v new: %+v", podFullName, oldStatus, status) } }
func TestSyncNamespaceThatIsTerminating(t *testing.T) { mockClient := &testclient.Fake{} now := util.Now() testNamespace := api.Namespace{ ObjectMeta: api.ObjectMeta{ Name: "test", ResourceVersion: "1", DeletionTimestamp: &now, }, Spec: api.NamespaceSpec{ Finalizers: []api.FinalizerName{"qingyuan"}, }, Status: api.NamespaceStatus{ Phase: api.NamespaceTerminating, }, } err := syncNamespace(mockClient, testNamespace) if err != nil { t.Errorf("Unexpected error when synching namespace %v", err) } // TODO: Reuse the constants for all these strings from testclient expectedActionSet := util.NewStringSet( testclient.ListControllerAction, "list-services", "list-pods", "list-resourceQuotas", "list-secrets", "list-limitRanges", "list-events", "finalize-namespace", "delete-namespace") actionSet := util.NewStringSet() for i := range mockClient.Actions { actionSet.Insert(mockClient.Actions[i].Action) } if !actionSet.HasAll(expectedActionSet.List()...) { t.Errorf("Expected actions: %v, but got: %v", expectedActionSet, actionSet) } }
func TestEventGet(t *testing.T) { objReference := &api.ObjectReference{ Kind: "foo", Namespace: "nm", Name: "objref1", UID: "uid", APIVersion: "apiv1", ResourceVersion: "1", } timeStamp := util.Now() event := &api.Event{ ObjectMeta: api.ObjectMeta{ Namespace: "other", }, InvolvedObject: *objReference, FirstTimestamp: timeStamp, LastTimestamp: timeStamp, Count: 1, } c := &testClient{ Request: testRequest{ Method: "GET", Path: testapi.ResourcePath("events", "other", "1"), Body: nil, }, Response: Response{StatusCode: 200, Body: event}, } response, err := c.Setup().Events("other").Get("1") if err != nil { t.Fatalf("%v should be nil.", err) } if e, r := event.InvolvedObject, response.InvolvedObject; !reflect.DeepEqual(e, r) { t.Errorf("%#v != %#v.", e, r) } }
// Delete enforces life-cycle rules for namespace termination func (r *REST) Delete(ctx api.Context, name string, options *api.DeleteOptions) (runtime.Object, error) { nsObj, err := r.Get(ctx, name) if err != nil { return nil, err } namespace := nsObj.(*api.Namespace) // upon first request to delete, we switch the phase to start namespace termination if namespace.DeletionTimestamp.IsZero() { now := util.Now() namespace.DeletionTimestamp = &now namespace.Status.Phase = api.NamespaceTerminating result, _, err := r.status.Update(ctx, namespace) return result, err } // prior to final deletion, we must ensure that finalizers is empty if len(namespace.Spec.Finalizers) != 0 { err = apierrors.NewConflict("Namespace", namespace.Name, fmt.Errorf("The system is ensuring all content is removed from this namespace. Upon completion, this namespace will automatically be purged by the system.")) return nil, err } return r.Etcd.Delete(ctx, name, nil) }
// FillObjectMetaSystemFields populates fields that are managed by the system on ObjectMeta. func FillObjectMetaSystemFields(ctx Context, meta *ObjectMeta) { meta.CreationTimestamp = util.Now() meta.UID = util.NewUUID() meta.SelfLink = "" }
createTimes := make(map[string]util.Time, 0) nodes := make(map[string]string, 0) scheduleTimes := make(map[string]util.Time, 0) runTimes := make(map[string]util.Time, 0) watchTimes := make(map[string]util.Time, 0) var mutex sync.Mutex checkPod := func(p *api.Pod) { mutex.Lock() defer mutex.Unlock() defer GinkgoRecover() if p.Status.Phase == api.PodRunning { if _, found := watchTimes[p.Name]; !found { watchTimes[p.Name] = util.Now() createTimes[p.Name] = p.CreationTimestamp nodes[p.Name] = p.Spec.NodeName var startTime util.Time for _, cs := range p.Status.ContainerStatuses { if cs.State.Running != nil { if startTime.Before(cs.State.Running.StartedAt) { startTime = cs.State.Running.StartedAt } } } if startTime != util.NewTime(time.Time{}) { runTimes[p.Name] = startTime } else { Failf("Pod %v is reported to be running, but none of its containers is", p.Name) }
func (f fakeRecorder) Event(object runtime.Object, reason, message string) { f.events = append(f.events, fakeEvent{object, util.Now(), reason, message}) }
func (f fakeRecorder) Eventf(object runtime.Object, reason, messageFmt string, args ...interface{}) { f.events = append(f.events, fakeEvent{object, util.Now(), reason, fmt.Sprintf(messageFmt, args...)}) }
func (recorder *recorderImpl) Event(object runtime.Object, reason, message string) { recorder.generateEvent(object, util.Now(), reason, message) }