// Outputs linesTotal lines of logs to stdout uniformly for duration func generateLogs(linesTotal int, duration time.Duration) { delay := duration / time.Duration(linesTotal) rand.Seed(time.Now().UnixNano()) tick := time.Tick(delay) for id := 0; id < linesTotal; id++ { glog.Info(generateLogLine(id)) <-tick } }
func (util *FlockerUtil) CreateVolume(c *flockerVolumeProvisioner) (datasetUUID string, volumeSizeGB int, labels map[string]string, err error) { if c.flockerClient == nil { c.flockerClient, err = c.plugin.newFlockerClient("") if err != nil { return } } nodes, err := c.flockerClient.ListNodes() if err != nil { return } if len(nodes) < 1 { err = fmt.Errorf("no nodes found inside the flocker cluster to provision a dataset") return } // select random node rand.Seed(time.Now().UTC().UnixNano()) node := nodes[rand.Intn(len(nodes))] glog.V(2).Infof("selected flocker node with UUID '%s' to provision dataset", node.UUID) capacity := c.options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)] requestBytes := capacity.Value() volumeSizeGB = int(volume.RoundUpSize(requestBytes, 1024*1024*1024)) createOptions := &flockerapi.CreateDatasetOptions{ MaximumSize: requestBytes, Metadata: map[string]string{ "type": "k8s-dynamic-prov", "pvc": c.options.PVC.Name, }, Primary: node.UUID, } datasetState, err := c.flockerClient.CreateDataset(createOptions) if err != nil { return } datasetUUID = datasetState.DatasetID glog.V(2).Infof("successfully created Flocker dataset with UUID '%s'", datasetUUID) return }
func TestTokenCreation(t *testing.T) { testcases := map[string]struct { ClientObjects []runtime.Object IsAsync bool MaxRetries int Reactors []reaction ExistingServiceAccount *v1.ServiceAccount ExistingSecrets []*v1.Secret AddedServiceAccount *v1.ServiceAccount UpdatedServiceAccount *v1.ServiceAccount DeletedServiceAccount *v1.ServiceAccount AddedSecret *v1.Secret UpdatedSecret *v1.Secret DeletedSecret *v1.Secret ExpectedActions []core.Action }{ "new serviceaccount with no secrets": { ClientObjects: []runtime.Object{serviceAccount(emptySecretReferences())}, AddedServiceAccount: serviceAccount(emptySecretReferences()), ExpectedActions: []core.Action{ core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, v1.NamespaceDefault, "default"), core.NewCreateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, createdTokenSecret()), core.NewUpdateAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, v1.NamespaceDefault, serviceAccount(addTokenSecretReference(emptySecretReferences()))), }, }, "new serviceaccount with no secrets encountering create error": { ClientObjects: []runtime.Object{serviceAccount(emptySecretReferences())}, MaxRetries: 10, IsAsync: true, Reactors: []reaction{{ verb: "create", resource: "secrets", reactor: func(t *testing.T) core.ReactionFunc { i := 0 return func(core.Action) (bool, runtime.Object, error) { i++ if i < 3 { return true, nil, apierrors.NewForbidden(api.Resource("secrets"), "foo", errors.New("No can do")) } return false, nil, nil } }, }}, AddedServiceAccount: serviceAccount(emptySecretReferences()), ExpectedActions: []core.Action{ // Attempt 1 core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, v1.NamespaceDefault, "default"), core.NewCreateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, createdTokenSecret()), // Attempt 2 core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, v1.NamespaceDefault, "default"), core.NewCreateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, namedCreatedTokenSecret("default-token-x50vb")), // Attempt 3 core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, v1.NamespaceDefault, "default"), core.NewCreateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, namedCreatedTokenSecret("default-token-scq98")), core.NewUpdateAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, v1.NamespaceDefault, serviceAccount(addNamedTokenSecretReference(emptySecretReferences(), "default-token-scq98"))), }, }, "new serviceaccount with no secrets encountering unending create error": { ClientObjects: []runtime.Object{serviceAccount(emptySecretReferences()), createdTokenSecret()}, MaxRetries: 2, IsAsync: true, Reactors: []reaction{{ verb: "create", resource: "secrets", reactor: func(t *testing.T) core.ReactionFunc { return func(core.Action) (bool, runtime.Object, error) { return true, nil, apierrors.NewForbidden(api.Resource("secrets"), "foo", errors.New("No can do")) } }, }}, AddedServiceAccount: serviceAccount(emptySecretReferences()), ExpectedActions: []core.Action{ // Attempt core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, v1.NamespaceDefault, "default"), core.NewCreateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, createdTokenSecret()), // Retry 1 core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, v1.NamespaceDefault, "default"), core.NewCreateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, namedCreatedTokenSecret("default-token-x50vb")), // Retry 2 core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, v1.NamespaceDefault, "default"), core.NewCreateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, namedCreatedTokenSecret("default-token-scq98")), }, }, "new serviceaccount with missing secrets": { ClientObjects: []runtime.Object{serviceAccount(missingSecretReferences())}, AddedServiceAccount: serviceAccount(missingSecretReferences()), ExpectedActions: []core.Action{ core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, v1.NamespaceDefault, "default"), core.NewCreateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, createdTokenSecret()), core.NewUpdateAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, v1.NamespaceDefault, serviceAccount(addTokenSecretReference(missingSecretReferences()))), }, }, "new serviceaccount with non-token secrets": { ClientObjects: []runtime.Object{serviceAccount(regularSecretReferences()), opaqueSecret()}, AddedServiceAccount: serviceAccount(regularSecretReferences()), ExpectedActions: []core.Action{ core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, v1.NamespaceDefault, "default"), core.NewCreateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, createdTokenSecret()), core.NewUpdateAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, v1.NamespaceDefault, serviceAccount(addTokenSecretReference(regularSecretReferences()))), }, }, "new serviceaccount with token secrets": { ClientObjects: []runtime.Object{serviceAccount(tokenSecretReferences()), serviceAccountTokenSecret()}, ExistingSecrets: []*v1.Secret{serviceAccountTokenSecret()}, AddedServiceAccount: serviceAccount(tokenSecretReferences()), ExpectedActions: []core.Action{}, }, "new serviceaccount with no secrets with resource conflict": { ClientObjects: []runtime.Object{updatedServiceAccount(emptySecretReferences()), createdTokenSecret()}, AddedServiceAccount: serviceAccount(emptySecretReferences()), ExpectedActions: []core.Action{ core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, v1.NamespaceDefault, "default"), }, }, "updated serviceaccount with no secrets": { ClientObjects: []runtime.Object{serviceAccount(emptySecretReferences())}, UpdatedServiceAccount: serviceAccount(emptySecretReferences()), ExpectedActions: []core.Action{ core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, v1.NamespaceDefault, "default"), core.NewCreateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, createdTokenSecret()), core.NewUpdateAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, v1.NamespaceDefault, serviceAccount(addTokenSecretReference(emptySecretReferences()))), }, }, "updated serviceaccount with missing secrets": { ClientObjects: []runtime.Object{serviceAccount(missingSecretReferences())}, UpdatedServiceAccount: serviceAccount(missingSecretReferences()), ExpectedActions: []core.Action{ core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, v1.NamespaceDefault, "default"), core.NewCreateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, createdTokenSecret()), core.NewUpdateAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, v1.NamespaceDefault, serviceAccount(addTokenSecretReference(missingSecretReferences()))), }, }, "updated serviceaccount with non-token secrets": { ClientObjects: []runtime.Object{serviceAccount(regularSecretReferences()), opaqueSecret()}, UpdatedServiceAccount: serviceAccount(regularSecretReferences()), ExpectedActions: []core.Action{ core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, v1.NamespaceDefault, "default"), core.NewCreateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, createdTokenSecret()), core.NewUpdateAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, v1.NamespaceDefault, serviceAccount(addTokenSecretReference(regularSecretReferences()))), }, }, "updated serviceaccount with token secrets": { ExistingSecrets: []*v1.Secret{serviceAccountTokenSecret()}, UpdatedServiceAccount: serviceAccount(tokenSecretReferences()), ExpectedActions: []core.Action{}, }, "updated serviceaccount with no secrets with resource conflict": { ClientObjects: []runtime.Object{updatedServiceAccount(emptySecretReferences())}, UpdatedServiceAccount: serviceAccount(emptySecretReferences()), ExpectedActions: []core.Action{ core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, v1.NamespaceDefault, "default"), }, }, "deleted serviceaccount with no secrets": { DeletedServiceAccount: serviceAccount(emptySecretReferences()), ExpectedActions: []core.Action{}, }, "deleted serviceaccount with missing secrets": { DeletedServiceAccount: serviceAccount(missingSecretReferences()), ExpectedActions: []core.Action{}, }, "deleted serviceaccount with non-token secrets": { ClientObjects: []runtime.Object{opaqueSecret()}, DeletedServiceAccount: serviceAccount(regularSecretReferences()), ExpectedActions: []core.Action{}, }, "deleted serviceaccount with token secrets": { ClientObjects: []runtime.Object{serviceAccountTokenSecret()}, ExistingSecrets: []*v1.Secret{serviceAccountTokenSecret()}, DeletedServiceAccount: serviceAccount(tokenSecretReferences()), ExpectedActions: []core.Action{ core.NewDeleteAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, "token-secret-1"), }, }, "added secret without serviceaccount": { ClientObjects: []runtime.Object{serviceAccountTokenSecret()}, AddedSecret: serviceAccountTokenSecret(), ExpectedActions: []core.Action{ core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, v1.NamespaceDefault, "default"), core.NewDeleteAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, "token-secret-1"), }, }, "added secret with serviceaccount": { ExistingServiceAccount: serviceAccount(tokenSecretReferences()), AddedSecret: serviceAccountTokenSecret(), ExpectedActions: []core.Action{}, }, "added token secret without token data": { ClientObjects: []runtime.Object{serviceAccountTokenSecretWithoutTokenData()}, ExistingServiceAccount: serviceAccount(tokenSecretReferences()), AddedSecret: serviceAccountTokenSecretWithoutTokenData(), ExpectedActions: []core.Action{ core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, "token-secret-1"), core.NewUpdateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, serviceAccountTokenSecret()), }, }, "added token secret without ca data": { ClientObjects: []runtime.Object{serviceAccountTokenSecretWithoutCAData()}, ExistingServiceAccount: serviceAccount(tokenSecretReferences()), AddedSecret: serviceAccountTokenSecretWithoutCAData(), ExpectedActions: []core.Action{ core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, "token-secret-1"), core.NewUpdateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, serviceAccountTokenSecret()), }, }, "added token secret with mismatched ca data": { ClientObjects: []runtime.Object{serviceAccountTokenSecretWithCAData([]byte("mismatched"))}, ExistingServiceAccount: serviceAccount(tokenSecretReferences()), AddedSecret: serviceAccountTokenSecretWithCAData([]byte("mismatched")), ExpectedActions: []core.Action{ core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, "token-secret-1"), core.NewUpdateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, serviceAccountTokenSecret()), }, }, "added token secret without namespace data": { ClientObjects: []runtime.Object{serviceAccountTokenSecretWithoutNamespaceData()}, ExistingServiceAccount: serviceAccount(tokenSecretReferences()), AddedSecret: serviceAccountTokenSecretWithoutNamespaceData(), ExpectedActions: []core.Action{ core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, "token-secret-1"), core.NewUpdateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, serviceAccountTokenSecret()), }, }, "added token secret with custom namespace data": { ClientObjects: []runtime.Object{serviceAccountTokenSecretWithNamespaceData([]byte("custom"))}, ExistingServiceAccount: serviceAccount(tokenSecretReferences()), AddedSecret: serviceAccountTokenSecretWithNamespaceData([]byte("custom")), ExpectedActions: []core.Action{ // no update is performed... the custom namespace is preserved }, }, "updated secret without serviceaccount": { ClientObjects: []runtime.Object{serviceAccountTokenSecret()}, UpdatedSecret: serviceAccountTokenSecret(), ExpectedActions: []core.Action{ core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, v1.NamespaceDefault, "default"), core.NewDeleteAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, "token-secret-1"), }, }, "updated secret with serviceaccount": { ExistingServiceAccount: serviceAccount(tokenSecretReferences()), UpdatedSecret: serviceAccountTokenSecret(), ExpectedActions: []core.Action{}, }, "updated token secret without token data": { ClientObjects: []runtime.Object{serviceAccountTokenSecretWithoutTokenData()}, ExistingServiceAccount: serviceAccount(tokenSecretReferences()), UpdatedSecret: serviceAccountTokenSecretWithoutTokenData(), ExpectedActions: []core.Action{ core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, "token-secret-1"), core.NewUpdateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, serviceAccountTokenSecret()), }, }, "updated token secret without ca data": { ClientObjects: []runtime.Object{serviceAccountTokenSecretWithoutCAData()}, ExistingServiceAccount: serviceAccount(tokenSecretReferences()), UpdatedSecret: serviceAccountTokenSecretWithoutCAData(), ExpectedActions: []core.Action{ core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, "token-secret-1"), core.NewUpdateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, serviceAccountTokenSecret()), }, }, "updated token secret with mismatched ca data": { ClientObjects: []runtime.Object{serviceAccountTokenSecretWithCAData([]byte("mismatched"))}, ExistingServiceAccount: serviceAccount(tokenSecretReferences()), UpdatedSecret: serviceAccountTokenSecretWithCAData([]byte("mismatched")), ExpectedActions: []core.Action{ core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, "token-secret-1"), core.NewUpdateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, serviceAccountTokenSecret()), }, }, "updated token secret without namespace data": { ClientObjects: []runtime.Object{serviceAccountTokenSecretWithoutNamespaceData()}, ExistingServiceAccount: serviceAccount(tokenSecretReferences()), UpdatedSecret: serviceAccountTokenSecretWithoutNamespaceData(), ExpectedActions: []core.Action{ core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, "token-secret-1"), core.NewUpdateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, v1.NamespaceDefault, serviceAccountTokenSecret()), }, }, "updated token secret with custom namespace data": { ClientObjects: []runtime.Object{serviceAccountTokenSecretWithNamespaceData([]byte("custom"))}, ExistingServiceAccount: serviceAccount(tokenSecretReferences()), UpdatedSecret: serviceAccountTokenSecretWithNamespaceData([]byte("custom")), ExpectedActions: []core.Action{ // no update is performed... the custom namespace is preserved }, }, "deleted secret without serviceaccount": { DeletedSecret: serviceAccountTokenSecret(), ExpectedActions: []core.Action{}, }, "deleted secret with serviceaccount with reference": { ClientObjects: []runtime.Object{serviceAccount(tokenSecretReferences())}, ExistingServiceAccount: serviceAccount(tokenSecretReferences()), DeletedSecret: serviceAccountTokenSecret(), ExpectedActions: []core.Action{ core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, v1.NamespaceDefault, "default"), core.NewUpdateAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, v1.NamespaceDefault, serviceAccount(emptySecretReferences())), }, }, "deleted secret with serviceaccount without reference": { ExistingServiceAccount: serviceAccount(emptySecretReferences()), DeletedSecret: serviceAccountTokenSecret(), ExpectedActions: []core.Action{ core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, v1.NamespaceDefault, "default"), }, }, } for k, tc := range testcases { glog.Infof(k) // Re-seed to reset name generation utilrand.Seed(1) generator := &testGenerator{Token: "ABC"} client := fake.NewSimpleClientset(tc.ClientObjects...) for _, reactor := range tc.Reactors { client.Fake.PrependReactor(reactor.verb, reactor.resource, reactor.reactor(t)) } controller := NewTokensController(client, TokensControllerOptions{TokenGenerator: generator, RootCA: []byte("CA Data"), MaxRetries: tc.MaxRetries}) if tc.ExistingServiceAccount != nil { controller.serviceAccounts.Add(tc.ExistingServiceAccount) } for _, s := range tc.ExistingSecrets { controller.secrets.Add(s) } if tc.AddedServiceAccount != nil { controller.serviceAccounts.Add(tc.AddedServiceAccount) controller.queueServiceAccountSync(tc.AddedServiceAccount) } if tc.UpdatedServiceAccount != nil { controller.serviceAccounts.Add(tc.UpdatedServiceAccount) controller.queueServiceAccountUpdateSync(nil, tc.UpdatedServiceAccount) } if tc.DeletedServiceAccount != nil { controller.serviceAccounts.Delete(tc.DeletedServiceAccount) controller.queueServiceAccountSync(tc.DeletedServiceAccount) } if tc.AddedSecret != nil { controller.secrets.Add(tc.AddedSecret) controller.queueSecretSync(tc.AddedSecret) } if tc.UpdatedSecret != nil { controller.secrets.Add(tc.UpdatedSecret) controller.queueSecretUpdateSync(nil, tc.UpdatedSecret) } if tc.DeletedSecret != nil { controller.secrets.Delete(tc.DeletedSecret) controller.queueSecretSync(tc.DeletedSecret) } // This is the longest we'll wait for async tests timeout := time.Now().Add(30 * time.Second) waitedForAdditionalActions := false for { if controller.syncServiceAccountQueue.Len() > 0 { controller.syncServiceAccount() } if controller.syncSecretQueue.Len() > 0 { controller.syncSecret() } // The queues still have things to work on if controller.syncServiceAccountQueue.Len() > 0 || controller.syncSecretQueue.Len() > 0 { continue } // If we expect this test to work asynchronously... if tc.IsAsync { // if we're still missing expected actions within our test timeout if len(client.Actions()) < len(tc.ExpectedActions) && time.Now().Before(timeout) { // wait for the expected actions (without hotlooping) time.Sleep(time.Millisecond) continue } // if we exactly match our expected actions, wait a bit to make sure no other additional actions show up if len(client.Actions()) == len(tc.ExpectedActions) && !waitedForAdditionalActions { time.Sleep(time.Second) waitedForAdditionalActions = true continue } } break } if controller.syncServiceAccountQueue.Len() > 0 { t.Errorf("%s: unexpected items in service account queue: %d", k, controller.syncServiceAccountQueue.Len()) } if controller.syncSecretQueue.Len() > 0 { t.Errorf("%s: unexpected items in secret queue: %d", k, controller.syncSecretQueue.Len()) } actions := client.Actions() for i, action := range actions { if len(tc.ExpectedActions) < i+1 { t.Errorf("%s: %d unexpected actions: %+v", k, len(actions)-len(tc.ExpectedActions), actions[i:]) break } expectedAction := tc.ExpectedActions[i] if !reflect.DeepEqual(expectedAction, action) { t.Errorf("%s:\nExpected:\n%s\ngot:\n%s", k, spew.Sdump(expectedAction), spew.Sdump(action)) continue } } if len(tc.ExpectedActions) > len(actions) { t.Errorf("%s: %d additional expected actions", k, len(tc.ExpectedActions)-len(actions)) for _, a := range tc.ExpectedActions[len(actions):] { t.Logf(" %+v", a) } } } }