github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/upgradeseries/upgrader.go (about)

     1  // Copyright 2018 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package upgradeseries
     5  
     6  import (
     7  	"strings"
     8  
     9  	"github.com/juju/errors"
    10  
    11  	"github.com/juju/juju/juju/paths"
    12  	"github.com/juju/juju/service"
    13  	"github.com/juju/juju/service/systemd"
    14  	"github.com/juju/juju/version"
    15  )
    16  
    17  //go:generate mockgen -package mocks -destination mocks/servicemanager_mock.go github.com/juju/juju/service SystemdServiceManager
    18  
    19  var (
    20  	systemdDir          = systemd.EtcSystemdDir
    21  	systemdMultiUserDir = systemd.EtcSystemdMultiUserDir
    22  )
    23  
    24  // Upgrader describes methods required to perform file-system manipulation in
    25  // preparation for upgrading the host Ubuntu version.
    26  type Upgrader interface {
    27  	PerformUpgrade() error
    28  }
    29  
    30  // upgrader implements the Upgrader interface for a specific (from/to) upgrade
    31  // of the host Ubuntu version, via the systemd service manager.
    32  type upgrader struct {
    33  	logger Logger
    34  
    35  	fromSeries string
    36  	fromInit   string
    37  	toSeries   string
    38  	toInit     string
    39  
    40  	machineAgent string
    41  	unitAgents   []string
    42  
    43  	manager service.SystemdServiceManager
    44  }
    45  
    46  // NewUpgrader uses the input function to determine the series that should be
    47  // supported, and returns a reference to a new Upgrader that supports it.
    48  func NewUpgrader(toSeries string, manager service.SystemdServiceManager, logger Logger) (Upgrader, error) {
    49  	fromSeries, err := hostSeries()
    50  	if err != nil {
    51  		return nil, errors.Trace(err)
    52  	}
    53  	fromInit, err := service.VersionInitSystem(fromSeries)
    54  	if err != nil {
    55  		return nil, errors.Trace(err)
    56  	}
    57  
    58  	toInit, err := service.VersionInitSystem(toSeries)
    59  	if err != nil {
    60  		return nil, errors.Trace(err)
    61  	}
    62  
    63  	return &upgrader{
    64  		logger:     logger,
    65  		fromSeries: fromSeries,
    66  		fromInit:   fromInit,
    67  		toSeries:   toSeries,
    68  		toInit:     toInit,
    69  		manager:    manager,
    70  	}, nil
    71  }
    72  
    73  // PerformUpgrade writes Juju binaries and service files that allow the machine
    74  // and unit agents to run on the target version of Ubuntu.
    75  func (u *upgrader) PerformUpgrade() error {
    76  	if err := u.populateAgents(); err != nil {
    77  		return errors.Trace(err)
    78  	}
    79  
    80  	if err := u.ensureSystemdFiles(); err != nil {
    81  		return errors.Trace(err)
    82  	}
    83  
    84  	return errors.Trace(u.ensureAgentBinaries())
    85  }
    86  
    87  // populateAgents discovers and sets the names of the machine and unit agents.
    88  // If there are any other agents determined, a warning is logged to notify that
    89  // they are being skipped from the upgrade process.
    90  func (u *upgrader) populateAgents() (err error) {
    91  	var unknown []string
    92  	u.machineAgent, u.unitAgents, unknown, err = u.manager.FindAgents(paths.NixDataDir)
    93  	if err != nil {
    94  		return errors.Trace(err)
    95  	}
    96  	if len(unknown) > 0 {
    97  		u.logger.Warningf("skipping agents not of type machine or unit: %s", strings.Join(unknown, ", "))
    98  	}
    99  	return nil
   100  }
   101  
   102  // ensureSystemdFiles determines whether re-writing service files to target
   103  // systemd is required. If it is, the necessary changes are invoked via the
   104  // service manager.
   105  func (u *upgrader) ensureSystemdFiles() error {
   106  	if u.fromInit == service.InitSystemSystemd || u.toInit != service.InitSystemSystemd {
   107  		return nil
   108  	}
   109  
   110  	services, links, failed, err := u.manager.WriteSystemdAgents(
   111  		u.machineAgent, u.unitAgents, paths.NixDataDir, systemdDir, systemdMultiUserDir)
   112  
   113  	if len(services) > 0 {
   114  		u.logger.Infof("agents written and linked by systemd: %s", strings.Join(services, ", "))
   115  	}
   116  	if len(links) > 0 {
   117  		u.logger.Infof("agents written and linked by symlink: %s", strings.Join(links, ", "))
   118  	}
   119  
   120  	return errors.Annotatef(err, "failed to write agents: %s", strings.Join(failed, ", "))
   121  }
   122  
   123  // ensureAgentBinaries ensures that the jujud binary and links exist in the
   124  // right tools path for the target OS series, and that individual agents use
   125  // those files.
   126  func (u *upgrader) ensureAgentBinaries() error {
   127  	if err := u.manager.CopyAgentBinary(
   128  		u.machineAgent, u.unitAgents, paths.NixDataDir, u.toSeries, u.fromSeries, version.Current); err != nil {
   129  		return errors.Trace(err)
   130  	}
   131  
   132  	u.logger.Infof("copied agent binaries for series %q", u.toSeries)
   133  	return nil
   134  }