github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/worker/uniter/uniter_windows.go (about) 1 package uniter 2 3 import ( 4 "math/rand" 5 "os" 6 "os/exec" 7 "path/filepath" 8 "time" 9 "fmt" 10 11 "launchpad.net/juju-core/agent/tools" 12 "launchpad.net/juju-core/utils" 13 "launchpad.net/juju-core/state/api/uniter" 14 "launchpad.net/juju-core/cmd" 15 "launchpad.net/juju-core/worker/uniter/charm" 16 "launchpad.net/juju-core/worker/uniter/jujuc" 17 "launchpad.net/juju-core/worker/uniter/hook" 18 19 "launchpad.net/juju-core/windows" 20 ) 21 22 23 func (u *Uniter) init(unitTag string) (err error) { 24 defer utils.ErrorContextf(&err, "failed to initialize uniter for %q", unitTag) 25 u.unit, err = u.st.Unit(unitTag) 26 if err != nil { 27 return err 28 } 29 if err = u.setupLocks(); err != nil { 30 return err 31 } 32 u.toolsDir = tools.ToolsDir(u.dataDir, unitTag) 33 if err := EnsureJujucSymlinks(u.toolsDir); err != nil { 34 return err 35 } 36 u.baseDir = filepath.Join(u.dataDir, "agents", unitTag) 37 u.relationsDir = filepath.Join(u.baseDir, "state", "relations") 38 if err := os.MkdirAll(u.relationsDir, 0755); err != nil { 39 return err 40 } 41 u.service, err = u.st.Service(u.unit.ServiceTag()) 42 if err != nil { 43 return err 44 } 45 var env *uniter.Environment 46 env, err = u.st.Environment() 47 if err != nil { 48 return err 49 } 50 u.uuid = env.UUID() 51 u.envName = env.Name() 52 53 runListenerSocketPath := filepath.Join(u.baseDir, RunListenerFile) 54 //TODO: gsamfira: This is a bit hacky. Would prefer implementing 55 //named pipes on windows 56 u.tcpSock, err = utils.WriteSocketFile(runListenerSocketPath) 57 if err != nil { 58 return err 59 } 60 61 logger.Debugf("starting juju-run listener on:%s", u.tcpSock) 62 u.runListener, err = NewRunListener(u, u.tcpSock) 63 if err != nil { 64 return err 65 } 66 67 u.relationers = map[int]*Relationer{} 68 u.relationHooks = make(chan hook.Info) 69 u.charm = charm.NewGitDir(filepath.Join(u.baseDir, "charm")) 70 deployerPath := filepath.Join(u.baseDir, "state", "deployer") 71 bundles := charm.NewBundlesDir(filepath.Join(u.baseDir, "state", "bundles")) 72 u.deployer = charm.NewGitDeployer(u.charm.Path(), deployerPath, bundles) 73 u.sf = NewStateFile(filepath.Join(u.baseDir, "state", "uniter")) 74 u.rand = rand.New(rand.NewSource(time.Now().Unix())) 75 return nil 76 } 77 78 func (u *Uniter) startJujucServer(context *HookContext) (*jujuc.Server, string, error) { 79 // Prepare server. 80 getCmd := func(ctxId, cmdName string) (cmd.Command, error) { 81 // TODO: switch to long-running server with single context; 82 // use nonce in place of context id. 83 if ctxId != context.id { 84 return nil, fmt.Errorf("expected context id %q, got %q", context.id, ctxId) 85 } 86 return jujuc.NewCommand(context, cmdName) 87 } 88 // gsamfira: This function simply returns a free TCP socket. 89 // TODO: Must see if this socket is used by any other process then charms 90 socketPath, errSock := utils.GetSocket() 91 if errSock != nil { 92 return nil, "", errSock 93 } 94 srv, err := jujuc.NewServer(getCmd, socketPath) 95 if err != nil { 96 return nil, "", err 97 } 98 go srv.Run() 99 return srv, socketPath, nil 100 } 101 102 // runHook executes the supplied hook.Info in an appropriate hook context. If 103 // the hook itself fails to execute, it returns errHookFailed. 104 func (u *Uniter) runHook(hi hook.Info) (err error) { 105 // Prepare context. 106 if err = hi.Validate(); err != nil { 107 return err 108 } 109 110 hookName := string(hi.Kind) 111 relationId := -1 112 if hi.Kind.IsRelation() { 113 relationId = hi.RelationId 114 if hookName, err = u.relationers[relationId].PrepareHook(hi); err != nil { 115 return err 116 } 117 } 118 hctxId := fmt.Sprintf("%s:%s:%d", u.unit.Name(), hookName, u.rand.Int63()) 119 120 lockMessage := fmt.Sprintf("%s: running hook %q", u.unit.Name(), hookName) 121 if err = u.acquireHookLock(lockMessage); err != nil { 122 return err 123 } 124 defer u.hookLock.Unlock() 125 126 hctx, err := u.getHookContext(hctxId, relationId, hi.RemoteUnit) 127 if err != nil { 128 return err 129 } 130 srv, socketPath, err := u.startJujucServer(hctx) 131 if err != nil { 132 return err 133 } 134 defer srv.Close() 135 136 // Run the hook. 137 if err := u.writeState(RunHook, Pending, &hi, nil); err != nil { 138 return err 139 } 140 logger.Infof("running %q hook", hookName) 141 ranHook := true 142 err = hctx.RunHook(hookName, u.charm.Path(), u.toolsDir, socketPath) 143 if RebootRequiredError(err){ 144 logger.Infof("hook %q requested a reboot", hookName) 145 if err := u.writeState(RunHook, Queued, &hi, nil); err != nil { 146 return err 147 } 148 time := 5 149 logger.Infof("rebooting system in %q seconds", time) 150 errReboot := windows.Reboot(time) 151 if eeReboot, ok := errReboot.(*exec.Error); ok && eeReboot != nil { 152 logger.Infof("Reboot returned error: %q", eeReboot.Err) 153 } 154 logger.Infof("Stopping uniter due to reboot") 155 u.Stop() 156 } 157 if IsMissingHookError(err) { 158 ranHook = false 159 } else if err != nil { 160 logger.Errorf("hook failed: %s", err) 161 u.notifyHookFailed(hookName, hctx) 162 return errHookFailed 163 } 164 if err := u.writeState(RunHook, Done, &hi, nil); err != nil { 165 return err 166 } 167 if ranHook { 168 logger.Infof("ran %q hook", hookName) 169 u.notifyHookCompleted(hookName, hctx) 170 } else { 171 logger.Infof("skipped %q hook (missing)", hookName) 172 } 173 return u.commitHook(hi) 174 }