Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 1 | package rt |
| 2 | |
| 3 | import ( |
| 4 | "fmt" |
| 5 | "time" |
| 6 | |
| 7 | _ "v.io/core/veyron/lib/stats/sysstats" |
| 8 | "v.io/core/veyron2" |
| 9 | "v.io/core/veyron2/context" |
| 10 | "v.io/core/veyron2/ipc" |
| 11 | "v.io/core/veyron2/ipc/stream" |
| 12 | "v.io/core/veyron2/naming" |
| 13 | "v.io/core/veyron2/options" |
| 14 | "v.io/core/veyron2/security" |
| 15 | "v.io/core/veyron2/vlog" |
| 16 | "v.io/core/veyron2/vtrace" |
| 17 | |
| 18 | //iipc "v.io/core/veyron/runtimes/google/ipc" |
| 19 | iipc "v.io/core/veyron/runtimes/google/ipc" |
| 20 | imanager "v.io/core/veyron/runtimes/google/ipc/stream/manager" |
| 21 | "v.io/core/veyron/runtimes/google/ipc/stream/vc" |
| 22 | inaming "v.io/core/veyron/runtimes/google/naming" |
| 23 | "v.io/core/veyron/runtimes/google/naming/namespace" |
| 24 | ivtrace "v.io/core/veyron/runtimes/google/vtrace" |
| 25 | ) |
| 26 | |
| 27 | type contextKey int |
| 28 | |
| 29 | const ( |
| 30 | streamManagerKey = contextKey(iota) |
| 31 | clientKey |
| 32 | namespaceKey |
| 33 | loggerKey |
| 34 | principalKey |
| 35 | vtraceKey |
| 36 | reservedNameKey |
Suharsh Sivakumar | 033a30e | 2015-01-07 13:54:43 -0800 | [diff] [blame^] | 37 | profileKey |
| 38 | appCycleKey |
| 39 | listenSpecKey |
Suharsh Sivakumar | ba56393 | 2015-01-06 15:15:50 -0800 | [diff] [blame] | 40 | protocolsKey |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 41 | ) |
| 42 | |
| 43 | func init() { |
| 44 | veyron2.RegisterRuntime("google", &RuntimeX{}) |
| 45 | } |
| 46 | |
| 47 | // initRuntimeXContext provides compatibility between Runtime and RuntimeX. |
| 48 | // It is only used during the transition between runtime and |
| 49 | // RuntimeX. It populates a context with all the subparts that the |
| 50 | // new interface expects to be present. In the future this work will |
| 51 | // be replaced by RuntimeX.Init() |
| 52 | // TODO(mattr): Remove this after the runtime->runtimex transistion. |
| 53 | func (rt *vrt) initRuntimeXContext(ctx *context.T) *context.T { |
| 54 | ctx = context.WithValue(ctx, streamManagerKey, rt.sm[0]) |
| 55 | ctx = context.WithValue(ctx, clientKey, rt.client) |
| 56 | ctx = context.WithValue(ctx, namespaceKey, rt.ns) |
| 57 | ctx = context.WithValue(ctx, loggerKey, vlog.Log) |
| 58 | ctx = context.WithValue(ctx, principalKey, rt.principal) |
| 59 | ctx = context.WithValue(ctx, vtraceKey, rt.traceStore) |
| 60 | return ctx |
| 61 | } |
| 62 | |
| 63 | // RuntimeX implements the veyron2.RuntimeX interface. It is stateless. |
| 64 | // Please see the interface definition for documentation of the |
| 65 | // individiual methods. |
| 66 | type RuntimeX struct{} |
| 67 | |
| 68 | // TODO(mattr): This function isn't used yet. We'll implement it later |
| 69 | // in the transition. |
Suharsh Sivakumar | 033a30e | 2015-01-07 13:54:43 -0800 | [diff] [blame^] | 70 | func (*RuntimeX) Init(ctx *context.T) *context.T { |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 71 | // TODO(mattr): Here we need to do a bunch of one time init, like parsing flags |
| 72 | // and reading the credentials, init logging and verror, start an appcycle manager. |
| 73 | // TODO(mattr): Here we need to arrange for a long of one time cleanup |
| 74 | // when cancel is called. Dump vtrace, shotdown signalhandling, shutdownlogging, |
| 75 | // shutdown the appcyclemanager. |
Suharsh Sivakumar | 033a30e | 2015-01-07 13:54:43 -0800 | [diff] [blame^] | 76 | return nil |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 77 | } |
| 78 | |
| 79 | func (*RuntimeX) NewEndpoint(ep string) (naming.Endpoint, error) { |
| 80 | return inaming.NewEndpoint(ep) |
| 81 | } |
| 82 | |
| 83 | func (r *RuntimeX) NewServer(ctx *context.T, opts ...ipc.ServerOpt) (ipc.Server, error) { |
| 84 | // Create a new RoutingID (and StreamManager) for each server. |
| 85 | _, sm, err := r.SetNewStreamManager(ctx) |
| 86 | if err != nil { |
| 87 | return nil, fmt.Errorf("failed to create ipc/stream/Manager: %v", err) |
| 88 | } |
| 89 | |
| 90 | ns, _ := ctx.Value(namespaceKey).(naming.Namespace) |
| 91 | principal, _ := ctx.Value(principalKey).(security.Principal) |
| 92 | |
| 93 | otherOpts := append([]ipc.ServerOpt{}, opts...) |
| 94 | otherOpts = append(otherOpts, vc.LocalPrincipal{principal}) |
| 95 | if reserved, ok := ctx.Value(reservedNameKey).(*reservedNameDispatcher); ok { |
| 96 | otherOpts = append(otherOpts, options.ReservedNameDispatcher{reserved.dispatcher}) |
| 97 | otherOpts = append(otherOpts, reserved.opts...) |
| 98 | } |
| 99 | // TODO(mattr): We used to get rt.preferredprotocols here, should we |
| 100 | // attach these to the context directly? |
| 101 | |
| 102 | traceStore, _ := ctx.Value(vtraceKey).(*ivtrace.Store) |
| 103 | server, err := iipc.InternalNewServer(ctx, sm, ns, traceStore, otherOpts...) |
| 104 | if done := ctx.Done(); err == nil && done != nil { |
| 105 | // Arrange to clean up the server when the parent context is canceled. |
| 106 | // TODO(mattr): Should we actually do this? Or just have users clean |
| 107 | // their own servers up manually? |
| 108 | go func() { |
| 109 | <-done |
| 110 | server.Stop() |
| 111 | }() |
| 112 | } |
| 113 | return server, err |
| 114 | } |
| 115 | |
| 116 | func (r *RuntimeX) setNewStreamManager(ctx *context.T, opts ...stream.ManagerOpt) (*context.T, stream.Manager, error) { |
| 117 | rid, err := naming.NewRoutingID() |
| 118 | if err != nil { |
| 119 | return ctx, nil, err |
| 120 | } |
| 121 | sm := imanager.InternalNew(rid) |
| 122 | ctx = context.WithValue(ctx, streamManagerKey, sm) |
| 123 | |
| 124 | // Arrange for the manager to shut itself down when the context is canceled. |
| 125 | if done := ctx.Done(); done != nil { |
| 126 | go func() { |
| 127 | <-done |
| 128 | sm.Shutdown() |
| 129 | }() |
| 130 | } |
| 131 | |
| 132 | return ctx, sm, nil |
| 133 | } |
| 134 | |
| 135 | func (r *RuntimeX) SetNewStreamManager(ctx *context.T, opts ...stream.ManagerOpt) (*context.T, stream.Manager, error) { |
| 136 | newctx, sm, err := r.setNewStreamManager(ctx, opts...) |
| 137 | if err != nil { |
| 138 | return ctx, nil, err |
| 139 | } |
| 140 | |
| 141 | // Create a new client since it depends on the stream manager. |
| 142 | newctx, _, err = r.SetNewClient(newctx) |
| 143 | if err != nil { |
| 144 | return ctx, nil, err |
| 145 | } |
| 146 | |
| 147 | return newctx, sm, nil |
| 148 | } |
| 149 | |
Suharsh Sivakumar | 033a30e | 2015-01-07 13:54:43 -0800 | [diff] [blame^] | 150 | func (*RuntimeX) GetStreamManager(ctx *context.T) stream.Manager { |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 151 | cl, _ := ctx.Value(streamManagerKey).(stream.Manager) |
| 152 | return cl |
| 153 | } |
| 154 | |
| 155 | func (r *RuntimeX) SetPrincipal(ctx *context.T, principal security.Principal) (*context.T, error) { |
| 156 | var err error |
| 157 | newctx := ctx |
| 158 | |
| 159 | newctx = context.WithValue(newctx, principalKey, principal) |
| 160 | |
| 161 | // TODO(mattr, suharshs): The stream manager holds a cache of vifs |
| 162 | // which were negotiated with the principal, so we replace it here when the |
| 163 | // principal changes. However we should negotiate the vif with a |
| 164 | // random principal and then we needn't replace this here. |
| 165 | if newctx, _, err = r.setNewStreamManager(newctx); err != nil { |
| 166 | return ctx, err |
| 167 | } |
Suharsh Sivakumar | 033a30e | 2015-01-07 13:54:43 -0800 | [diff] [blame^] | 168 | if newctx, _, err = r.setNewNamespace(newctx, r.GetNamespace(ctx).Roots()...); err != nil { |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 169 | return ctx, err |
| 170 | } |
| 171 | if newctx, _, err = r.SetNewClient(newctx); err != nil { |
| 172 | return ctx, err |
| 173 | } |
| 174 | |
| 175 | return newctx, nil |
| 176 | } |
| 177 | |
Suharsh Sivakumar | 033a30e | 2015-01-07 13:54:43 -0800 | [diff] [blame^] | 178 | func (*RuntimeX) GetPrincipal(ctx *context.T) security.Principal { |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 179 | p, _ := ctx.Value(principalKey).(security.Principal) |
| 180 | return p |
| 181 | } |
| 182 | |
| 183 | func (*RuntimeX) SetNewClient(ctx *context.T, opts ...ipc.ClientOpt) (*context.T, ipc.Client, error) { |
| 184 | // TODO(mattr, suharshs): Currently there are a lot of things that can come in as opts. |
| 185 | // Some of them will be removed as opts and simply be pulled from the context instead |
| 186 | // these are: |
| 187 | // stream.Manager, Namespace, LocalPrincipal |
| 188 | sm, _ := ctx.Value(streamManagerKey).(stream.Manager) |
| 189 | ns, _ := ctx.Value(namespaceKey).(naming.Namespace) |
| 190 | p, _ := ctx.Value(principalKey).(security.Principal) |
Suharsh Sivakumar | ba56393 | 2015-01-06 15:15:50 -0800 | [diff] [blame] | 191 | protocols, _ := ctx.Value(protocolsKey).([]string) |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 192 | |
| 193 | // TODO(mattr, suharshs): Some will need to ba accessible from the |
| 194 | // client so that we can replace the client transparantly: |
| 195 | // VCSecurityLevel, PreferredProtocols |
| 196 | // Currently we are ignoring these and the settings will be lost in some cases. |
| 197 | // We should try to retrieve them from the client currently attached to the context |
| 198 | // where possible. |
| 199 | otherOpts := append([]ipc.ClientOpt{}, opts...) |
| 200 | |
| 201 | // Note we always add DialTimeout, so we don't have to worry about replicating the option. |
Suharsh Sivakumar | ba56393 | 2015-01-06 15:15:50 -0800 | [diff] [blame] | 202 | otherOpts = append(otherOpts, vc.LocalPrincipal{p}, &imanager.DialTimeout{5 * time.Minute}, options.PreferredProtocols(protocols)) |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 203 | |
| 204 | client, err := iipc.InternalNewClient(sm, ns, otherOpts...) |
| 205 | if err == nil { |
| 206 | ctx = context.WithValue(ctx, clientKey, client) |
| 207 | } |
| 208 | return ctx, client, err |
| 209 | } |
| 210 | |
Suharsh Sivakumar | 033a30e | 2015-01-07 13:54:43 -0800 | [diff] [blame^] | 211 | func (*RuntimeX) GetClient(ctx *context.T) ipc.Client { |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 212 | cl, _ := ctx.Value(clientKey).(ipc.Client) |
| 213 | return cl |
| 214 | } |
| 215 | |
| 216 | func (*RuntimeX) SetNewSpan(ctx *context.T, name string) (*context.T, vtrace.Span) { |
| 217 | return ivtrace.WithNewSpan(ctx, name) |
| 218 | } |
| 219 | |
Suharsh Sivakumar | 033a30e | 2015-01-07 13:54:43 -0800 | [diff] [blame^] | 220 | func (*RuntimeX) GetSpan(ctx *context.T) vtrace.Span { |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 221 | return ivtrace.FromContext(ctx) |
| 222 | } |
| 223 | |
| 224 | func (*RuntimeX) setNewNamespace(ctx *context.T, roots ...string) (*context.T, naming.Namespace, error) { |
| 225 | ns, err := namespace.New(roots...) |
| 226 | if err == nil { |
| 227 | ctx = context.WithValue(ctx, namespaceKey, ns) |
| 228 | } |
| 229 | return ctx, ns, err |
| 230 | } |
| 231 | |
| 232 | func (r *RuntimeX) SetNewNamespace(ctx *context.T, roots ...string) (*context.T, naming.Namespace, error) { |
| 233 | newctx, ns, err := r.setNewNamespace(ctx, roots...) |
| 234 | if err != nil { |
| 235 | return ctx, nil, err |
| 236 | } |
| 237 | |
| 238 | // Replace the client since it depends on the namespace. |
| 239 | newctx, _, err = r.SetNewClient(newctx) |
| 240 | if err != nil { |
| 241 | return ctx, nil, err |
| 242 | } |
| 243 | |
| 244 | return newctx, ns, err |
| 245 | } |
| 246 | |
Suharsh Sivakumar | 033a30e | 2015-01-07 13:54:43 -0800 | [diff] [blame^] | 247 | func (*RuntimeX) GetNamespace(ctx *context.T) naming.Namespace { |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 248 | ns, _ := ctx.Value(namespaceKey).(naming.Namespace) |
| 249 | return ns |
| 250 | } |
| 251 | |
| 252 | func (*RuntimeX) SetNewLogger(ctx *context.T, name string, opts ...vlog.LoggingOpts) (*context.T, vlog.Logger, error) { |
| 253 | logger, err := vlog.NewLogger(name, opts...) |
| 254 | if err == nil { |
| 255 | ctx = context.WithValue(ctx, loggerKey, logger) |
| 256 | } |
| 257 | return ctx, logger, err |
| 258 | } |
| 259 | |
Suharsh Sivakumar | 033a30e | 2015-01-07 13:54:43 -0800 | [diff] [blame^] | 260 | func (*RuntimeX) GetLogger(ctx *context.T) vlog.Logger { |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 261 | logger, _ := ctx.Value(loggerKey).(vlog.Logger) |
| 262 | return logger |
| 263 | } |
| 264 | |
Suharsh Sivakumar | 033a30e | 2015-01-07 13:54:43 -0800 | [diff] [blame^] | 265 | func (*RuntimeX) GetVtraceStore(ctx *context.T) vtrace.Store { |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 266 | traceStore, _ := ctx.Value(vtraceKey).(vtrace.Store) |
| 267 | return traceStore |
| 268 | } |
| 269 | |
| 270 | type reservedNameDispatcher struct { |
| 271 | dispatcher ipc.Dispatcher |
| 272 | opts []ipc.ServerOpt |
| 273 | } |
| 274 | |
| 275 | // TODO(mattr): Get this from the profile instead, then remove this |
| 276 | // method from the interface. |
| 277 | func (*RuntimeX) SetReservedNameDispatcher(ctx *context.T, server ipc.Dispatcher, opts ...ipc.ServerOpt) *context.T { |
| 278 | return context.WithValue(ctx, reservedNameKey, &reservedNameDispatcher{server, opts}) |
| 279 | } |
Suharsh Sivakumar | ba56393 | 2015-01-06 15:15:50 -0800 | [diff] [blame] | 280 | |
Suharsh Sivakumar | 033a30e | 2015-01-07 13:54:43 -0800 | [diff] [blame^] | 281 | // SetProfile sets the profile used to create this runtime. |
| 282 | // TODO(suharshs, mattr): Determine if this is needed by functions after the new |
| 283 | // profile init function is in use. This will probably be easy to do because: |
| 284 | // Name is used in tests only. |
| 285 | // Platform is used for String representaions of a Profile. |
| 286 | // String is unused. |
| 287 | // Cleanup is used in rt.Cleanup and can probably be replaced by a cancelfunc returned |
| 288 | // by the new profile initialization function. |
| 289 | func (*RuntimeX) SetProfile(ctx *context.T, profile veyron2.Profile) *context.T { |
| 290 | return context.WithValue(ctx, profileKey, profile) |
| 291 | } |
| 292 | |
| 293 | func (*RuntimeX) GetProfile(ctx *context.T) veyron2.Profile { |
| 294 | profile, _ := ctx.Value(profileKey).(veyron2.Profile) |
| 295 | return profile |
| 296 | } |
| 297 | |
| 298 | func (*RuntimeX) SetAppCycle(ctx *context.T, appCycle veyron2.AppCycle) *context.T { |
| 299 | return context.WithValue(ctx, appCycleKey, appCycle) |
| 300 | } |
| 301 | |
| 302 | func (*RuntimeX) GetAppCycle(ctx *context.T) veyron2.AppCycle { |
| 303 | appCycle, _ := ctx.Value(appCycleKey).(veyron2.AppCycle) |
| 304 | return appCycle |
| 305 | } |
| 306 | |
| 307 | func (*RuntimeX) SetListenSpec(ctx *context.T, listenSpec ipc.ListenSpec) *context.T { |
| 308 | return context.WithValue(ctx, listenSpecKey, listenSpec) |
| 309 | } |
| 310 | |
| 311 | func (*RuntimeX) GetListenSpec(ctx *context.T) ipc.ListenSpec { |
| 312 | listenSpec, _ := ctx.Value(listenSpecKey).(ipc.ListenSpec) |
| 313 | return listenSpec |
| 314 | } |
| 315 | |
Suharsh Sivakumar | ba56393 | 2015-01-06 15:15:50 -0800 | [diff] [blame] | 316 | func (*RuntimeX) SetPreferredProtocols(ctx *context.T, protocols []string) *context.T { |
| 317 | return context.WithValue(ctx, protocolsKey, protocols) |
| 318 | } |