Refactor gRPC-based image functions

Signed-off-by: Jonathon Anderson <janderson@ciq.com>
This commit is contained in:
Jonathon Anderson
2026-03-21 01:49:07 -06:00
parent a21a73379f
commit 3c895dd941
15 changed files with 420 additions and 582 deletions

View File

@@ -4,8 +4,6 @@ import (
"fmt"
"path"
"github.com/pkg/errors"
"github.com/warewulf/warewulf/internal/pkg/util"
"github.com/warewulf/warewulf/internal/pkg/wwlog"
)
@@ -17,7 +15,7 @@ func Build(name string, buildForce bool) error {
imagePath := ImageFile(name)
if !ValidSource(name) {
return errors.Errorf("Image does not exist: %s", name)
return fmt.Errorf("Image does not exist: %s", name)
}
if !buildForce {

View File

@@ -0,0 +1,78 @@
package image
import (
"fmt"
"os"
"github.com/warewulf/warewulf/internal/pkg/node"
"github.com/warewulf/warewulf/internal/pkg/util"
"github.com/warewulf/warewulf/internal/pkg/wwlog"
)
func Delete(name string) error {
// validate image names
if !ValidSource(name) {
return fmt.Errorf("image name is not valid source: %s", name)
}
nodeDB, err := node.New()
if err != nil {
return fmt.Errorf("could not open nodeDB: %s", err)
}
// check if the deleted images are not used by nodes
for nodeName, node := range nodeDB.Nodes {
if node.ImageName == name {
return fmt.Errorf("image %s is in use by node %s, cannot delete", node.ImageName, nodeName)
}
}
// check if the deleted images are not used by profiles
for profileName, profile := range nodeDB.NodeProfiles {
if profile.ImageName == name {
return fmt.Errorf("image %s is in use by profile %s, cannot delete", profile.ImageName, profileName)
}
}
// delete images
if err := DeleteSource(name); err != nil {
return fmt.Errorf("could not remove image source %s: %w", name, err)
}
if err := DeleteImage(name); err != nil {
return fmt.Errorf("could not remove image file %s: %w", name, err)
}
wwlog.Info("Deleted image %q", name)
return nil
}
/*
Delete the chroot of an image
*/
func DeleteSource(name string) error {
fullPath := SourceDir(name)
wwlog.Verbose("Removing path: %s", fullPath)
return os.RemoveAll(fullPath)
}
/*
Delete the image of an image
*/
func DeleteImage(name string) error {
imageFile := ImageFile(name)
if util.IsFile(imageFile) {
wwlog.Verbose("removing %s for image %s", imageFile, name)
errImg := os.Remove(imageFile)
wwlog.Verbose("removing %s for image %s", imageFile+".gz", name)
errGz := os.Remove(imageFile + ".gz")
if errImg != nil {
return fmt.Errorf("Problems delete %s for image %s: %s", imageFile, name, errImg)
}
if errGz != nil {
return fmt.Errorf("Problems delete %s for image %s: %s", imageFile+".gz", name, errGz)
}
return nil
}
return fmt.Errorf("Image %s of image %s doesn't exist", imageFile, name)
}

View File

@@ -2,8 +2,10 @@ package image
import (
"context"
"fmt"
"os"
"path"
"strconv"
"github.com/containers/image/v5/types"
"github.com/containers/storage/drivers/copy"
@@ -74,3 +76,48 @@ func ImportDirectory(uri string, name string) error {
return nil
}
// create the system context and reading out environment variables
func GetSystemContext(noHttps bool, username string, password string, platform string) (sCtx *types.SystemContext, err error) {
sCtx = &types.SystemContext{}
// only check env if noHttps wasn't set
if !noHttps {
val, ok := os.LookupEnv("WAREWULF_OCI_NOHTTPS")
if ok {
noHttps, err = strconv.ParseBool(val)
if err != nil {
return nil, fmt.Errorf("while parsing insecure http option: %v", err)
}
}
// only set this if we want to disable, otherwise leave as undefined
if noHttps {
sCtx.DockerInsecureSkipTLSVerify = types.NewOptionalBool(true)
}
sCtx.OCIInsecureSkipTLSVerify = noHttps
}
if username == "" {
username, _ = os.LookupEnv("WAREWULF_OCI_USERNAME")
}
if password == "" {
password, _ = os.LookupEnv("WAREWULF_OCI_PASSWORD")
}
if username != "" || password != "" {
if username != "" && password != "" {
sCtx.DockerAuthConfig = &types.DockerAuthConfig{
Username: username,
Password: password,
}
} else {
return nil, fmt.Errorf("oci username and password env vars must be specified together")
}
}
if platform == "" {
platform, _ = os.LookupEnv("WAREWULF_OCI_PLATFORM")
}
if platform != "" {
sCtx.ArchitectureChoice = platform
}
return sCtx, nil
}

View File

@@ -0,0 +1,60 @@
package image
import (
"fmt"
"os"
"github.com/warewulf/warewulf/internal/pkg/node"
"github.com/warewulf/warewulf/internal/pkg/wwlog"
)
func Rename(name string, targetName string, build bool) error {
if !ValidSource(name) {
return fmt.Errorf("image source does not exist: %s", name)
}
if !ValidName(targetName) {
return fmt.Errorf("invalid image name: %s", targetName)
}
// rename the image source folder
sourceDir := SourceDir(name)
destDir := SourceDir(targetName)
err := os.Rename(sourceDir, destDir)
if err != nil {
return err
}
err = DeleteImage(name)
if err != nil {
wwlog.Warn("Could not remove image files for %s: %s", name, err)
}
if build {
err = Build(targetName, true)
if err != nil {
return err
}
}
// update the nodes profiles image name
nodeDB, err := node.New()
if err != nil {
return err
}
for nodeId, node := range nodeDB.Nodes {
if node.ImageName == name {
wwlog.Debug("updating node %s image to %s", nodeId, targetName)
nodeDB.Nodes[nodeId].ImageName = targetName
}
}
for profileId, profile := range nodeDB.NodeProfiles {
if profile.ImageName == name {
wwlog.Debug("updating profile %s image to %s", profileId, targetName)
nodeDB.NodeProfiles[profileId].ImageName = targetName
}
}
return nodeDB.Persist()
}

View File

@@ -68,16 +68,6 @@ func ValidSource(name string) bool {
return true
}
/*
Delete the chroot of an image
*/
func DeleteSource(name string) error {
fullPath := SourceDir(name)
wwlog.Verbose("Removing path: %s", fullPath)
return os.RemoveAll(fullPath)
}
func Duplicate(name string, destination string) error {
fullPathImageSource := RootFsDir(name)
@@ -91,27 +81,6 @@ func Duplicate(name string, destination string) error {
return nil
}
/*
Delete the image of an image
*/
func DeleteImage(name string) error {
imageFile := ImageFile(name)
if util.IsFile(imageFile) {
wwlog.Verbose("removing %s for image %s", imageFile, name)
errImg := os.Remove(imageFile)
wwlog.Verbose("removing %s for image %s", imageFile+".gz", name)
errGz := os.Remove(imageFile + ".gz")
if errImg != nil {
return errors.Errorf("Problems delete %s for image %s: %s\n", imageFile, name, errImg)
}
if errGz != nil {
return errors.Errorf("Problems delete %s for image %s: %s\n", imageFile+".gz", name, errGz)
}
return nil
}
return errors.Errorf("Image %s of image %s doesn't exist\n", imageFile, name)
}
func IsWriteAble(name string) bool {
return !util.IsFile(filepath.Join(SourceDir(name), "readonly"))
}