Skip to content

Commit

Permalink
Merge branch 'lxc:main' into use-mount.ceph
Browse files Browse the repository at this point in the history
  • Loading branch information
MadnessASAP authored Dec 10, 2024
2 parents f8797c9 + 411dc2a commit 5d93f08
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 14 deletions.
8 changes: 6 additions & 2 deletions client/oci_images.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (

"github.com/lxc/incus/v6/shared/api"
"github.com/lxc/incus/v6/shared/ioprogress"
"github.com/lxc/incus/v6/shared/logger"
"github.com/lxc/incus/v6/shared/osarch"
"github.com/lxc/incus/v6/shared/subprocess"
"github.com/lxc/incus/v6/shared/units"
Expand Down Expand Up @@ -145,13 +146,14 @@ func (r *ProtocolOCI) GetImageFile(fingerprint string, req ImageFileRequest) (*I
req.ProgressHandler(ioprogress.ProgressData{Text: "Retrieving OCI image from registry"})
}

_, err = subprocess.RunCommand(
stdout, err := subprocess.RunCommand(
"skopeo",
"--insecure-policy",
"copy",
fmt.Sprintf("%s/%s", strings.Replace(r.httpHost, "https://", "docker://", -1), info.Alias),
fmt.Sprintf("oci:%s:latest", filepath.Join(ociPath, "oci")))
if err != nil {
logger.Debug("Error copying remote image to local", logger.Ctx{"image": info.Alias, "stdout": stdout, "stderr": err})
return nil, err
}

Expand All @@ -160,13 +162,14 @@ func (r *ProtocolOCI) GetImageFile(fingerprint string, req ImageFileRequest) (*I
req.ProgressHandler(ioprogress.ProgressData{Text: "Unpacking the OCI image"})
}

_, err = subprocess.RunCommand(
stdout, err = subprocess.RunCommand(
"umoci",
"unpack",
"--keep-dirlinks",
"--image", filepath.Join(ociPath, "oci"),
filepath.Join(ociPath, "image"))
if err != nil {
logger.Debug("Error unpacking OCI image", logger.Ctx{"image": filepath.Join(ociPath, "oci"), "stdout": stdout, "stderr": err})
return nil, err
}

Expand Down Expand Up @@ -305,6 +308,7 @@ func (r *ProtocolOCI) GetImageAlias(name string) (*api.ImageAliasesEntry, string
// Get the image information from skopeo.
stdout, err := subprocess.RunCommand("skopeo", "inspect", fmt.Sprintf("%s/%s", strings.Replace(r.httpHost, "https://", "docker://", -1), name))
if err != nil {
logger.Debug("Error getting image alias", logger.Ctx{"name": name, "stdout": stdout, "stderr": err})
return nil, "", err
}

Expand Down
4 changes: 2 additions & 2 deletions cmd/incusd/daemon_images.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func ImageDownload(ctx context.Context, r *http.Request, s *state.State, op *ope
// Setup OCI client
remote, err = incus.ConnectOCI(args.Server, clientArgs)
if err != nil {
return nil, false, fmt.Errorf("Failed to connect to simple streams server %q: %w", args.Server, err)
return nil, false, fmt.Errorf("Failed to connect to oci server %q: %w", args.Server, err)
}
} else if protocol == "simplestreams" {
// Setup simplestreams client
Expand All @@ -114,7 +114,7 @@ func ImageDownload(ctx context.Context, r *http.Request, s *state.State, op *ope

// For public images, handle aliases and initial metadata
if args.Secret == "" {
// Look for a matching alias
// Look for a matching alias. Note, this err message is lost!
entry, _, err := remote.GetImageAliasType(args.Type, fp)
if err == nil {
fp = entry.Target
Expand Down
90 changes: 80 additions & 10 deletions internal/server/scriptlet/load/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package load
import (
"fmt"
"slices"
"sort"
"sync"

"go.starlark.net/starlark"
Expand All @@ -15,8 +16,8 @@ const nameInstancePlacement = "instance_placement"
// prefixQEMU is the prefix used in Starlark for the QEMU scriptlet.
const prefixQEMU = "qemu"

// prefixAuthorization is the prefix used in Starlark for the Authorization scriptlet.
const prefixAuthorization = "authorization"
// nameAuthorization is the name used in Starlark for the Authorization scriptlet.
const nameAuthorization = "authorization"

// compile compiles a scriptlet.
func compile(programName string, src string, preDeclared []string) (*starlark.Program, error) {
Expand All @@ -33,6 +34,72 @@ func compile(programName string, src string, preDeclared []string) (*starlark.Pr
return mod, nil
}

// validate validates a scriptlet by compiling it and checking the presence of required functions.
func validate(compiler func(string, string) (*starlark.Program, error), programName string, src string, requiredFunctions map[string][]string) error {
prog, err := compiler(programName, src)
if err != nil {
return err
}

thread := &starlark.Thread{Name: programName}
globals, err := prog.Init(thread, nil)
if err != nil {
return err
}

globals.Freeze()

var notFound []string
for funName, requiredArgs := range requiredFunctions {
// The function is missing if its name is not found in the globals.
funv := globals[funName]
if funv == nil {
notFound = append(notFound, funName)
continue
}

// The function is missing if its name is not bound to a function.
fun, ok := funv.(*starlark.Function)
if !ok {
notFound = append(notFound, funName)
}

// Get the function arguments.
argc := fun.NumParams()
var args []string
for i := range argc {
arg, _ := fun.Param(i)
args = append(args, arg)
}

// Return an error early if the function does not have the right arguments.
match := len(args) == len(requiredArgs)
if match {
sort.Strings(args)
sort.Strings(requiredArgs)
for i := range args {
if args[i] != requiredArgs[i] {
match = false
break
}
}
}

if !match {
return fmt.Errorf("The function %q defines arguments %q (expected: %q)", funName, args, requiredArgs)
}
}

switch len(notFound) {
case 0:
return nil
case 1:
return fmt.Errorf("The function %q is required but has not been found in the scriptlet", notFound[0])
default:
return fmt.Errorf("The functions %q are required but have not been found in the scriptlet", notFound)
}
}

var programsMu sync.Mutex
var programs = make(map[string]*starlark.Program)

Expand Down Expand Up @@ -89,8 +156,9 @@ func InstancePlacementCompile(name string, src string) (*starlark.Program, error

// InstancePlacementValidate validates the instance placement scriptlet.
func InstancePlacementValidate(src string) error {
_, err := InstancePlacementCompile(nameInstancePlacement, src)
return err
return validate(InstancePlacementCompile, nameInstancePlacement, src, map[string][]string{
"instance_placement": {"request", "candidate_members"},
})
}

// InstancePlacementSet compiles the instance placement scriptlet into memory for use with InstancePlacementRun.
Expand Down Expand Up @@ -131,8 +199,9 @@ func QEMUCompile(name string, src string) (*starlark.Program, error) {

// QEMUValidate validates the QEMU scriptlet.
func QEMUValidate(src string) error {
_, err := QEMUCompile(prefixQEMU, src)
return err
return validate(QEMUCompile, prefixQEMU, src, map[string][]string{
"qemu_hook": {"hook_name"},
})
}

// QEMUSet compiles the QEMU scriptlet into memory for use with QEMURun.
Expand All @@ -157,17 +226,18 @@ func AuthorizationCompile(name string, src string) (*starlark.Program, error) {

// AuthorizationValidate validates the authorization scriptlet.
func AuthorizationValidate(src string) error {
_, err := AuthorizationCompile(prefixAuthorization, src)
return err
return validate(AuthorizationCompile, nameAuthorization, src, map[string][]string{
"authorize": {"details", "object", "entitlement"},
})
}

// AuthorizationSet compiles the authorization scriptlet into memory for use with AuthorizationRun.
// If empty src is provided the current program is deleted.
func AuthorizationSet(src string) error {
return set(AuthorizationCompile, prefixAuthorization, src)
return set(AuthorizationCompile, nameAuthorization, src)
}

// AuthorizationProgram returns the precompiled authorization scriptlet program.
func AuthorizationProgram() (*starlark.Program, *starlark.Thread, error) {
return program("Authorization", prefixAuthorization)
return program("Authorization", nameAuthorization)
}

0 comments on commit 5d93f08

Please sign in to comment.