Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

incusd/instances/publish: Fix base metadata #1374

Merged
merged 4 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/incus/top.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ func (c *cmdTop) Run(cmd *cobra.Command, args []string) error {

// These variables can be changed by the UI
refreshInterval := time.Duration(c.flagRefresh) * time.Second
sortingMethod := alphabetical // default is alphabetical, could change this to a flag
sortingMethod := alphabetical // default is alphabetical, could change this to a flag

// Start the ticker for periodic updates
ticker := time.NewTicker(refreshInterval)
Expand Down
12 changes: 6 additions & 6 deletions cmd/incusd/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,16 +346,11 @@ func imgPostInstanceInfo(ctx context.Context, s *state.State, r *http.Request, r
}

// Export instance to writer.
var meta api.ImageMetadata
var meta *api.ImageMetadata

writer = internalIO.NewQuotaWriter(writer, budget)
meta, err = c.Export(writer, req.Properties, req.ExpiresAt, tracker)

// Get ExpiresAt
if meta.ExpiryDate != 0 {
info.ExpiresAt = time.Unix(meta.ExpiryDate, 0)
}

// Clean up file handles.
// When compression is used, Close on imageProgressWriter/tarWriter is required for compressFile/gzip to
// know it is finished. Otherwise it is equivalent to imageFile.Close.
Expand All @@ -373,6 +368,11 @@ func imgPostInstanceInfo(ctx context.Context, s *state.State, r *http.Request, r
return nil, err
}

// Get ExpiresAt
if meta.ExpiryDate != 0 {
info.ExpiresAt = time.Unix(meta.ExpiryDate, 0)
}

fi, err := os.Stat(imageFile.Name())
if err != nil {
return nil, err
Expand Down
205 changes: 77 additions & 128 deletions internal/server/instance/drivers/driver_lxc.go
Original file line number Diff line number Diff line change
Expand Up @@ -5135,16 +5135,14 @@ func (d *lxc) Update(args db.InstanceArgs, userRequested bool) error {
}

// Export backs up the instance.
func (d *lxc) Export(w io.Writer, properties map[string]string, expiration time.Time, tracker *ioprogress.ProgressTracker) (api.ImageMetadata, error) {
func (d *lxc) Export(w io.Writer, properties map[string]string, expiration time.Time, tracker *ioprogress.ProgressTracker) (*api.ImageMetadata, error) {
ctxMap := logger.Ctx{
"created": d.creationDate,
"ephemeral": d.ephemeral,
"used": d.lastUsedDate}

meta := api.ImageMetadata{}

if d.IsRunning() {
return meta, fmt.Errorf("Cannot export a running instance as an image")
return nil, fmt.Errorf("Cannot export a running instance as an image")
}

d.logger.Info("Exporting instance", ctxMap)
Expand All @@ -5153,7 +5151,7 @@ func (d *lxc) Export(w io.Writer, properties map[string]string, expiration time.
_, err := d.mount()
if err != nil {
d.logger.Error("Failed exporting instance", ctxMap)
return meta, err
return nil, err
}

defer func() { _ = d.unmount() }()
Expand All @@ -5162,7 +5160,7 @@ func (d *lxc) Export(w io.Writer, properties map[string]string, expiration time.
idmap, err := d.DiskIdmap()
if err != nil {
d.logger.Error("Failed exporting instance", ctxMap)
return meta, err
return nil, err
}

// Create the tarball.
Expand All @@ -5188,164 +5186,115 @@ func (d *lxc) Export(w io.Writer, properties map[string]string, expiration time.
return nil
}

// Look for metadata.yaml.
fnam := filepath.Join(cDir, "metadata.yaml")
if !util.PathExists(fnam) {
// Generate a new metadata.yaml.
tempDir, err := os.MkdirTemp("", "incus_metadata_")
// Get the instance's architecture.
var arch string
if d.IsSnapshot() {
parentName, _, _ := api.GetParentAndSnapshotName(d.name)
parent, err := instance.LoadByProjectAndName(d.state, d.project.Name, parentName)
if err != nil {
_ = tarWriter.Close()
d.logger.Error("Failed exporting instance", ctxMap)
return meta, err
}

defer func() { _ = os.RemoveAll(tempDir) }()

// Get the instance's architecture.
var arch string
if d.IsSnapshot() {
parentName, _, _ := api.GetParentAndSnapshotName(d.name)
parent, err := instance.LoadByProjectAndName(d.state, d.project.Name, parentName)
if err != nil {
_ = tarWriter.Close()
d.logger.Error("Failed exporting instance", ctxMap)
return meta, err
}

arch, _ = osarch.ArchitectureName(parent.Architecture())
} else {
arch, _ = osarch.ArchitectureName(d.architecture)
}

if arch == "" {
arch, err = osarch.ArchitectureName(d.state.OS.Architectures[0])
if err != nil {
d.logger.Error("Failed exporting instance", ctxMap)
return meta, err
}
}

// Fill in the metadata.
meta.Architecture = arch
meta.CreationDate = time.Now().UTC().Unix()
meta.Properties = properties
if !expiration.IsZero() {
meta.ExpiryDate = expiration.UTC().Unix()
return nil, err
}

data, err := yaml.Marshal(&meta)
if err != nil {
_ = tarWriter.Close()
d.logger.Error("Failed exporting instance", ctxMap)
return meta, err
}
arch, _ = osarch.ArchitectureName(parent.Architecture())
} else {
arch, _ = osarch.ArchitectureName(d.architecture)
}

// Write the actual file.
fnam = filepath.Join(tempDir, "metadata.yaml")
err = os.WriteFile(fnam, data, 0644)
if arch == "" {
arch, err = osarch.ArchitectureName(d.state.OS.Architectures[0])
if err != nil {
_ = tarWriter.Close()
d.logger.Error("Failed exporting instance", ctxMap)
return meta, err
return nil, err
}
}

fi, err := os.Lstat(fnam)
if err != nil {
_ = tarWriter.Close()
d.logger.Error("Failed exporting instance", ctxMap)
return meta, err
}
// Generate metadata.yaml.
meta := api.ImageMetadata{}
fnam := filepath.Join(cDir, "metadata.yaml")

tmpOffset := len(path.Dir(fnam)) + 1
err = tarWriter.WriteFile(fnam[tmpOffset:], fnam, fi, false)
if err != nil {
_ = tarWriter.Close()
d.logger.Debug("Error writing to tarfile", logger.Ctx{"err": err})
d.logger.Error("Failed exporting instance", ctxMap)
return meta, err
}
} else {
if util.PathExists(fnam) {
// Parse the metadata.
content, err := os.ReadFile(fnam)
if err != nil {
_ = tarWriter.Close()
d.logger.Error("Failed exporting instance", ctxMap)
return meta, err
return nil, err
}

err = yaml.Unmarshal(content, &meta)
if err != nil {
_ = tarWriter.Close()
d.logger.Error("Failed exporting instance", ctxMap)
return meta, err
return nil, err
}
}

if !expiration.IsZero() {
meta.ExpiryDate = expiration.UTC().Unix()
}
// Fill in the metadata.
meta.Architecture = arch
meta.CreationDate = time.Now().UTC().Unix()

if properties != nil {
meta.Properties = properties
}
if meta.Properties == nil {
meta.Properties = map[string]string{}
}

if properties != nil || !expiration.IsZero() {
// Generate a new metadata.yaml.
tempDir, err := os.MkdirTemp("", "incus_metadata_")
if err != nil {
_ = tarWriter.Close()
d.logger.Error("Failed exporting instance", ctxMap)
return meta, err
}
for k, v := range properties {
meta.Properties[k] = v
}

defer func() { _ = os.RemoveAll(tempDir) }()
if !expiration.IsZero() {
meta.ExpiryDate = expiration.UTC().Unix()
}

data, err := yaml.Marshal(&meta)
if err != nil {
_ = tarWriter.Close()
d.logger.Error("Failed exporting instance", ctxMap)
return meta, err
}
// Write the new metadata.yaml.
tempDir, err := os.MkdirTemp("", "incus_metadata_")
if err != nil {
_ = tarWriter.Close()
d.logger.Error("Failed exporting instance", ctxMap)
return nil, err
}

// Write the actual file.
fnam = filepath.Join(tempDir, "metadata.yaml")
err = os.WriteFile(fnam, data, 0644)
if err != nil {
_ = tarWriter.Close()
d.logger.Error("Failed exporting instance", ctxMap)
return meta, err
}
}
defer func() { _ = os.RemoveAll(tempDir) }()

// Include metadata.yaml in the tarball.
fi, err := os.Lstat(fnam)
if err != nil {
_ = tarWriter.Close()
d.logger.Debug("Error statting during export", logger.Ctx{"fileName": fnam})
d.logger.Error("Failed exporting instance", ctxMap)
return meta, err
}
data, err := yaml.Marshal(&meta)
if err != nil {
_ = tarWriter.Close()
d.logger.Error("Failed exporting instance", ctxMap)
return nil, err
}

if properties != nil || !expiration.IsZero() {
tmpOffset := len(path.Dir(fnam)) + 1
err = tarWriter.WriteFile(fnam[tmpOffset:], fnam, fi, false)
} else {
err = tarWriter.WriteFile(fnam[offset:], fnam, fi, false)
}
fnam = filepath.Join(tempDir, "metadata.yaml")
err = os.WriteFile(fnam, data, 0644)
if err != nil {
_ = tarWriter.Close()
d.logger.Error("Failed exporting instance", ctxMap)
return nil, err
}

if err != nil {
_ = tarWriter.Close()
d.logger.Debug("Error writing to tarfile", logger.Ctx{"err": err})
d.logger.Error("Failed exporting instance", ctxMap)
return meta, err
}
// Add metadata.yaml to the tarball.
fi, err := os.Lstat(fnam)
if err != nil {
_ = tarWriter.Close()
d.logger.Error("Failed exporting instance", ctxMap)
return nil, err
}

tmpOffset := len(filepath.Dir(fnam)) + 1
err = tarWriter.WriteFile(fnam[tmpOffset:], fnam, fi, false)
if err != nil {
_ = tarWriter.Close()
d.logger.Debug("Error writing to tarfile", logger.Ctx{"err": err})
d.logger.Error("Failed exporting instance", ctxMap)
return nil, err
}

// Include all the rootfs files.
fnam = d.RootfsPath()
err = filepath.Walk(fnam, writeToTar)
if err != nil {
d.logger.Error("Failed exporting instance", ctxMap)
return meta, err
return nil, err
}

// Include all the templates.
Expand All @@ -5354,18 +5303,18 @@ func (d *lxc) Export(w io.Writer, properties map[string]string, expiration time.
err = filepath.Walk(fnam, writeToTar)
if err != nil {
d.logger.Error("Failed exporting instance", ctxMap)
return meta, err
return nil, err
}
}

err = tarWriter.Close()
if err != nil {
d.logger.Error("Failed exporting instance", ctxMap)
return meta, err
return nil, err
}

d.logger.Info("Exported instance", ctxMap)
return meta, nil
return &meta, nil
}

func collectCRIULogFile(d instance.Instance, imagesDir string, function string, method string) error {
Expand Down
Loading
Loading