services/allocator/allocatord: Add to creatorInfo
Add the mountName and the blessingNames to the creatorInfo annotation.
Go back to using self-blessed blessings when testing.
Change-Id: I42adb1a9a0f119b39be25deb6629986c651b3006
diff --git a/services/allocator/allocatord/cache.go b/services/allocator/allocatord/cache.go
index be7bc4a..bd5807f 100644
--- a/services/allocator/allocatord/cache.go
+++ b/services/allocator/allocatord/cache.go
@@ -9,6 +9,7 @@
"github.com/golang/groupcache/lru"
+ "v.io/v23/context"
"v.io/v23/verror"
)
@@ -17,7 +18,7 @@
ownerCacheMutex sync.Mutex
)
-func checkOwner(email, kName string) error {
+func checkOwner(ctx *context.T, email, kName string) error {
ownerCacheMutex.Lock()
if ownerCache == nil {
ownerCache = lru.New(maxInstancesFlag)
@@ -30,7 +31,7 @@
}
ownerCacheMutex.Unlock()
- if err := isOwnerOfInstance(email, kName); err != nil {
+ if err := isOwnerOfInstance(ctx, email, kName); err != nil {
return err
}
ownerCacheMutex.Lock()
diff --git a/services/allocator/allocatord/dashboard.go b/services/allocator/allocatord/dashboard.go
index 19a6ed8..fff3715 100644
--- a/services/allocator/allocatord/dashboard.go
+++ b/services/allocator/allocatord/dashboard.go
@@ -54,11 +54,12 @@
}
func handleDashboard(ss *serverState, rs *requestState) error {
+ ctx := ss.ctx
instance := rs.r.FormValue(paramDashboardName)
if instance == "" {
return fmt.Errorf("parameter %q required for instance name", paramDashboardName)
}
- if err := checkOwner(rs.email, kubeNameFromMountName(instance)); err != nil {
+ if err := checkOwner(ctx, rs.email, kubeNameFromMountName(instance)); err != nil {
return err
}
@@ -86,7 +87,7 @@
if mountedName == "" {
return fmt.Errorf("parameter %q required for instance name", paramDashboardName)
}
- if err := checkOwner(rs.email, kubeNameFromMountName(mountedName)); err != nil {
+ if err := checkOwner(ctx, rs.email, kubeNameFromMountName(mountedName)); err != nil {
return err
}
diff --git a/services/allocator/allocatord/handlers.go b/services/allocator/allocatord/handlers.go
index bdfb3fe..8635456 100644
--- a/services/allocator/allocatord/handlers.go
+++ b/services/allocator/allocatord/handlers.go
@@ -10,7 +10,6 @@
"strings"
"time"
- "v.io/v23"
"v.io/v23/security"
)
@@ -43,17 +42,21 @@
Message: rs.r.FormValue(paramMessage),
}
for _, instance := range instances {
- var patterns []string
- for _, b := range security.BlessingNames(v23.GetPrincipal(ctx), ss.args.baseBlessings) {
- bName := strings.Join([]string{b, instance.name}, security.ChainSeparator)
- patterns = append(patterns, bName)
+ if len(instance.blessingNames) == 0 {
+ // TODO(rthellend): Remove when all instances have the new
+ // creatorInfo annotations.
+ ctx.Info("blessingNames missing from creatorInfo")
+ for _, b := range ss.args.baseBlessingNames {
+ bName := strings.Join([]string{b, instance.name}, security.ChainSeparator)
+ instance.blessingNames = append(instance.blessingNames, bName)
+ }
}
tmplArgs.Instances = append(tmplArgs.Instances, instanceArg{
Name: instance.mountName,
NameRoot: nameRoot(ctx),
CreationTime: instance.creationTime,
- BlessingPatterns: patterns,
+ BlessingPatterns: instance.blessingNames,
DestroyURL: makeURL(ctx, routeDestroy, params{paramName: instance.mountName, paramCSRF: rs.csrfToken}),
DashboardURL: makeURL(ctx, routeDashboard, params{paramDashboardName: relativeMountName(instance.mountName), paramCSRF: rs.csrfToken}),
})
@@ -66,7 +69,7 @@
func handleCreate(ss *serverState, rs *requestState) error {
ctx := ss.ctx
- name, err := create(ctx, rs.email, ss.args.baseBlessings)
+ name, err := create(ctx, rs.email, ss.args.baseBlessings, ss.args.baseBlessingNames)
if err != nil {
return fmt.Errorf("create failed: %v", err)
}
diff --git a/services/allocator/allocatord/http.go b/services/allocator/allocatord/http.go
index 8b6fdb0..932cdbe 100644
--- a/services/allocator/allocatord/http.go
+++ b/services/allocator/allocatord/http.go
@@ -76,9 +76,10 @@
dashboardGCMMetric,
dashboardGCMProject,
monitoringKeyFile string
- secureCookies bool
- oauthCreds *oauthCredentials
- baseBlessings security.Blessings
+ secureCookies bool
+ oauthCreds *oauthCredentials
+ baseBlessings security.Blessings
+ baseBlessingNames []string
// URI prefix for static assets served from (another) content server.
staticAssetsPrefix string
// Manages locally served resources.
diff --git a/services/allocator/allocatord/main.go b/services/allocator/allocatord/main.go
index 661c5c6..967f1ce 100644
--- a/services/allocator/allocatord/main.go
+++ b/services/allocator/allocatord/main.go
@@ -101,19 +101,18 @@
return env.UsageErrorf("--%s not specified, and no default namespace root found", serverNameRootFlagName)
}
- var baseBlessings security.Blessings
+ var (
+ baseBlessings security.Blessings
+ baseBlessingNames []string
+ )
if clusterAgentFlag == "" || blessingSecretFlag == "" {
- fmt.Fprintln(env.Stderr, "WARNING: Using disabled blessings for allocated servers")
- p := v23.GetPrincipal(ctx)
- defaultB, _ := p.BlessingStore().Default()
- // This caveat ensures that the blessing we create cannot be used.
- disabled, err := security.NewCaveat(security.ConstCaveat, false)
- if err != nil {
+ fmt.Fprintln(env.Stderr, "WARNING: Using self-blessed blessings for allocated servers")
+ const selfName = "allocator"
+ var err error
+ if baseBlessings, err = v23.GetPrincipal(ctx).BlessSelf(selfName); err != nil {
return err
}
- if baseBlessings, err = p.Bless(p.PublicKey(), defaultB, "allocator", disabled); err != nil {
- return err
- }
+ baseBlessingNames = []string{selfName}
} else {
secret, err := ioutil.ReadFile(blessingSecretFlag)
if err != nil {
@@ -123,12 +122,13 @@
if err != nil {
return err
}
+ baseBlessingNames = security.BlessingNames(v23.GetPrincipal(ctx), baseBlessings)
}
ctx, server, err := v23.WithNewServer(
ctx,
nameFlag,
- allocator.AllocatorServer(&allocatorImpl{baseBlessings}),
+ allocator.AllocatorServer(&allocatorImpl{baseBlessings, baseBlessingNames}),
security.AllowEveryone(),
)
if err != nil {
@@ -157,6 +157,7 @@
serverName: serverNameFlag,
secureCookies: secureCookiesFlag,
baseBlessings: baseBlessings,
+ baseBlessingNames: baseBlessingNames,
staticAssetsPrefix: staticAssetsPrefixFlag,
assets: ah,
})
diff --git a/services/allocator/allocatord/service.go b/services/allocator/allocatord/service.go
index 2036300..b57d007 100644
--- a/services/allocator/allocatord/service.go
+++ b/services/allocator/allocatord/service.go
@@ -33,7 +33,8 @@
)
type allocatorImpl struct {
- baseBlessings security.Blessings
+ baseBlessings security.Blessings
+ baseBlessingNames []string
}
// Create creates a new instance of the service.
@@ -46,7 +47,7 @@
if email == "" {
return "", verror.New(verror.ErrNoAccess, ctx, "unable to determine caller's email address")
}
- return create(ctx, email, i.baseBlessings)
+ return create(ctx, email, i.baseBlessings, i.baseBlessingNames)
}
// Destroy destroys the instance with the given name.
@@ -81,17 +82,17 @@
return mNames, nil
}
-func create(ctx *context.T, email string, baseBlessings security.Blessings) (string, error) {
+func create(ctx *context.T, email string, baseBlessings security.Blessings, baseBlessingNames []string) (string, error) {
// Enforce a limit on the number of instances. These tests are a little
// bit racy. It's possible that multiple calls to create() will run
// concurrently and that we'll end up with too many instances.
- if n, err := serverInstances(email); err != nil {
+ if n, err := serverInstances(ctx, email); err != nil {
return "", err
} else if len(n) >= maxInstancesPerUserFlag {
return "", verror.New(errLimitExceeded, ctx, maxInstancesPerUserFlag)
}
- if n, err := serverInstances(""); err != nil {
+ if n, err := serverInstances(ctx, ""); err != nil {
return "", err
} else if len(n) >= maxInstancesFlag {
return "", verror.New(errGlobalLimitExceeded, ctx, maxInstancesFlag)
@@ -103,7 +104,7 @@
}
mName := mountNameFromKubeName(ctx, kName)
- cfg, cleanup, err := createDeploymentConfig(ctx, email, kName, mName)
+ cfg, cleanup, err := createDeploymentConfig(ctx, email, kName, mName, baseBlessingNames)
defer cleanup()
if err != nil {
return "", err
@@ -135,11 +136,11 @@
func destroy(ctx *context.T, email, mName string) error {
kName := kubeNameFromMountName(mName)
- if err := isOwnerOfInstance(email, kName); err != nil {
+ if err := isOwnerOfInstance(ctx, email, kName); err != nil {
return err
}
- cfg, cleanup, err := createDeploymentConfig(ctx, email, kName, mName)
+ cfg, cleanup, err := createDeploymentConfig(ctx, email, kName, mName, nil)
defer cleanup()
if err != nil {
return err
@@ -157,23 +158,31 @@
}
func list(ctx *context.T, email string) ([]serverInstance, error) {
- instances, err := serverInstances(email)
+ instances, err := serverInstances(ctx, email)
if err != nil {
return nil, err
}
for i, instance := range instances {
- instances[i].mountName = mountNameFromKubeName(ctx, instance.name)
+ // TODO(rthellend): Remove when all instances have the new
+ // creatorInfo annotations.
+ if instances[i].mountName == "" {
+ instances[i].mountName = mountNameFromKubeName(ctx, instance.name)
+ }
}
return instances, err
}
-func createDeploymentConfig(ctx *context.T, email, deploymentName, mountName string) (string, func(), error) {
+func createDeploymentConfig(ctx *context.T, email, deploymentName, mountName string, baseBlessingNames []string) (string, func(), error) {
cleanup := func() {}
acl, err := accessList(ctx, email)
if err != nil {
return "", cleanup, err
}
- creatorInfo, err := creatorInfo(ctx, email)
+ blessingNames := make([]string, len(baseBlessingNames))
+ for i, b := range baseBlessingNames {
+ blessingNames[i] = b + security.ChainSeparator + deploymentName
+ }
+ creatorInfo, err := creatorInfo(ctx, email, mountName, blessingNames)
if err != nil {
return "", cleanup, err
}
@@ -239,18 +248,21 @@
return string(j[1 : len(j)-1]), nil
}
+type creatorInfoData struct {
+ Email string `json:"email"`
+ BlessingNames []string `json:"blessingNames"`
+ MountName string `json:"mountName"`
+}
+
// creatorInfo returns a double encoded JSON access list that can be used as
// annotation in a Deployment template, e.g.
// "annotations": {
-// "v.io/allocatord/creator-info": {{.CreatorInfo}}
+// "v.io/allocator-creator-info": {{.CreatorInfo}}
// }
-func creatorInfo(ctx *context.T, email string) (string, error) {
- info := struct {
- Email string `json:"email"`
- }{email}
- j, err := json.Marshal(info)
+func creatorInfo(ctx *context.T, email, mountName string, blessingNames []string) (string, error) {
+ j, err := json.Marshal(creatorInfoData{email, blessingNames, mountName})
if err != nil {
- ctx.Errorf("json.Marshal(%#v) failed: %v", info, err)
+ ctx.Errorf("json.Marshal() failed: %v", err)
return "", err
}
// JSON encode again, because the annotation is in a JSON template.
@@ -263,22 +275,24 @@
return string(j), nil
}
+func decodeCreatorInfo(s string) (data creatorInfoData, err error) {
+ err = json.Unmarshal([]byte(s), &data)
+ return
+}
+
func emailHash(email string) string {
h := sha1.Sum([]byte(email))
return hex.EncodeToString(h[:])
}
type serverInstance struct {
- name string
- mountName string
- creationTime time.Time
+ name string
+ mountName string
+ blessingNames []string
+ creationTime time.Time
}
-func serverInstances(email string) ([]serverInstance, error) {
- // TODO(caprita): Store the mount name and server blessing name(s) as
- // annotations in the deployment, and retrieve them here. This should
- // ensure that the values are accurate, and do not depend on the version
- // of allocatord that is presenting them.
+func serverInstances(ctx *context.T, email string) ([]serverInstance, error) {
args := []string{"kubectl", "get", "deployments", "-o", "json"}
if email != "" {
args = append(args, "-l", "ownerHash="+emailHash(email))
@@ -299,8 +313,9 @@
var list struct {
Items []struct {
Metadata struct {
- Name string `json:"name"`
- CreationTime time.Time `json:"creationTimestamp"`
+ Name string `json:"name"`
+ CreationTime time.Time `json:"creationTimestamp"`
+ Annotations map[string]string `json:"annotations"`
} `json:"metadata"`
} `json:"items"`
}
@@ -309,18 +324,26 @@
}
instances := []serverInstance{}
for _, l := range list.Items {
- if strings.HasPrefix(l.Metadata.Name, serverNameFlag+"-") {
- instances = append(instances, serverInstance{
- name: l.Metadata.Name,
- creationTime: l.Metadata.CreationTime,
- })
+ if !strings.HasPrefix(l.Metadata.Name, serverNameFlag+"-") {
+ continue
}
+ cInfo, err := decodeCreatorInfo(l.Metadata.Annotations["v.io/allocator-creator-info"])
+ if err != nil {
+ ctx.Errorf("decodeCreatorInfo failed: %v", err)
+ continue
+ }
+ instances = append(instances, serverInstance{
+ name: l.Metadata.Name,
+ mountName: cInfo.MountName,
+ blessingNames: cInfo.BlessingNames,
+ creationTime: l.Metadata.CreationTime,
+ })
}
return instances, nil
}
-func isOwnerOfInstance(email, kName string) error {
- instances, err := serverInstances(email)
+func isOwnerOfInstance(ctx *context.T, email, kName string) error {
+ instances, err := serverInstances(ctx, email)
if err != nil {
return err
}