github.com/coreos/mantle@v0.13.0/cmd/cork/create.go (about) 1 // Copyright 2015 CoreOS, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package main 16 17 import ( 18 "os" 19 "path/filepath" 20 21 "github.com/coreos/go-semver/semver" 22 "github.com/spf13/cobra" 23 "github.com/spf13/pflag" 24 25 "github.com/coreos/mantle/sdk" 26 "github.com/coreos/mantle/sdk/repo" 27 ) 28 29 const ( 30 coreosManifestURL = "https://github.com/coreos/manifest.git" 31 ) 32 33 var ( 34 // everything uses this flag 35 chrootFlags *pflag.FlagSet 36 chrootName string 37 38 // creation flags 39 creationFlags *pflag.FlagSet 40 sdkVersion string 41 manifestURL string 42 manifestName string 43 manifestBranch string 44 repoVerify bool 45 sigVerify bool 46 47 // only for `create` command 48 allowReplace bool 49 50 // only for `enter` command 51 bindGpgAgent bool 52 53 // for create/update/enter 54 useHostDNS bool 55 56 // only for `update` command 57 allowCreate bool 58 forceSync bool 59 downgradeInPlace bool 60 downgradeReplace bool 61 newVersion string 62 63 verifyKeyFile string 64 65 setupCmd = &cobra.Command{ 66 Use: "setup", 67 Short: "Setup the system for SDK use", 68 Run: runSetup, 69 } 70 createCmd = &cobra.Command{ 71 Use: "create", 72 Short: "Download and unpack the SDK", 73 Run: runCreate, 74 } 75 enterCmd = &cobra.Command{ 76 Use: "enter [-- command]", 77 Short: "Enter the SDK chroot, optionally running a command", 78 Run: runEnter, 79 } 80 deleteCmd = &cobra.Command{ 81 Use: "delete", 82 Short: "Delete the SDK chroot", 83 Run: runDelete, 84 } 85 updateCmd = &cobra.Command{ 86 Use: "update", 87 Short: "Update the SDK chroot and source tree", 88 Run: runUpdate, 89 } 90 verifyCmd = &cobra.Command{ 91 Use: "verify", 92 Short: "Check repo tree and release manifest match", 93 Run: runVerify, 94 } 95 ) 96 97 func init() { 98 // the names and error handling of these flag sets are meaningless, 99 // the flag sets are only used to group common options together. 100 chrootFlags = pflag.NewFlagSet("chroot", pflag.ExitOnError) 101 chrootFlags.StringVar(&chrootName, 102 "chroot", "chroot", "SDK chroot directory name") 103 chrootFlags.BoolVar(&useHostDNS, 104 "use-host-dns", false, "Use the host's /etc/resolv.conf instead of 8.8.8.8 and 8.8.4.4") 105 106 creationFlags = pflag.NewFlagSet("creation", pflag.ExitOnError) 107 creationFlags.StringVar(&sdkVersion, 108 "sdk-version", "", "SDK version. Defaults to the SDK version in version.txt") 109 creationFlags.StringVar(&manifestURL, 110 "manifest-url", coreosManifestURL, "Manifest git repo location") 111 creationFlags.StringVar(&manifestBranch, 112 "manifest-branch", "master", "Manifest git repo branch") 113 creationFlags.StringVar(&manifestName, 114 "manifest-name", "default.xml", "Manifest file name") 115 creationFlags.BoolVar(&repoVerify, 116 "verify", false, "Check repo tree and release manifest match") 117 creationFlags.StringVar(&verifyKeyFile, 118 "verify-key", "", "PGP public key to be used in verifing download signatures. Defaults to CoreOS Buildbot (0412 7D0B FABE C887 1FFB 2CCE 50E0 8855 93D2 DCB4)") 119 creationFlags.BoolVar(&sigVerify, 120 "verify-signature", false, "Verify the manifest Git tag with GPG") 121 122 root.AddCommand(setupCmd) 123 124 createCmd.Flags().AddFlagSet(chrootFlags) 125 createCmd.Flags().AddFlagSet(creationFlags) 126 createCmd.Flags().BoolVar(&allowReplace, 127 "replace", false, "Replace an existing SDK chroot") 128 root.AddCommand(createCmd) 129 130 enterCmd.Flags().AddFlagSet(chrootFlags) 131 enterCmd.Flags().BoolVar(&bindGpgAgent, 132 "bind-gpg-agent", true, "bind mount the gpg agent socket directory") 133 root.AddCommand(enterCmd) 134 135 deleteCmd.Flags().AddFlagSet(chrootFlags) 136 root.AddCommand(deleteCmd) 137 138 updateCmd.Flags().AddFlagSet(chrootFlags) 139 updateCmd.Flags().AddFlagSet(creationFlags) 140 updateCmd.Flags().BoolVar(&allowCreate, 141 "create", false, "Create the SDK chroot if missing") 142 updateCmd.Flags().BoolVar(&forceSync, 143 "force-sync", false, "Overrwrite stale .git directories if needed") 144 updateCmd.Flags().BoolVar(&downgradeInPlace, 145 "downgrade-in-place", false, 146 "Allow in-place downgrades of SDK chroot") 147 updateCmd.Flags().BoolVar(&downgradeReplace, 148 "downgrade-replace", false, 149 "Replace SDK chroot instead of downgrading") 150 updateCmd.Flags().StringVar(&newVersion, 151 "new-version", "", "Hint at the new version. Defaults to the version in version.txt") 152 root.AddCommand(updateCmd) 153 154 root.AddCommand(verifyCmd) 155 } 156 157 func runSetup(cmd *cobra.Command, args []string) { 158 if len(args) != 0 { 159 plog.Fatal("No args accepted") 160 } 161 162 if err := installQemuBinfmt(); err != nil { 163 plog.Fatal("Install QEMU binfmt failed: ", err) 164 } 165 } 166 167 func installQemuBinfmt() error { 168 const dest = "/etc/binfmt.d/qemu-aarch64.conf" 169 const data = ":qemu-aarch64:M::\\x7fELF\\x02\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\xb7:\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x00\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xfe\\xff\\xff:/usr/bin/qemu-aarch64-static:" 170 171 // Only install if file does not exist 172 if _, err := os.Stat(dest); err == nil { 173 return nil 174 } 175 176 dir := filepath.Dir(dest) 177 if err := os.MkdirAll(dir, 0755); err != nil { 178 return err 179 } 180 181 file, err := os.Create(dest) 182 if err != nil { 183 return err 184 } 185 186 if _, err := file.WriteString(data); err != nil { 187 return err 188 } 189 190 if err := file.Close(); err != nil { 191 os.Remove(dest) 192 return err 193 } 194 195 return nil 196 } 197 198 func runCreate(cmd *cobra.Command, args []string) { 199 if len(args) != 0 { 200 plog.Fatal("No args accepted") 201 } 202 203 if sdkVersion == "" { 204 plog.Noticef("Detecting SDK version") 205 206 getRemoteVersions := sdk.VersionsFromRemoteRepo 207 if sigVerify { 208 getRemoteVersions = sdk.VersionsFromSignedRemoteRepo 209 } 210 211 if ver, err := sdk.VersionsFromManifest(); err == nil { 212 sdkVersion = ver.SDKVersion 213 plog.Noticef("Found SDK version %s from local repo", sdkVersion) 214 } else if ver, err := getRemoteVersions(manifestURL, manifestBranch); err == nil { 215 sdkVersion = ver.SDKVersion 216 plog.Noticef("Found SDK version %s from remote repo", sdkVersion) 217 } else { 218 plog.Fatalf("Reading from remote repo failed: %v", err) 219 } 220 } 221 222 unpackChroot(allowReplace) 223 updateRepo() 224 } 225 226 func unpackChroot(replace bool) { 227 plog.Noticef("Downloading SDK version %s", sdkVersion) 228 if err := sdk.DownloadSDK(sdkVersion, verifyKeyFile); err != nil { 229 plog.Fatalf("Download failed: %v", err) 230 } 231 232 if replace { 233 if err := sdk.Delete(chrootName); err != nil { 234 plog.Fatalf("Replace failed: %v", err) 235 } 236 } 237 238 if err := sdk.Unpack(sdkVersion, chrootName); err != nil { 239 plog.Fatalf("Create failed: %v", err) 240 } 241 242 if err := sdk.Setup(chrootName); err != nil { 243 plog.Fatalf("Create failed: %v", err) 244 } 245 } 246 247 func updateRepo() { 248 if err := sdk.RepoInit(chrootName, manifestURL, manifestBranch, manifestName, useHostDNS); err != nil { 249 plog.Fatalf("repo init failed: %v", err) 250 } 251 252 if sigVerify { 253 if err := sdk.RepoVerifyTag(manifestBranch); err != nil { 254 plog.Fatalf("repo tag verification failed: %v", err) 255 } 256 } 257 258 if err := sdk.RepoSync(chrootName, forceSync, useHostDNS); err != nil { 259 plog.Fatalf("repo sync failed: %v", err) 260 } 261 262 if repoVerify { 263 if err := repo.VerifySync(manifestName); err != nil { 264 plog.Fatalf("Verify failed: %v", err) 265 } 266 } 267 } 268 269 func runEnter(cmd *cobra.Command, args []string) { 270 err := sdk.Enter(chrootName, bindGpgAgent, useHostDNS, args...) 271 if err != nil && len(args) != 0 { 272 plog.Fatalf("Running %v failed: %v", args, err) 273 } 274 } 275 276 func runDelete(cmd *cobra.Command, args []string) { 277 if len(args) != 0 { 278 plog.Fatal("No args accepted") 279 } 280 281 if err := sdk.Delete(chrootName); err != nil { 282 plog.Fatalf("Delete failed: %v", err) 283 } 284 } 285 286 func verLessThan(a, b string) bool { 287 aver, err := semver.NewVersion(a) 288 if err != nil { 289 plog.Fatal(err) 290 } 291 bver, err := semver.NewVersion(b) 292 if err != nil { 293 plog.Fatal(err) 294 } 295 return aver.LessThan(*bver) 296 } 297 298 func runUpdate(cmd *cobra.Command, args []string) { 299 const updateChroot = "/mnt/host/source/src/scripts/update_chroot" 300 updateCommand := append([]string{updateChroot}, args...) 301 302 // avoid downgrade strategy ambiguity 303 if downgradeInPlace && downgradeReplace { 304 plog.Fatal("Conflicting downgrade options") 305 } 306 307 if sdkVersion == "" || newVersion == "" { 308 plog.Notice("Detecting versions in remote repo") 309 getRemoteVersions := sdk.VersionsFromRemoteRepo 310 if sigVerify { 311 getRemoteVersions = sdk.VersionsFromSignedRemoteRepo 312 } 313 ver, err := getRemoteVersions(manifestURL, manifestBranch) 314 if err != nil { 315 plog.Fatalf("Reading from remote repo failed: %v", err) 316 } 317 318 if newVersion == "" { 319 newVersion = ver.Version 320 } 321 322 if sdkVersion == "" { 323 sdkVersion = ver.SDKVersion 324 } 325 } 326 327 plog.Infof("New version %s", newVersion) 328 plog.Infof("SDK version %s", sdkVersion) 329 330 plog.Info("Checking version of local chroot") 331 chroot := filepath.Join(sdk.RepoRoot(), chrootName) 332 old, err := sdk.OSRelease(chroot) 333 if err != nil { 334 if allowCreate && os.IsNotExist(err) { 335 unpackChroot(false) 336 } else { 337 plog.Fatal(err) 338 } 339 } else if verLessThan(newVersion, old.Version) { 340 plog.Noticef("Downgrade from %s to %s required!", 341 old.Version, newVersion) 342 if downgradeReplace { 343 unpackChroot(true) 344 } else if downgradeInPlace { 345 plog.Infof("Attempting to downgrade existing chroot.") 346 } else { 347 plog.Fatalf("Refusing to downgrade.") 348 } 349 } 350 351 updateRepo() 352 353 if err := sdk.Enter(chrootName, false, false, updateCommand...); err != nil { 354 plog.Fatalf("update_chroot failed: %v", err) 355 } 356 } 357 358 func runVerify(cmd *cobra.Command, args []string) { 359 if len(args) != 0 { 360 plog.Fatal("No args accepted") 361 } 362 363 if err := repo.VerifySync(""); err != nil { 364 plog.Fatalf("Verify failed: %v", err) 365 } 366 }