19
19
corecharm "launchpad.net/juju-core/charm"
20
20
"launchpad.net/juju-core/charm/hooks"
21
21
"launchpad.net/juju-core/cmd"
22
"launchpad.net/juju-core/errors"
23
"launchpad.net/juju-core/state"
22
"launchpad.net/juju-core/state/api/params"
23
"launchpad.net/juju-core/state/api/uniter"
24
24
"launchpad.net/juju-core/state/watcher"
25
25
"launchpad.net/juju-core/utils"
26
26
"launchpad.net/juju-core/utils/fslock"
61
61
ranConfigChanged bool
64
// NewUniter creates a new Uniter which will install, run, and upgrade a
65
// charm on behalf of the named unit, by executing hooks and operations
66
// provoked by changes in st.
67
func NewUniter(st *state.State, name string, dataDir string) *Uniter {
64
// NewUniter creates a new Uniter which will install, run, and upgrade
65
// a charm on behalf of the unit with the given unitTag, by executing
66
// hooks and operations provoked by changes in st.
67
func NewUniter(st *uniter.State, unitTag string, dataDir string) *Uniter {
73
73
defer u.tomb.Done()
74
u.tomb.Kill(u.loop(name))
74
u.tomb.Kill(u.loop(unitTag))
79
func (u *Uniter) loop(name string) (err error) {
80
if err = u.init(name); err != nil {
79
func (u *Uniter) loop(unitTag string) (err error) {
80
if err = u.init(unitTag); err != nil {
83
83
logger.Infof("unit %q started", u.unit)
85
85
// Start filtering state change events for consumption by modes.
86
u.f, err = newFilter(u.st, name)
86
u.f, err = newFilter(u.st, unitTag)
92
92
u.tomb.Kill(u.f.Wait())
95
// Announce our presence to the world.
96
pinger, err := u.unit.SetAgentAlive()
100
defer watcher.Stop(pinger, &u.tomb)
102
95
// Run modes until we encounter an error.
136
func (u *Uniter) init(name string) (err error) {
137
defer utils.ErrorContextf(&err, "failed to initialize uniter for unit %q", name)
138
u.unit, err = u.st.Unit(name)
129
func (u *Uniter) init(unitTag string) (err error) {
130
defer utils.ErrorContextf(&err, "failed to initialize uniter for %q", unitTag)
131
u.unit, err = u.st.Unit(unitTag)
142
135
if err = u.setupLocks(); err != nil {
145
ename := u.unit.Tag()
146
u.toolsDir = tools.ToolsDir(u.dataDir, ename)
138
u.toolsDir = tools.ToolsDir(u.dataDir, unitTag)
147
139
if err := EnsureJujucSymlinks(u.toolsDir); err != nil {
150
u.baseDir = filepath.Join(u.dataDir, "agents", ename)
142
u.baseDir = filepath.Join(u.dataDir, "agents", unitTag)
151
143
u.relationsDir = filepath.Join(u.baseDir, "state", "relations")
152
144
if err := os.MkdirAll(u.relationsDir, 0755); err != nil {
155
u.service, err = u.st.Service(u.unit.ServiceName())
147
u.service, err = u.st.Service(u.unit.ServiceTag())
159
var env *state.Environment
151
var env *uniter.Environment
160
152
env, err = u.st.Environment()
156
u.uuid, err = env.UUID()
165
160
u.relationers = map[int]*Relationer{}
166
161
u.relationHooks = make(chan hook.Info)
167
162
u.charm = charm.NewGitDir(filepath.Join(u.baseDir, "charm"))
328
hctx := NewHookContext(u.unit, hctxId, u.uuid, relationId, hi.RemoteUnit,
319
hctx, err := NewHookContext(u.unit, hctxId, u.uuid, relationId, hi.RemoteUnit,
329
320
ctxRelations, apiAddrs)
331
325
// Prepare server.
332
326
getCmd := func(ctxId, cmdName string) (cmd.Command, error) {
399
393
for id, dir := range dirs {
401
rel, err := u.st.Relation(id)
402
if errors.IsNotFoundError(err) {
395
rel, err := u.st.RelationById(id)
396
if params.IsCodeNotFound(err) {
404
398
} else if err != nil {
407
if err = u.addRelation(rel, dir); err == state.ErrCannotEnterScope {
401
err = u.addRelation(rel, dir)
402
if params.IsCodeCannotEnterScope(err) {
409
404
} else if err != nil {
432
427
if err := rel.Refresh(); err != nil {
433
428
return nil, fmt.Errorf("cannot update relation %q: %v", rel, err)
435
if rel.Life() == state.Dying {
430
if rel.Life() == params.Dying {
436
431
if err := r.SetDying(); err != nil {
438
433
} else if r.IsImplicit() {
444
439
// Relations that are not alive are simply skipped, because they
445
440
// were not previously known anyway.
446
rel, err := u.st.Relation(id)
441
rel, err := u.st.RelationById(id)
448
if errors.IsNotFoundError(err) {
443
if params.IsCodeNotFound(err) {
453
if rel.Life() != state.Alive {
448
if rel.Life() != params.Alive {
456
451
// Make sure we ignore relations not implemented by the unit's charm
461
if ep, err := rel.Endpoint(u.unit.ServiceName()); err != nil {
456
if ep, err := rel.Endpoint(); err != nil {
463
458
} else if !ep.ImplementedBy(ch) {
464
459
logger.Warningf("skipping relation with unknown endpoint %q", ep)
476
471
e := dir.Remove()
477
if err != state.ErrCannotEnterScope {
472
if !params.IsCodeCannotEnterScope(err) {
484
if u.unit.IsPrincipal() {
479
if ok, err := u.unit.IsPrincipal(); err != nil {
485
482
return added, nil
487
484
// If no Alive relations remain between a subordinate unit's service
505
502
// addRelation causes the unit agent to join the supplied relation, and to
506
503
// store persistent state in the supplied dir.
507
func (u *Uniter) addRelation(rel *state.Relation, dir *relation.StateDir) error {
504
func (u *Uniter) addRelation(rel *uniter.Relation, dir *relation.StateDir) error {
508
505
logger.Infof("joining relation %q", rel)
509
506
ru, err := rel.Unit(u.unit)
513
510
r := NewRelationer(ru, dir, u.relationHooks)
511
w, err := u.unit.Watch()
515
515
defer watcher.Stop(w, &u.tomb)
522
522
return watcher.MustErr(w)
524
if err := r.Join(); err == state.ErrCannotEnterScopeYet {
525
if params.IsCodeCannotEnterScopeYet(err) {
525
526
logger.Infof("cannot enter scope for relation %q; waiting for subordinate to be removed", rel)
527
528
} else if err != nil {