github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/cloudconfig/userdatacfg_win.go (about)

     1  // Copyright 2012, 2013, 2014, 2015 Canonical Ltd.
     2  // Copyright 2014, 2015 Cloudbase Solutions SRL
     3  // Licensed under the AGPLv3, see LICENCE file for details.
     4  
     5  package cloudconfig
     6  
     7  import (
     8  	"encoding/json"
     9  	"fmt"
    10  	"path/filepath"
    11  
    12  	"github.com/juju/errors"
    13  	"github.com/juju/names"
    14  	"github.com/juju/utils/featureflag"
    15  
    16  	"github.com/juju/juju/juju/osenv"
    17  	"github.com/juju/juju/juju/paths"
    18  )
    19  
    20  type aclType string
    21  
    22  const (
    23  	fileSystem    aclType = "FileSystem"
    24  	registryEntry aclType = "Registry"
    25  )
    26  
    27  type windowsConfigure struct {
    28  	baseConfigure
    29  }
    30  
    31  // Configure updates the provided cloudinit.Config with
    32  // configuration to initialize a Juju machine agent.
    33  func (w *windowsConfigure) Configure() error {
    34  	if err := w.ConfigureBasic(); err != nil {
    35  		return err
    36  	}
    37  	return w.ConfigureJuju()
    38  }
    39  
    40  func (w *windowsConfigure) ConfigureBasic() error {
    41  
    42  	series := w.icfg.Series
    43  	tmpDir, err := paths.TempDir(series)
    44  	if err != nil {
    45  		return err
    46  	}
    47  	renderer := w.conf.ShellRenderer()
    48  	dataDir := renderer.FromSlash(w.icfg.DataDir)
    49  	baseDir := renderer.FromSlash(filepath.Dir(tmpDir))
    50  	binDir := renderer.Join(baseDir, "bin")
    51  
    52  	w.conf.AddScripts(
    53  		fmt.Sprintf(`%s`, winPowershellHelperFunctions),
    54  
    55  		// Some providers create a baseDir before this step, but we need to
    56  		// make sure it exists before applying icacls
    57  		fmt.Sprintf(`mkdir -Force "%s"`, renderer.FromSlash(baseDir)),
    58  		fmt.Sprintf(`mkdir %s`, renderer.FromSlash(tmpDir)),
    59  		fmt.Sprintf(`mkdir "%s"`, binDir),
    60  		fmt.Sprintf(`mkdir "%s\locks"`, renderer.FromSlash(dataDir)),
    61  	)
    62  
    63  	// This is necessary for setACLs to work
    64  	w.conf.AddScripts(`$adminsGroup = (New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544")).Translate([System.Security.Principal.NTAccount])`)
    65  	w.conf.AddScripts(setACLs(renderer.FromSlash(baseDir), fileSystem)...)
    66  	w.conf.AddScripts(`setx /m PATH "$env:PATH;C:\Juju\bin\"`)
    67  	noncefile := renderer.Join(dataDir, NonceFile)
    68  	w.conf.AddScripts(
    69  		fmt.Sprintf(`Set-Content "%s" "%s"`, noncefile, shquote(w.icfg.MachineNonce)),
    70  	)
    71  	return nil
    72  }
    73  
    74  func (w *windowsConfigure) ConfigureJuju() error {
    75  	if err := w.icfg.VerifyConfig(); err != nil {
    76  		return errors.Trace(err)
    77  	}
    78  	if w.icfg.Bootstrap == true {
    79  		// Bootstrap machine not supported on windows
    80  		return errors.Errorf("bootstrapping is not supported on windows")
    81  	}
    82  
    83  	toolsJson, err := json.Marshal(w.icfg.Tools)
    84  	if err != nil {
    85  		return errors.Annotate(err, "while serializing the tools")
    86  	}
    87  	renderer := w.conf.ShellRenderer()
    88  	w.conf.AddScripts(
    89  		fmt.Sprintf(`$binDir="%s"`, renderer.FromSlash(w.icfg.JujuTools())),
    90  		fmt.Sprintf(`mkdir '%s'`, renderer.FromSlash(w.icfg.LogDir)),
    91  		`mkdir $binDir`,
    92  		`$WebClient = New-Object System.Net.WebClient`,
    93  		`[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}`,
    94  		fmt.Sprintf(`ExecRetry { $WebClient.DownloadFile('%s', "$binDir\tools.tar.gz") }`, w.icfg.Tools.URL),
    95  		`$dToolsHash = Get-FileSHA256 -FilePath "$binDir\tools.tar.gz"`,
    96  		fmt.Sprintf(`$dToolsHash > "$binDir\juju%s.sha256"`,
    97  			w.icfg.Tools.Version),
    98  		fmt.Sprintf(`if ($dToolsHash.ToLower() -ne "%s"){ Throw "Tools checksum mismatch"}`,
    99  			w.icfg.Tools.SHA256),
   100  		fmt.Sprintf(`GUnZip-File -infile $binDir\tools.tar.gz -outdir $binDir`),
   101  		`rm "$binDir\tools.tar*"`,
   102  		fmt.Sprintf(`Set-Content $binDir\downloaded-tools.txt '%s'`, string(toolsJson)),
   103  	)
   104  
   105  	for _, cmd := range CreateJujuRegistryKeyCmds() {
   106  		w.conf.AddRunCmd(cmd)
   107  	}
   108  
   109  	machineTag := names.NewMachineTag(w.icfg.MachineId)
   110  	_, err = w.addAgentInfo(machineTag)
   111  	if err != nil {
   112  		return errors.Trace(err)
   113  	}
   114  	return w.addMachineAgentToBoot()
   115  }
   116  
   117  // CreateJujuRegistryKey is going to create a juju registry key and set
   118  // permissions on it such that it's only accessible to administrators
   119  // It is exported because it is used in an upgrade step
   120  func CreateJujuRegistryKeyCmds() []string {
   121  	aclCmds := setACLs(osenv.JujuRegistryKey, registryEntry)
   122  	regCmds := []string{
   123  
   124  		// Create a registry key for storing juju related information
   125  		fmt.Sprintf(`New-Item -Path '%s'`, osenv.JujuRegistryKey),
   126  
   127  		// Create a JUJU_DEV_FEATURE_FLAGS entry which may or may not be empty.
   128  		fmt.Sprintf(`New-ItemProperty -Path '%s' -Name '%s'`,
   129  			osenv.JujuRegistryKey,
   130  			osenv.JujuFeatureFlagEnvKey),
   131  		fmt.Sprintf(`Set-ItemProperty -Path '%s' -Name '%s' -Value '%s'`,
   132  			osenv.JujuRegistryKey,
   133  			osenv.JujuFeatureFlagEnvKey,
   134  			featureflag.AsEnvironmentValue()),
   135  	}
   136  	return append(regCmds[:1], append(aclCmds, regCmds[1:]...)...)
   137  }
   138  
   139  func setACLs(path string, permType aclType) []string {
   140  	ruleModel := `$rule = New-Object System.Security.AccessControl.%sAccessRule %s`
   141  	permModel := `%s = "%s", "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow"`
   142  	adminPermVar := `$adminPerm`
   143  	jujudPermVar := `$jujudPerm`
   144  	return []string{
   145  		fmt.Sprintf(`$acl = Get-Acl -Path '%s'`, path),
   146  
   147  		// Reset the ACL's on it and add administrator access only.
   148  		`$acl.SetAccessRuleProtection($true, $false)`,
   149  
   150  		// $adminsGroup must be defined before calling setACLs
   151  		fmt.Sprintf(permModel, adminPermVar, `$adminsGroup`),
   152  		fmt.Sprintf(permModel, jujudPermVar, `jujud`),
   153  		fmt.Sprintf(ruleModel, permType, adminPermVar),
   154  		`$acl.AddAccessRule($rule)`,
   155  		fmt.Sprintf(ruleModel, permType, jujudPermVar),
   156  		`$acl.AddAccessRule($rule)`,
   157  		fmt.Sprintf(`Set-Acl -Path '%s' -AclObject $acl`, path),
   158  	}
   159  }