github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/worker/uniter/uniter_linux.go (about) 1 package uniter 2 3 import ( 4 "math/rand" 5 "os" 6 "path/filepath" 7 "time" 8 "fmt" 9 10 "launchpad.net/juju-core/cmd" 11 "launchpad.net/juju-core/agent/tools" 12 "launchpad.net/juju-core/utils" 13 "launchpad.net/juju-core/worker/uniter/charm" 14 "launchpad.net/juju-core/worker/uniter/jujuc" 15 "launchpad.net/juju-core/worker/uniter/hook" 16 "launchpad.net/juju-core/state/api/uniter" 17 ) 18 19 func (u *Uniter) init(unitTag string) (err error) { 20 defer utils.ErrorContextf(&err, "failed to initialize uniter for %q", unitTag) 21 u.unit, err = u.st.Unit(unitTag) 22 if err != nil { 23 return err 24 } 25 if err = u.setupLocks(); err != nil { 26 return err 27 } 28 u.toolsDir = tools.ToolsDir(u.dataDir, unitTag) 29 if err := EnsureJujucSymlinks(u.toolsDir); err != nil { 30 return err 31 } 32 u.baseDir = filepath.Join(u.dataDir, "agents", unitTag) 33 u.relationsDir = filepath.Join(u.baseDir, "state", "relations") 34 if err := os.MkdirAll(u.relationsDir, 0755); err != nil { 35 return err 36 } 37 u.service, err = u.st.Service(u.unit.ServiceTag()) 38 if err != nil { 39 return err 40 } 41 var env *uniter.Environment 42 env, err = u.st.Environment() 43 if err != nil { 44 return err 45 } 46 u.uuid = env.UUID() 47 u.envName = env.Name() 48 49 runListenerSocketPath := filepath.Join(u.baseDir, RunListenerFile) 50 logger.Debugf("starting juju-run listener on unix:%s", runListenerSocketPath) 51 u.runListener, err = NewRunListener(u, runListenerSocketPath) 52 if err != nil { 53 return err 54 } 55 // The socket needs to have permissions 777 in order for other users to use it. 56 if err := os.Chmod(runListenerSocketPath, 0777); err != nil { 57 return err 58 } 59 u.relationers = map[int]*Relationer{} 60 u.relationHooks = make(chan hook.Info) 61 u.charm = charm.NewGitDir(filepath.Join(u.baseDir, "charm")) 62 deployerPath := filepath.Join(u.baseDir, "state", "deployer") 63 bundles := charm.NewBundlesDir(filepath.Join(u.baseDir, "state", "bundles")) 64 u.deployer = charm.NewGitDeployer(u.charm.Path(), deployerPath, bundles) 65 u.sf = NewStateFile(filepath.Join(u.baseDir, "state", "uniter")) 66 u.rand = rand.New(rand.NewSource(time.Now().Unix())) 67 return nil 68 } 69 70 func (u *Uniter) startJujucServer(context *HookContext) (*jujuc.Server, string, error) { 71 // Prepare server. 72 getCmd := func(ctxId, cmdName string) (cmd.Command, error) { 73 // TODO: switch to long-running server with single context; 74 // use nonce in place of context id. 75 if ctxId != context.id { 76 return nil, fmt.Errorf("expected context id %q, got %q", context.id, ctxId) 77 } 78 return jujuc.NewCommand(context, cmdName) 79 } 80 socketPath := filepath.Join(u.baseDir, "agent.socket") 81 // Use abstract namespace so we don't get stale socket files. 82 socketPath = "@" + socketPath 83 srv, err := jujuc.NewServer(getCmd, socketPath) 84 if err != nil { 85 return nil, "", err 86 } 87 go srv.Run() 88 return srv, socketPath, nil 89 } 90 91 // runHook executes the supplied hook.Info in an appropriate hook context. If 92 // the hook itself fails to execute, it returns errHookFailed. 93 func (u *Uniter) runHook(hi hook.Info) (err error) { 94 // Prepare context. 95 if err = hi.Validate(); err != nil { 96 return err 97 } 98 99 hookName := string(hi.Kind) 100 relationId := -1 101 if hi.Kind.IsRelation() { 102 relationId = hi.RelationId 103 if hookName, err = u.relationers[relationId].PrepareHook(hi); err != nil { 104 return err 105 } 106 } 107 hctxId := fmt.Sprintf("%s:%s:%d", u.unit.Name(), hookName, u.rand.Int63()) 108 109 lockMessage := fmt.Sprintf("%s: running hook %q", u.unit.Name(), hookName) 110 if err = u.acquireHookLock(lockMessage); err != nil { 111 return err 112 } 113 defer u.hookLock.Unlock() 114 115 hctx, err := u.getHookContext(hctxId, relationId, hi.RemoteUnit) 116 if err != nil { 117 return err 118 } 119 srv, socketPath, err := u.startJujucServer(hctx) 120 if err != nil { 121 return err 122 } 123 defer srv.Close() 124 125 // Run the hook. 126 if err := u.writeState(RunHook, Pending, &hi, nil); err != nil { 127 return err 128 } 129 logger.Infof("running %q hook", hookName) 130 ranHook := true 131 err = hctx.RunHook(hookName, u.charm.Path(), u.toolsDir, socketPath) 132 if IsMissingHookError(err) { 133 ranHook = false 134 } else if err != nil { 135 logger.Errorf("hook failed: %s", err) 136 u.notifyHookFailed(hookName, hctx) 137 return errHookFailed 138 } 139 if err := u.writeState(RunHook, Done, &hi, nil); err != nil { 140 return err 141 } 142 if ranHook { 143 logger.Infof("ran %q hook", hookName) 144 u.notifyHookCompleted(hookName, hctx) 145 } else { 146 logger.Infof("skipped %q hook (missing)", hookName) 147 } 148 return u.commitHook(hi) 149 }