Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 1 | package impl |
| 2 | |
| 3 | import ( |
| 4 | "errors" |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 5 | |
| 6 | "veyron/services/mgmt/profile" |
| 7 | |
| 8 | "veyron2/ipc" |
Adam Sadovsky | 04c5eef | 2014-07-30 17:33:27 -0700 | [diff] [blame] | 9 | "veyron2/naming" |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 10 | "veyron2/storage" |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 11 | "veyron2/vlog" |
| 12 | ) |
| 13 | |
Jiri Simsa | ddbfebb | 2014-06-20 15:56:06 -0700 | [diff] [blame] | 14 | // invoker holds the profile repository invocation. |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 15 | type invoker struct { |
| 16 | // store is the storage server used for storing profile data. |
| 17 | store storage.Store |
| 18 | // suffix is the suffix of the current invocation that is assumed to |
Bogdan Caprita | d9281a3 | 2014-07-02 14:40:39 -0700 | [diff] [blame] | 19 | // be used as a relative object name to identify a profile |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 20 | // specification. |
| 21 | suffix string |
| 22 | } |
| 23 | |
| 24 | var ( |
| 25 | errNotFound = errors.New("not found") |
| 26 | errOperationFailed = errors.New("operation failed") |
| 27 | ) |
| 28 | |
| 29 | // NewInvoker is the invoker factory. |
| 30 | func NewInvoker(store storage.Store, suffix string) *invoker { |
| 31 | return &invoker{store: store, suffix: suffix} |
| 32 | } |
| 33 | |
| 34 | // STORE MANAGEMENT INTERFACE IMPLEMENTATION |
| 35 | |
| 36 | // dir is used to organize directory contents in the store. |
| 37 | type dir struct{} |
| 38 | |
| 39 | // makeParentNodes creates the parent nodes if they do not already exist. |
Adam Sadovsky | 04c5eef | 2014-07-30 17:33:27 -0700 | [diff] [blame] | 40 | func makeParentNodes(context ipc.ServerContext, store storage.Store, path string) error { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 41 | pathComponents := storage.ParsePath(path) |
| 42 | for i := 0; i < len(pathComponents); i++ { |
| 43 | name := pathComponents[:i].String() |
Adam Sadovsky | 04c5eef | 2014-07-30 17:33:27 -0700 | [diff] [blame] | 44 | object := store.BindObject(name) |
| 45 | if _, err := object.Get(context); err != nil { |
| 46 | if _, err := object.Put(context, &dir{}); err != nil { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 47 | return errOperationFailed |
| 48 | } |
| 49 | } |
| 50 | } |
| 51 | return nil |
| 52 | } |
| 53 | |
Matt Rosencrantz | f5afcaf | 2014-06-02 11:31:22 -0700 | [diff] [blame] | 54 | func (i *invoker) Put(context ipc.ServerContext, profile profile.Specification) error { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 55 | vlog.VI(0).Infof("%v.Put(%v)", i.suffix, profile) |
Adam Sadovsky | 04c5eef | 2014-07-30 17:33:27 -0700 | [diff] [blame] | 56 | // Transaction is rooted at "", so tname == tid. |
| 57 | tname, err := i.store.BindTransactionRoot("").CreateTransaction(context) |
| 58 | if err != nil { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 59 | return err |
| 60 | } |
Ken Ashcraft | 7ca37d9 | 2014-08-12 17:46:43 -0700 | [diff] [blame] | 61 | path := naming.Join(tname, "/profiles", i.suffix) |
Adam Sadovsky | 04c5eef | 2014-07-30 17:33:27 -0700 | [diff] [blame] | 62 | if err := makeParentNodes(context, i.store, path); err != nil { |
| 63 | return err |
| 64 | } |
| 65 | object := i.store.BindObject(path) |
| 66 | if _, err := object.Put(context, profile); err != nil { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 67 | return errOperationFailed |
| 68 | } |
Adam Sadovsky | 04c5eef | 2014-07-30 17:33:27 -0700 | [diff] [blame] | 69 | if err := i.store.BindTransaction(tname).Commit(context); err != nil { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 70 | return errOperationFailed |
| 71 | } |
| 72 | return nil |
| 73 | } |
| 74 | |
Matt Rosencrantz | f5afcaf | 2014-06-02 11:31:22 -0700 | [diff] [blame] | 75 | func (i *invoker) Remove(context ipc.ServerContext) error { |
Cosmos Nicolaou | ef43dc4 | 2014-06-13 14:38:51 -0700 | [diff] [blame] | 76 | vlog.VI(0).Infof("%v.Remove()", i.suffix) |
Adam Sadovsky | 04c5eef | 2014-07-30 17:33:27 -0700 | [diff] [blame] | 77 | // Transaction is rooted at "", so tname == tid. |
| 78 | tname, err := i.store.BindTransactionRoot("").CreateTransaction(context) |
| 79 | if err != nil { |
| 80 | return err |
| 81 | } |
Ken Ashcraft | 7ca37d9 | 2014-08-12 17:46:43 -0700 | [diff] [blame] | 82 | path := naming.Join(tname, "/profiles", i.suffix) |
Adam Sadovsky | 04c5eef | 2014-07-30 17:33:27 -0700 | [diff] [blame] | 83 | object := i.store.BindObject(path) |
| 84 | found, err := object.Exists(context) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 85 | if err != nil { |
| 86 | return errOperationFailed |
| 87 | } |
| 88 | if !found { |
| 89 | return errNotFound |
| 90 | } |
Adam Sadovsky | 04c5eef | 2014-07-30 17:33:27 -0700 | [diff] [blame] | 91 | if err := object.Remove(context); err != nil { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 92 | return errOperationFailed |
| 93 | } |
Adam Sadovsky | 04c5eef | 2014-07-30 17:33:27 -0700 | [diff] [blame] | 94 | if err := i.store.BindTransaction(tname).Commit(context); err != nil { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 95 | return errOperationFailed |
| 96 | } |
| 97 | return nil |
| 98 | } |
| 99 | |
| 100 | // PROFILE INTERACE IMPLEMENTATION |
| 101 | |
Matt Rosencrantz | f5afcaf | 2014-06-02 11:31:22 -0700 | [diff] [blame] | 102 | func (i *invoker) lookup(context ipc.ServerContext) (profile.Specification, error) { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 103 | empty := profile.Specification{} |
Ken Ashcraft | 7ca37d9 | 2014-08-12 17:46:43 -0700 | [diff] [blame] | 104 | path := naming.Join("/profiles", i.suffix) |
Adam Sadovsky | 04c5eef | 2014-07-30 17:33:27 -0700 | [diff] [blame] | 105 | entry, err := i.store.BindObject(path).Get(context) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 106 | if err != nil { |
| 107 | return empty, errNotFound |
| 108 | } |
| 109 | s, ok := entry.Value.(profile.Specification) |
| 110 | if !ok { |
| 111 | return empty, errOperationFailed |
| 112 | } |
| 113 | return s, nil |
| 114 | } |
| 115 | |
Matt Rosencrantz | f5afcaf | 2014-06-02 11:31:22 -0700 | [diff] [blame] | 116 | func (i *invoker) Label(context ipc.ServerContext) (string, error) { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 117 | vlog.VI(0).Infof("%v.Label()", i.suffix) |
Matt Rosencrantz | f5afcaf | 2014-06-02 11:31:22 -0700 | [diff] [blame] | 118 | s, err := i.lookup(context) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 119 | if err != nil { |
| 120 | return "", err |
| 121 | } |
| 122 | return s.Label, nil |
| 123 | } |
| 124 | |
Matt Rosencrantz | f5afcaf | 2014-06-02 11:31:22 -0700 | [diff] [blame] | 125 | func (i *invoker) Description(context ipc.ServerContext) (string, error) { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 126 | vlog.VI(0).Infof("%v.Description()", i.suffix) |
Matt Rosencrantz | f5afcaf | 2014-06-02 11:31:22 -0700 | [diff] [blame] | 127 | s, err := i.lookup(context) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 128 | if err != nil { |
| 129 | return "", err |
| 130 | } |
| 131 | return s.Description, nil |
| 132 | } |
| 133 | |
Matt Rosencrantz | f5afcaf | 2014-06-02 11:31:22 -0700 | [diff] [blame] | 134 | func (i *invoker) Specification(context ipc.ServerContext) (profile.Specification, error) { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 135 | vlog.VI(0).Infof("%v.Specification()", i.suffix) |
Matt Rosencrantz | f5afcaf | 2014-06-02 11:31:22 -0700 | [diff] [blame] | 136 | return i.lookup(context) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 137 | } |