blob: bf01b56006c74daddf7c445982cbbb68462c7504 [file] [log] [blame]
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001package impl
2
3import (
Bogdan Capritac87a9142014-07-21 10:38:13 -07004 "fmt"
Gautham82bb9952014-08-28 14:11:51 -07005 "os"
6 "path/filepath"
Bogdan Caprita4d67c042014-08-19 10:41:19 -07007 "strings"
Jiri Simsa24e87aa2014-06-09 09:27:34 -07008
Gautham82bb9952014-08-28 14:11:51 -07009 vsecurity "veyron/security"
10 vflag "veyron/security/flag"
11 "veyron/security/serialization"
Bogdan Caprita4d67c042014-08-19 10:41:19 -070012 inode "veyron/services/mgmt/node"
Bogdan Capritac87a9142014-07-21 10:38:13 -070013 "veyron/services/mgmt/node/config"
Jiri Simsa24e87aa2014-06-09 09:27:34 -070014
Jiri Simsa5293dcb2014-05-10 09:56:38 -070015 "veyron2/ipc"
Gautham82bb9952014-08-28 14:11:51 -070016 "veyron2/rt"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070017 "veyron2/security"
Bogdan Caprita4d67c042014-08-19 10:41:19 -070018 "veyron2/services/mgmt/node"
19 "veyron2/verror"
Gautham82bb9952014-08-28 14:11:51 -070020 "veyron2/vlog"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070021)
22
Bogdan Caprita4d67c042014-08-19 10:41:19 -070023// internalState wraps state shared between different node manager
24// invocations.
25type internalState struct {
26 callback *callbackState
27 updating *updatingState
28}
29
Jiri Simsa5293dcb2014-05-10 09:56:38 -070030// dispatcher holds the state of the node manager dispatcher.
31type dispatcher struct {
Bogdan Caprita4d67c042014-08-19 10:41:19 -070032 auth security.Authorizer
33 // internal holds the state that persists across RPC method invocations.
Bogdan Capritac87a9142014-07-21 10:38:13 -070034 internal *internalState
Bogdan Caprita4d67c042014-08-19 10:41:19 -070035 // config holds the node manager's (immutable) configuration state.
36 config *config.State
Jiri Simsa5293dcb2014-05-10 09:56:38 -070037}
38
Bogdan Caprita4d67c042014-08-19 10:41:19 -070039const (
40 appsSuffix = "apps"
41 nodeSuffix = "nm"
42 configSuffix = "cfg"
43)
44
45var (
46 errInvalidSuffix = verror.BadArgf("invalid suffix")
47 errOperationFailed = verror.Internalf("operation failed")
48 errInProgress = verror.Existsf("operation in progress")
49 errIncompatibleUpdate = verror.BadArgf("update failed: mismatching app title")
50 errUpdateNoOp = verror.NotFoundf("no different version available")
51 errNotExist = verror.NotFoundf("object does not exist")
52 errInvalidOperation = verror.BadArgf("invalid operation")
Gautham82bb9952014-08-28 14:11:51 -070053 errInvalidBlessing = verror.BadArgf("invalid claim blessing")
Bogdan Caprita4d67c042014-08-19 10:41:19 -070054)
55
Jiri Simsa24e87aa2014-06-09 09:27:34 -070056// NewDispatcher is the node manager dispatcher factory.
Gautham82bb9952014-08-28 14:11:51 -070057func NewDispatcher(config *config.State) (*dispatcher, error) {
Bogdan Capritac87a9142014-07-21 10:38:13 -070058 if err := config.Validate(); err != nil {
59 return nil, fmt.Errorf("Invalid config %v: %v", config, err)
60 }
Gautham82bb9952014-08-28 14:11:51 -070061 d := &dispatcher{
Bogdan Capritac87a9142014-07-21 10:38:13 -070062 internal: &internalState{
Bogdan Caprita78b62162014-08-21 15:35:08 -070063 callback: newCallbackState(config.Name),
Bogdan Caprita4d67c042014-08-19 10:41:19 -070064 updating: newUpdatingState(),
Jiri Simsa70c32052014-06-18 11:38:21 -070065 },
Bogdan Capritac87a9142014-07-21 10:38:13 -070066 config: config,
Gautham82bb9952014-08-28 14:11:51 -070067 }
68 // Prefer ACLs in the nodemanager data directory if they exist.
69 if data, sig, err := d.getACLFiles(os.O_RDONLY); err != nil {
70 if d.auth = vflag.NewAuthorizerOrDie(); d.auth == nil {
71 // If there are no specified ACLs we grant nodemanager access to all
72 // principal until it is claimed.
73 d.auth = vsecurity.NewACLAuthorizer(vsecurity.OpenACL())
74 }
75 } else {
76 defer data.Close()
77 defer sig.Close()
78 reader, err := serialization.NewVerifyingReader(data, sig, rt.R().Identity().PublicKey())
79 if err != nil {
80 return nil, fmt.Errorf("Failed to read nodemanager ACL file:%v", err)
81 }
82 acl, err := vsecurity.LoadACL(reader)
83 if err != nil {
84 return nil, fmt.Errorf("Failed to load nodemanager ACL:%v", err)
85 }
86 d.auth = vsecurity.NewACLAuthorizer(acl)
87 }
88 return d, nil
89}
90
91func (d *dispatcher) getACLFiles(flag int) (aclData *os.File, aclSig *os.File, err error) {
92 nodedata := filepath.Join(d.config.Root, "node-manager", "node-data")
93 perm := os.FileMode(0700)
94 if err = os.MkdirAll(nodedata, perm); err != nil {
95 return
96 }
97 if aclData, err = os.OpenFile(filepath.Join(nodedata, "acl.nodemanager"), flag, perm); err != nil {
98 return
99 }
100 if aclSig, err = os.OpenFile(filepath.Join(nodedata, "acl.signature"), flag, perm); err != nil {
101 return
102 }
103 return
104}
105
106func (d *dispatcher) claimNodeManager(id security.PublicID) error {
107 // TODO(gauthamt): Should we start trusting these identity providers?
108 if id.Names() == nil {
109 vlog.Errorf("Identity provider for device claimer is not trusted")
110 return errOperationFailed
111 }
112 rt.R().PublicIDStore().Add(id, security.AllPrincipals)
113 // Create ACLs to transfer nodemanager permissions to the provided identity.
114 acl := security.ACL{In: make(map[security.BlessingPattern]security.LabelSet)}
115 for _, name := range id.Names() {
116 acl.In[security.BlessingPattern(name)] = security.AllLabels
117 }
118 d.auth = vsecurity.NewACLAuthorizer(acl)
119 // Write out the ACLs so that it will persist across restarts.
120 data, sig, err := d.getACLFiles(os.O_CREATE | os.O_RDWR)
121 if err != nil {
122 vlog.Errorf("Failed to create ACL files:%v", err)
123 return errOperationFailed
124 }
125 writer, err := serialization.NewSigningWriteCloser(data, sig, rt.R().Identity(), nil)
126 if err != nil {
127 vlog.Errorf("Failed to create NewSigningWriteCloser:%v", err)
128 return errOperationFailed
129 }
130 if err = vsecurity.SaveACL(writer, acl); err != nil {
131 vlog.Errorf("Failed to SaveACL:%v", err)
132 return errOperationFailed
133 }
134 if err = writer.Close(); err != nil {
135 vlog.Errorf("Failed to Close() SigningWriteCloser:%v", err)
136 return errOperationFailed
137 }
138 return nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700139}
140
141// DISPATCHER INTERFACE IMPLEMENTATION
142
Cosmos Nicolaou8bfacf22014-08-19 11:19:36 -0700143func (d *dispatcher) Lookup(suffix, method string) (ipc.Invoker, security.Authorizer, error) {
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700144 components := strings.Split(suffix, "/")
145 for i := 0; i < len(components); i++ {
146 if len(components[i]) == 0 {
147 components = append(components[:i], components[i+1:]...)
148 i--
149 }
150 }
151 if len(components) == 0 {
152 return nil, nil, errInvalidSuffix
153 }
154 // The implementation of the node manager is split up into several
155 // invokers, which are instantiated depending on the receiver name
156 // prefix.
157 var receiver interface{}
158 switch components[0] {
159 case nodeSuffix:
160 receiver = node.NewServerNode(&nodeInvoker{
161 callback: d.internal.callback,
162 updating: d.internal.updating,
163 config: d.config,
Gautham82bb9952014-08-28 14:11:51 -0700164 disp: d,
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700165 })
166 case appsSuffix:
167 receiver = node.NewServerApplication(&appInvoker{
168 callback: d.internal.callback,
169 config: d.config,
170 suffix: components[1:],
171 })
172 case configSuffix:
173 if len(components) != 2 {
174 return nil, nil, errInvalidSuffix
175 }
176 receiver = inode.NewServerConfig(&configInvoker{
177 callback: d.internal.callback,
178 suffix: components[1],
179 })
180 default:
181 return nil, nil, errInvalidSuffix
182 }
183 return ipc.ReflectInvoker(receiver), d.auth, nil
Jiri Simsa24e87aa2014-06-09 09:27:34 -0700184}