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 }