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  }