Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure created service account tokens are available to the token controller #21706

Merged
merged 1 commit into from
Feb 23, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 5 additions & 1 deletion pkg/controller/serviceaccount/tokens_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,8 +331,12 @@ func (e *TokensController) createSecret(serviceAccount *api.ServiceAccount) erro
}

// Save the secret
if _, err := e.client.Core().Secrets(serviceAccount.Namespace).Create(secret); err != nil {
if createdToken, err := e.client.Core().Secrets(serviceAccount.Namespace).Create(secret); err != nil {
return err
} else {
// Manually add the new token to the cache store.
// This prevents the service account update (below) triggering another token creation, if the referenced token couldn't be found in the store
e.secrets.Add(createdToken)
}

liveServiceAccount.Secrets = append(liveServiceAccount.Secrets, api.ObjectReference{Name: secret.Name})
Expand Down
116 changes: 116 additions & 0 deletions test/e2e/service_accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,129 @@ import (
"k8s.io/kubernetes/plugin/pkg/admission/serviceaccount"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var serviceAccountTokenNamespaceVersion = version.MustParse("v1.2.0")

var _ = Describe("ServiceAccounts", func() {
f := NewFramework("svcaccounts")

It("should ensure a single API token exists", func() {
// wait for the service account to reference a single secret
var secrets []api.ObjectReference
expectNoError(wait.Poll(time.Millisecond*500, time.Second*10, func() (bool, error) {
By("waiting for a single token reference")
sa, err := f.Client.ServiceAccounts(f.Namespace.Name).Get("default")
if apierrors.IsNotFound(err) {
Logf("default service account was not found")
return false, nil
}
if err != nil {
Logf("error getting default service account: %v", err)
return false, err
}
switch len(sa.Secrets) {
case 0:
Logf("default service account has no secret references")
return false, nil
case 1:
Logf("default service account has a single secret reference")
secrets = sa.Secrets
return true, nil
default:
return false, fmt.Errorf("default service account has too many secret references: %#v", sa.Secrets)
}
}))

// make sure the reference doesn't flutter
{
By("ensuring the single token reference persists")
time.Sleep(2 * time.Second)
sa, err := f.Client.ServiceAccounts(f.Namespace.Name).Get("default")
expectNoError(err)
Expect(sa.Secrets).To(Equal(secrets))
}

// delete the referenced secret
By("deleting the service account token")
expectNoError(f.Client.Secrets(f.Namespace.Name).Delete(secrets[0].Name))

// wait for the referenced secret to be removed, and another one autocreated
expectNoError(wait.Poll(time.Millisecond*500, time.Second*10, func() (bool, error) {
By("waiting for a new token reference")
sa, err := f.Client.ServiceAccounts(f.Namespace.Name).Get("default")
if err != nil {
Logf("error getting default service account: %v", err)
return false, err
}
switch len(sa.Secrets) {
case 0:
Logf("default service account has no secret references")
return false, nil
case 1:
if sa.Secrets[0] == secrets[0] {
Logf("default service account still has the deleted secret reference")
return false, nil
}
Logf("default service account has a new single secret reference")
secrets = sa.Secrets
return true, nil
default:
return false, fmt.Errorf("default service account has too many secret references: %#v", sa.Secrets)
}
}))

// make sure the reference doesn't flutter
{
By("ensuring the single token reference persists")
time.Sleep(2 * time.Second)
sa, err := f.Client.ServiceAccounts(f.Namespace.Name).Get("default")
expectNoError(err)
Expect(sa.Secrets).To(Equal(secrets))
}

// delete the reference from the service account
By("deleting the reference to the service account token")
{
sa, err := f.Client.ServiceAccounts(f.Namespace.Name).Get("default")
expectNoError(err)
sa.Secrets = nil
_, updateErr := f.Client.ServiceAccounts(f.Namespace.Name).Update(sa)
expectNoError(updateErr)
}

// wait for another one to be autocreated
expectNoError(wait.Poll(time.Millisecond*500, time.Second*10, func() (bool, error) {
By("waiting for a new token to be created and added")
sa, err := f.Client.ServiceAccounts(f.Namespace.Name).Get("default")
if err != nil {
Logf("error getting default service account: %v", err)
return false, err
}
switch len(sa.Secrets) {
case 0:
Logf("default service account has no secret references")
return false, nil
case 1:
Logf("default service account has a new single secret reference")
secrets = sa.Secrets
return true, nil
default:
return false, fmt.Errorf("default service account has too many secret references: %#v", sa.Secrets)
}
}))

// make sure the reference doesn't flutter
{
By("ensuring the single token reference persists")
time.Sleep(2 * time.Second)
sa, err := f.Client.ServiceAccounts(f.Namespace.Name).Get("default")
expectNoError(err)
Expect(sa.Secrets).To(Equal(secrets))
}
})

It("should mount an API token into pods [Conformance]", func() {
var tokenContent string
var rootCAContent string
Expand Down