Skip to content

Commit bb449f6

Browse files
Fresnel Imaging Teamcopybara-github
Fresnel Imaging Team
authored andcommitted
Add support for downloading and placing ffu configuration files to the provisioned drive.
PiperOrigin-RevId: 400811866
1 parent 856c38c commit bb449f6

File tree

4 files changed

+217
-47
lines changed

4 files changed

+217
-47
lines changed

cli/config/config.go

+22-10
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,17 @@ const (
5757
// required to obtain the resources required to install it.
5858
type distribution struct {
5959
os OperatingSystem
60-
name string // Friendly name: e.g. Corp Windows.
61-
label string // If set, is used to set partition labels.
62-
seedServer string // If set, a seed is obtained from here.
63-
seedFile string // This file is hashed when obtainng a seed.
64-
seedDest string // The relative path where the seed should be written.
60+
confStore string // The relative path where configs are located.
6561
ffuDest string // The relative path where SFU files will be stored.
6662
imageServer string // The base image is obtained here.
63+
label string // If set, is used to set partition labels.
64+
name string // Friendly name: e.g. Corp Windows.
65+
seedDest string // The relative path where the seed should be written.
66+
seedFile string // This file is hashed when obtainng a seed.
67+
seedServer string // If set, a seed is obtained from here.
6768
images map[string]string
6869
ffus map[string]string // Contains SFU manifests names.
70+
configs map[string]string // Contains config file names.
6971
}
7072

7173
// Configuration represents the state of all flags and selections provided
@@ -88,11 +90,11 @@ type Configuration struct {
8890
func New(cleanup, warning, eject, ffu, update bool, devices []string, os, track, seedServer string) (*Configuration, error) {
8991
// Create a partial config using known good values.
9092
conf := &Configuration{
91-
cleanup: cleanup,
92-
warning: warning,
93-
ffu: ffu,
94-
eject: eject,
95-
update: update,
93+
cleanup: cleanup,
94+
warning: warning,
95+
ffu: ffu,
96+
eject: eject,
97+
update: update,
9698
}
9799
if len(devices) > 0 {
98100
if err := conf.addDeviceList(devices); err != nil {
@@ -273,6 +275,16 @@ func (c *Configuration) FFUPath() string {
273275
return fmt.Sprintf(`%s/%s/%s`, c.distro.imageServer, c.distro.name, c.track)
274276
}
275277

278+
// ConfName returns the name of the config file.
279+
func (c *Configuration) ConfName() string {
280+
return c.distro.configs[c.track]
281+
}
282+
283+
// ConfPath returns the path to the config.
284+
func (c *Configuration) ConfPath() string {
285+
return fmt.Sprintf(`%s/%s/%s`, c.distro.imageServer, c.distro.confStore, c.distro.configs[c.track])
286+
}
287+
276288
// PowerOff returns whether or not devices should be powered off after write
277289
// operations.
278290
func (c *Configuration) PowerOff() bool {

cli/config/config_test.go

+30
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,36 @@ func TestFFUManifest(t *testing.T) {
517517
}
518518
}
519519

520+
func TestYAMLConfig(t *testing.T) {
521+
track := `default`
522+
distro := distribution{
523+
configs: map[string]string{
524+
track: "conf.yaml",
525+
},
526+
}
527+
want := "conf.yaml"
528+
c := Configuration{track: track, distro: &distro}
529+
if got := c.ConfName(); got != want {
530+
t.Errorf("YAMLConfig() got: %q, want: %q", got, want)
531+
}
532+
}
533+
534+
func TestYAMLPath(t *testing.T) {
535+
track := `default`
536+
distro := distribution{
537+
imageServer: `https://foo.bar.com`,
538+
confStore: `configs/yaml`,
539+
configs: map[string]string{
540+
track: "conf.yaml",
541+
},
542+
}
543+
want := "https://foo.bar.com/configs/yaml/conf.yaml"
544+
c := Configuration{track: track, distro: &distro}
545+
if got := c.ConfPath(); got != want {
546+
t.Errorf("YAMLPath() got: %q, want: %q", got, want)
547+
}
548+
}
549+
520550
func TestCleanup(t *testing.T) {
521551
want := true
522552
c := Configuration{cleanup: want}

cli/installer/installer.go

+59-34
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ var (
8787
errUnsupported = errors.New("unsupported")
8888
errUser = errors.New("user detection error")
8989
errWipe = errors.New("device wipe error")
90+
errYAML = errors.New("yaml retrieval error")
9091

9192
// ErrLabel is made public to that callers can warn on mismatches.
9293
ErrLabel = errors.New(`label error`)
@@ -120,6 +121,8 @@ type Configuration interface {
120121
SeedFile() string
121122
SeedServer() string
122123
UpdateOnly() bool
124+
ConfName() string
125+
ConfPath() string
123126
}
124127

125128
// Device represents storage.Device.
@@ -269,16 +272,30 @@ func (i *Installer) Retrieve() (err error) {
269272
return i.retrieveFile(i.config.ImageFile(), i.config.Image())
270273
}
271274

272-
// Check FFU Path configuration
275+
// Check FFU Path configuration.
273276
if i.config.FFUPath() == "" {
274277
return fmt.Errorf("missing FFU path: %w", errConfig)
275278
}
276279

277-
// Check FFU Manifest configuration
280+
// Check FFU Manifest configuration.
278281
if i.config.FFUManifest() == "" {
279282
return fmt.Errorf("missing FFU manifest: %w", errConfig)
280283
}
281284

285+
// Check for missing conf file name.
286+
if i.config.ConfName() == "" {
287+
return fmt.Errorf("missing configuration file name: %w", errConfig)
288+
}
289+
290+
// Check conf path configuration.
291+
if i.config.ConfPath() == "" {
292+
return fmt.Errorf("missing conf file path: %w", errConfig)
293+
}
294+
295+
if err := i.retrieveFile(i.config.ConfName(), i.config.ConfPath()); err != nil {
296+
return fmt.Errorf("%w: %v", errYAML, err)
297+
}
298+
282299
if err := i.retrieveFile(i.config.ImageFile(), i.config.Image()); err != nil {
283300
return fmt.Errorf("%w: %v", errImage, err)
284301
}
@@ -475,7 +492,8 @@ func (i *Installer) DownloadSFU() error {
475492
return nil
476493
}
477494

478-
// PlaceSFU copies SFU files onto provisioned media from the local cache.
495+
// PlaceSFU copies SFU files and config files onto provisioned media
496+
// from the local cache.
479497
func (i *Installer) PlaceSFU(d Device) error {
480498
// Find a compatible partition to write the FFU to.
481499
logger.V(2).Infof("Searching for FFU %q for a %q partition larger than %v.", d.FriendlyName(), humanize.Bytes(minSFUPartSize), storage.FAT32)
@@ -487,39 +505,46 @@ func (i *Installer) PlaceSFU(d Device) error {
487505
if err != nil {
488506
return fmt.Errorf("getManifest() returned: %w: %v", errManifest, err)
489507
}
508+
// Copy SFU files.
490509
for ind, sfu := range sfus {
491-
// This is done as a separate function call to handle closing
492-
// the files through the defer at the end of each iteration
493-
// of the loop instead of waiting until the end of the function.
494-
func() error {
495-
path := filepath.Join(i.cache, sfu.Filename)
496-
newPath := filepath.Join(p.MountPoint(), i.config.FFUDest(), sfu.Filename)
497-
// Add colon for windows paths if its a drive root.
498-
if runtime.GOOS == "windows" && len(p.MountPoint()) < 2 {
499-
newPath = filepath.Join(fmt.Sprintf("%s:", p.MountPoint()), i.config.FFUDest(), sfu.Filename)
500-
}
501-
console.Printf("Copying SFU %d of %d...", ind+1, len(sfus))
502-
if err := os.MkdirAll(filepath.Dir(newPath), 0644); err != nil {
503-
return fmt.Errorf("failed to create path: %v", err)
504-
}
505-
source, err := os.Open(path)
506-
if err != nil {
507-
return fmt.Errorf("%w: couldn't open file(%s) from cache: %v", errPath, path, err)
508-
}
509-
defer source.Close()
510-
destination, err := os.Create(newPath)
511-
if err != nil {
512-
return fmt.Errorf("%w: couldn't create target file(%s): %v", errFile, path, err)
513-
}
514-
defer destination.Close()
515-
cBytes, err := io.Copy(destination, source)
516-
if err != nil {
517-
return fmt.Errorf("failed to copy file to %s: %v", newPath, err)
518-
}
519-
console.Printf("Copied %d bytes", cBytes)
520-
return nil
521-
}()
510+
console.Printf("Copying SFU %d of %d...", ind+1, len(sfus))
511+
if err := i.fileCopy(sfu.Filename, i.config.FFUDest(), p); err != nil {
512+
return fmt.Errorf("fileCopy() failed for %s to %s: %v", sfu.Filename, i.config.FFUDest(), err)
513+
}
514+
}
515+
// Copy config.
516+
console.Printf("Copying %s", i.config.ConfName())
517+
if err := i.fileCopy(i.config.ConfName(), i.config.FFUDest(), p); err != nil {
518+
return fmt.Errorf("fileCopy() failed for %s to %s: %v", i.config.ConfName(), i.config.FFUDest(), err)
519+
}
520+
return nil
521+
}
522+
523+
func (i *Installer) fileCopy(file, dest string, p partition) error {
524+
path := filepath.Join(i.cache, file)
525+
newPath := filepath.Join(p.MountPoint(), dest, file)
526+
// Add colon for windows paths if its a drive root.
527+
if runtime.GOOS == "windows" && len(p.MountPoint()) < 2 {
528+
newPath = filepath.Join(fmt.Sprintf("%s:", p.MountPoint()), dest, file)
529+
}
530+
if err := os.MkdirAll(filepath.Dir(newPath), 0744); err != nil {
531+
return fmt.Errorf("failed to create path: %v", err)
532+
}
533+
source, err := os.Open(path)
534+
if err != nil {
535+
return fmt.Errorf("%w: couldn't open file(%s) from cache: %v", errPath, path, err)
536+
}
537+
defer source.Close()
538+
destination, err := os.Create(newPath)
539+
if err != nil {
540+
return fmt.Errorf("%w: couldn't create target file(%s): %v", errFile, path, err)
541+
}
542+
defer destination.Close()
543+
cBytes, err := io.Copy(destination, source)
544+
if err != nil {
545+
return fmt.Errorf("failed to copy file to %s: %v", newPath, err)
522546
}
547+
console.Printf("Copied %d bytes", cBytes)
523548
return nil
524549
}
525550

cli/installer/installer_test.go

+106-3
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ type fakeConfig struct {
6060
ffuDest string
6161
ffuPath string
6262
ffuManifest string
63+
confName string
64+
confPath string
6365
}
6466

6567
func (f *fakeConfig) Dismount() bool {
@@ -118,6 +120,14 @@ func (f *fakeConfig) FFUPath() string {
118120
return f.ffuPath
119121
}
120122

123+
func (f *fakeConfig) ConfName() string {
124+
return f.confName
125+
}
126+
127+
func (f *fakeConfig) ConfPath() string {
128+
return f.confPath
129+
}
130+
121131
func TestNew(t *testing.T) {
122132
// Generate a fake config to use with New.
123133
c := &fakeConfig{
@@ -238,6 +248,32 @@ func TestRetrieve(t *testing.T) {
238248
}},
239249
want: errConfig,
240250
},
251+
{
252+
desc: "missing yaml config",
253+
installer: &Installer{cache: fakeCache, config: &fakeConfig{
254+
image: `https://foo.bar.com/test_installer.img`,
255+
imageFile: `test_installer.img`,
256+
ffuPath: `https://foo.bar.com/once/OS/stable/`,
257+
ffu: true,
258+
ffuManifest: "manifest.json",
259+
confName: "",
260+
confPath: "",
261+
}},
262+
want: errConfig,
263+
},
264+
{
265+
desc: "missing yaml path",
266+
installer: &Installer{cache: fakeCache, config: &fakeConfig{
267+
image: `https://foo.bar.com/test_installer.img`,
268+
imageFile: `test_installer.img`,
269+
ffuPath: `https://foo.bar.com/once/OS/stable/`,
270+
ffu: true,
271+
ffuManifest: "manifest.json",
272+
confName: "conf.yaml",
273+
confPath: "",
274+
}},
275+
want: errConfig,
276+
},
241277
{
242278
desc: "missing ffu manifest",
243279
installer: &Installer{cache: fakeCache, config: &fakeConfig{
@@ -268,6 +304,8 @@ func TestRetrieve(t *testing.T) {
268304
ffuPath: `https://foo.bar.com/once/OS/stable/`,
269305
ffu: true,
270306
ffuManifest: "manifest.json",
307+
confPath: "https://foo.bar.com/told/conf.yaml",
308+
confName: "conf.yaml",
271309
}},
272310
download: func(client httpDoer, path string, w io.Writer) error { return nil },
273311
want: nil,
@@ -1289,8 +1327,8 @@ func TestDownloadSFU(t *testing.T) {
12891327
}
12901328
}
12911329

1292-
// createFakeSFU is used to create a set of fake SFU files.
1293-
func createFakeSFU(fakeCache string) error {
1330+
// createFakeFiles is used to create a set of fake SFU and conf files.
1331+
func createFakeFiles(fakeCache, yamlName string) error {
12941332
sfus := fakeReadManifest()
12951333
for _, sfu := range sfus {
12961334
path := filepath.Join(fakeCache, sfu.Filename)
@@ -1300,16 +1338,80 @@ func createFakeSFU(fakeCache string) error {
13001338
}
13011339
defer f.Close()
13021340
}
1341+
path := filepath.Join(fakeCache, yamlName)
1342+
f, err := os.Create(path)
1343+
if err != nil {
1344+
return fmt.Errorf("ioutil.TempFile(%q, %q) returned %w: %v", fakeCache, yamlName, errFile, err)
1345+
}
1346+
defer f.Close()
13031347
return nil
13041348
}
13051349

1350+
func TestFileCopy(t *testing.T) {
1351+
// Setup a temp folder.
1352+
fakeCache, err := ioutil.TempDir("", "")
1353+
if err != nil {
1354+
t.Fatalf("ioutil.TempDir('', '') returned %v", err)
1355+
}
1356+
if err := createFakeFiles(fakeCache, "config.yaml"); err != nil {
1357+
t.Fatalf("createFakeFiles() failed: %v", err)
1358+
}
1359+
// Temp folders representing file system contents.
1360+
mount, _, err := fakeFileSystems()
1361+
if err != nil {
1362+
t.Fatalf("fakeFileSystems() returned %v", err)
1363+
}
1364+
defer os.RemoveAll(mount)
1365+
tests := []struct {
1366+
desc string
1367+
installer *Installer
1368+
file string
1369+
dest string
1370+
part partition
1371+
want error
1372+
}{
1373+
{
1374+
desc: "successful copy",
1375+
installer: &Installer{cache: fakeCache},
1376+
file: "config.yaml",
1377+
dest: `some/dirs`,
1378+
part: &fakePartition{mount: mount},
1379+
want: nil,
1380+
},
1381+
{
1382+
desc: "bad path",
1383+
installer: &Installer{cache: ""},
1384+
file: "config.yaml",
1385+
dest: "",
1386+
part: &fakePartition{mount: mount},
1387+
want: errPath,
1388+
},
1389+
{
1390+
desc: "empty file",
1391+
installer: &Installer{cache: fakeCache},
1392+
file: "",
1393+
dest: "",
1394+
part: &fakePartition{mount: mount},
1395+
want: errFile,
1396+
},
1397+
}
1398+
for _, tt := range tests {
1399+
1400+
got := tt.installer.fileCopy(tt.file, tt.dest, tt.part)
1401+
if !errors.Is(got, tt.want) {
1402+
t.Errorf("%s: fileCopy() got: %v, want: %v", tt.desc, got, tt.want)
1403+
}
1404+
}
1405+
}
1406+
13061407
func TestPlaceSFU(t *testing.T) {
13071408
// Setup a temp folder.
13081409
fakeCache, err := ioutil.TempDir("", "")
13091410
if err != nil {
13101411
t.Fatalf("ioutil.TempDir('', '') returned %v", err)
13111412
}
1312-
if err := createFakeSFU(fakeCache); err != nil {
1413+
yamlName := "conf.yaml"
1414+
if err := createFakeFiles(fakeCache, yamlName); err != nil {
13131415
t.Fatalf("createFakeSFU(%s) returned: %v", fakeCache, err)
13141416
}
13151417

@@ -1323,6 +1425,7 @@ func TestPlaceSFU(t *testing.T) {
13231425
c := &fakeConfig{
13241426
track: "stable",
13251427
ffuManifest: "manifest.json",
1428+
confName: yamlName,
13261429
}
13271430
tests := []struct {
13281431
desc string

0 commit comments

Comments
 (0)