Add support for listing resources in state. #3981

Merged
merged 13 commits into from Jan 5, 2016
@@ -54,6 +54,10 @@ func (payloads) newPublicFacade(st *state.State, resources *common.Resources, au
}
func (c payloads) registerPublicFacade() {
+ if !markRegistered(payload.ComponentName, "public-facade") {
+ return
+ }
+
common.RegisterStandardFacade(
payload.ComponentName,
0,
@@ -188,6 +192,10 @@ func (payloads) registerHookContextCommands() {
}
func (payloads) registerState() {
+ if !markRegistered(payload.ComponentName, "state") {
+ return
+ }
+
// TODO(ericsnow) Use a more general registration mechanism.
//state.RegisterMultiEnvCollections(persistence.Collections...)
@@ -8,7 +8,6 @@ import (
"os"
"github.com/juju/errors"
- "gopkg.in/juju/charm.v6-unstable"
"github.com/juju/juju/api"
"github.com/juju/juju/api/base"
@@ -19,9 +18,9 @@ import (
"github.com/juju/juju/resource/api/client"
"github.com/juju/juju/resource/api/server"
"github.com/juju/juju/resource/cmd"
+ "github.com/juju/juju/resource/persistence"
"github.com/juju/juju/resource/state"
corestate "github.com/juju/juju/state"
- "github.com/juju/juju/state/utils"
)
// resources exposes the registration methods needed
@@ -31,6 +30,7 @@ type resources struct{}
// RegisterForServer is the top-level registration method
// for the component in a jujud context.
func (r resources) registerForServer() error {
+ r.registerState()
r.registerPublicFacade()
return nil
}
@@ -45,6 +45,10 @@ func (r resources) registerForClient() error {
// registerPublicFacade adds the resources public API facade
// to the API server.
func (r resources) registerPublicFacade() {
+ if !markRegistered(resource.ComponentName, "public-facade") {
+ return
+ }
+
common.RegisterStandardFacade(
resource.ComponentName,
server.Version,
@@ -59,23 +63,13 @@ func (resources) newPublicFacade(st *corestate.State, _ *common.Resources, autho
return nil, common.ErrPerm
}
- rst := state.NewState(&resourceState{raw: st})
- return server.NewFacade(rst), nil
-}
-
-// resourceState is a wrapper around state.State that supports the needs
-// of resources.
-type resourceState struct {
- raw *corestate.State
-}
-
-// CharmMetadata implements resource/state.RawState.
-func (st resourceState) CharmMetadata(serviceID string) (*charm.Meta, error) {
- meta, err := utils.CharmMetadata(st.raw, serviceID)
+ rst, err := st.Resources()
+ //rst, err := state.NewState(&resourceState{raw: st})
if err != nil {
return nil, errors.Trace(err)
}
- return meta, nil
+
+ return server.NewFacade(rst), nil
}
// resourcesApiClient adds a Close() method to the resources public API client.
@@ -89,6 +83,31 @@ func (client resourcesAPIClient) Close() error {
return client.closeConnFunc()
}
+// registerState registers the state functionality for resources.
+func (resources) registerState() {
+ if !markRegistered(resource.ComponentName, "state") {
+ return
+ }
+
+ newResources := func(persist corestate.Persistence) corestate.Resources {
+ st := state.NewState(&resourceState{persist: persist})
+ return st
+ }
+
+ corestate.SetResourcesComponent(newResources)
+}
+
+// resourceState is a wrapper around state.State that supports the needs
+// of resources.
+type resourceState struct {
+ persist corestate.Persistence
+}
+
+// Persistence implements resource/state.RawState.
+func (st resourceState) Persistence() state.Persistence {
+ return persistence.NewPersistence(st.persist)
+}
+
// registerPublicCommands adds the resources-related commands
// to the "juju" supercommand.
func (r resources) registerPublicCommands() {
View
@@ -49,7 +49,7 @@ gopkg.in/check.v1 git b3d3430320d4260e5fea99841af984b3badcea63 2015-06-26T10:50:
gopkg.in/errgo.v1 git 66cb46252b94c1f3d65646f54ee8043ab38d766c 2015-10-07T15:31:57Z
gopkg.in/goose.v1 git e4a91e8b8323b8eef6fe41a66fd3ac6120520bb0 2015-11-13T22:25:24Z
gopkg.in/inconshreveable/log15.v2 git b105bd37f74e5d9dc7b6ad7806715c7a2b83fd3f 2015-09-21T21:38:54Z
-gopkg.in/juju/charm.v6-unstable git 24bd2be93973af4baee76f719f6e3f370663ac2c 2015-12-15T23:08:55Z
+gopkg.in/juju/charm.v6-unstable git 0229ee1077c43e8397bb0bde071752098145c5fe 2015-12-22T19:42:03Z
gopkg.in/juju/charmrepo.v2-unstable git e738044bd65b121158cd7f37910e0debb3cfa0a5 2015-11-23T04:36:59Z
gopkg.in/juju/charmstore.v5-unstable git a3afbf1cc0b2438ef7f7fc028cc54b19bd4f91e3 2015-11-19T15:07:26Z
gopkg.in/juju/environschema.v1 git 7bea6a9a531586600a7741e9bdd5e3c978ffda15 2015-10-20T16:12:31Z
@@ -1,7 +1,7 @@
// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
-package persistence_test
+package persistence
import (
"testing"
@@ -0,0 +1,115 @@
+// Copyright 2015 Canonical Ltd.
+// Licensed under the AGPLv3, see LICENCE file for details.
+
+package persistence
+
+import (
+ "fmt"
+ "time"
+
+ "github.com/juju/errors"
+ charmresource "gopkg.in/juju/charm.v6-unstable/resource"
+ "gopkg.in/mgo.v2/bson"
+
+ "github.com/juju/juju/resource"
+)
+
+const (
+ resourcesC = "resources"
+)
+
+// resourceID converts an external resource ID into an internal one.
+func (p Persistence) resourceID(id, serviceID string) string {
+ return fmt.Sprintf("resource#%s#%s", serviceID, id)
+}
+
+// newResourceDoc generates a doc that represents the given resource.
+func (p Persistence) newResourcDoc(id, serviceID string, res resource.Resource) *resourceDoc {
+ id = p.resourceID(id, serviceID)
+
+ return &resourceDoc{
+ DocID: id,
+ ServiceID: serviceID,
+
+ Name: res.Name,
+ Type: res.Type.String(),
+ Path: res.Path,
+ Comment: res.Comment,
+
+ Origin: res.Origin.String(),
+ Revision: res.Revision,
+ Fingerprint: res.Fingerprint.Bytes(),
+
+ Username: res.Username,
+ Timestamp: res.Timestamp,
+ }
+}
+
+// resources returns the resource docs for the given service.
+func (p Persistence) resources(serviceID string) ([]resourceDoc, error) {
+ var docs []resourceDoc
+ query := bson.D{{"service-id", serviceID}}
+ if err := p.base.All(resourcesC, query, &docs); err != nil {
+ return nil, errors.Trace(err)
+ }
+ return docs, nil
+}
+
+// resourceDoc is the top-level document for resources.
+type resourceDoc struct {
+ DocID string `bson:"_id"`
+ EnvUUID string `bson:"env-uuid"`
+ ServiceID string `bson:"service-id"`
+
+ Name string `bson:"name"`
+ Type string `bson:"type"`
+ Path string `bson:"path"`
+ Comment string `bson:"comment"`
+
+ Origin string `bson:"origin"`
+ Revision int `bson:"revision"`
+ Fingerprint []byte `bson:"fingerprint"`
+
+ Username string `bson:"username"`
+ Timestamp time.Time `bson:"timestamp-when-added"`
+}
+
+// doc2resource returns the resource.Resource represented by the doc.
+func doc2resource(doc resourceDoc) (resource.Resource, error) {
+ var res resource.Resource
+
+ resType, err := charmresource.ParseType(doc.Type)
+ if err != nil {
+ return res, errors.Annotate(err, "got invalid data from DB")
+ }
+
+ origin, err := charmresource.ParseOrigin(doc.Origin)
+ if err != nil {
+ return res, errors.Annotate(err, "got invalid data from DB")
+ }
+
+ fp, err := charmresource.NewFingerprint(doc.Fingerprint)
+ if err != nil {
+ return res, errors.Annotate(err, "got invalid data from DB")
+ }
+
+ res = resource.Resource{
+ Resource: charmresource.Resource{
+ Meta: charmresource.Meta{
+ Name: doc.Name,
+ Type: resType,
+ Path: doc.Path,
+ Comment: doc.Comment,
+ },
+ Origin: origin,
+ Revision: doc.Revision,
+ Fingerprint: fp,
+ },
+ Username: doc.Username,
+ Timestamp: doc.Timestamp,
+ }
+ if err := res.Validate(); err != nil {
+ return res, errors.Annotate(err, "got invalid data from DB")
+ }
+ return res, nil
+}
@@ -0,0 +1,14 @@
+// Copyright 2015 Canonical Ltd.
+// Licensed under the AGPLv3, see LICENCE file for details.
+
+package persistence
+
+import (
+ "testing"
+
+ gc "gopkg.in/check.v1"
+)
+
+func Test(t *testing.T) {
+ gc.TestingT(t)
+}
@@ -0,0 +1,56 @@
+// Copyright 2015 Canonical Ltd.
+// Licensed under the AGPLv3, see LICENCE file for details.
+
+package persistence
+
+import (
+ "github.com/juju/errors"
+ "github.com/juju/loggo"
+
+ "github.com/juju/juju/resource"
+)
+
+var logger = loggo.GetLogger("juju.resource.persistence")
+
+// PersistenceBase exposes the core persistence functionality needed
+// for resources.
+type PersistenceBase interface {
+ // All populates docs with the list of the documents corresponding
+ // to the provided query.
+ All(collName string, query, docs interface{}) error
+}
+
+// Persistence provides the persistence functionality for the
+// Juju environment as a whole.
+type Persistence struct {
+ base PersistenceBase
+}
+
+// NewPersistence wraps the base in a new Persistence.
+func NewPersistence(base PersistenceBase) *Persistence {
+ return &Persistence{
+ base: base,
+ }
+}
+
+// ListResources returns the resource data for the given service ID.
+func (p Persistence) ListResources(serviceID string) ([]resource.Resource, error) {
+ logger.Tracef("listing all resources for service %q", serviceID)
+
+ // TODO(ericsnow) Ensure that the service is still there?
+
+ docs, err := p.resources(serviceID)
+ if err != nil {
+ return nil, errors.Trace(err)
+ }
+
+ var results []resource.Resource
+ for _, doc := range docs {
+ res, err := doc2resource(doc)
+ if err != nil {
+ return nil, errors.Trace(err)
+ }
+ results = append(results, res)
+ }
+ return results, nil
+}
Oops, something went wrong.