github.com/stulluk/snapd@v0.0.0-20210611110309-f6d5d5bd24b0/sysconfig/sysconfig.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2020 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package sysconfig 21 22 import ( 23 "path/filepath" 24 25 "github.com/snapcore/snapd/gadget" 26 "github.com/snapcore/snapd/snap" 27 ) 28 29 // See https://github.com/snapcore/core20/pull/46 30 const writableDefaultsDir = "_writable_defaults" 31 32 // Options is the set of options used to configure the run system 33 type Options struct { 34 // CloudInitSrcDir is where to find the cloud-init data when installing it, 35 // i.e. in early boot install mode it could be something like 36 // filepath.Join(boot.InitramfsUbuntuSeedDir,"data") 37 CloudInitSrcDir string 38 39 // TargetRootDir is the root directory where to install configure 40 // data, i.e. for cloud-init during the initramfs it will be something like 41 // boot.InstallHostWritableDir 42 TargetRootDir string 43 44 // AllowCloudInit is whether to allow cloud-init to run or not in the 45 // TargetRootDir. 46 AllowCloudInit bool 47 48 // GadgetDir is the path of the mounted gadget snap. 49 GadgetDir string 50 51 // GadgetSnap is a snap.Container of the gadget snap. This is used in 52 // priority over GadgetDir if set. 53 GadgetSnap snap.Container 54 } 55 56 // FilesystemOnlyApplyOptions is the set of options for 57 // ApplyFilesystemOnlyDefaults. 58 type FilesystemOnlyApplyOptions struct { 59 // Classic is true when the system in rootdir is a classic system 60 Classic bool 61 } 62 63 // ApplyFilesystemOnlyDefaultsImpl is initialized by init() of configcore. 64 var ApplyFilesystemOnlyDefaultsImpl = func(rootDir string, defaults map[string]interface{}, options *FilesystemOnlyApplyOptions) error { 65 panic("ApplyFilesystemOnlyDefaultsImpl is unset, import overlord/configstate/configcore") 66 } 67 68 // ApplyFilesystemOnlyDefaults applies (via configcore.filesystemOnlyApply()) 69 // filesystem modifications under rootDir, according to the defaults. 70 // This is a subset of core config options that is important 71 // early during boot, before all the configuration is applied as part of 72 // normal execution of configure hook. 73 func ApplyFilesystemOnlyDefaults(rootDir string, defaults map[string]interface{}, options *FilesystemOnlyApplyOptions) error { 74 return ApplyFilesystemOnlyDefaultsImpl(rootDir, defaults, options) 75 } 76 77 // ConfigureTargetSystem configures the ubuntu-data partition with 78 // any configuration needed from e.g. the gadget or for cloud-init (and also for 79 // cloud-init from the gadget). 80 // It is okay to use both from install mode for run mode, as well as from the 81 // initramfs for recover mode. 82 func ConfigureTargetSystem(opts *Options) error { 83 if err := configureCloudInit(opts); err != nil { 84 return err 85 } 86 87 var gadgetInfo *gadget.Info 88 var err error 89 switch { 90 case opts.GadgetSnap != nil: 91 // we do not perform consistency validation here because 92 // such unlikely problems are better surfaced in different 93 // and less surprising contexts like the seeding itself 94 gadgetInfo, err = gadget.ReadInfoFromSnapFileNoValidate(opts.GadgetSnap, nil) 95 case opts.GadgetDir != "": 96 gadgetInfo, err = gadget.ReadInfo(opts.GadgetDir, nil) 97 } 98 99 if err != nil { 100 return err 101 } 102 103 if gadgetInfo != nil { 104 defaults := gadget.SystemDefaults(gadgetInfo.Defaults) 105 if len(defaults) > 0 { 106 // options are nil which implies core system 107 var options *FilesystemOnlyApplyOptions 108 if err := ApplyFilesystemOnlyDefaults(WritableDefaultsDir(opts.TargetRootDir), defaults, options); err != nil { 109 return err 110 } 111 } 112 } 113 114 return nil 115 } 116 117 // WritableDefaultsDir returns the full path of the joined subdir under the 118 // subtree for default content for system data living at rootdir, 119 // i.e. rootdir/_writable_defaults/subdir... 120 func WritableDefaultsDir(rootdir string, subdir ...string) string { 121 return filepath.Join(rootdir, writableDefaultsDir, filepath.Join(subdir...)) 122 }