fixed push authentication for container_image resource
This commit is contained in:
parent
2bee7f6bea
commit
b08d025567
5
go.mod
5
go.mod
@ -3,7 +3,7 @@ module decl
|
||||
go 1.22.5
|
||||
|
||||
require (
|
||||
// gitea.rosskeen.house/pylon/luaruntime v0.0.0-20240513200425-f413d8adf7b3
|
||||
// gitea.rosskeen.house/pylon/luaruntime v0.0.0-20240513200425-f413d8adf7b3
|
||||
gitea.rosskeen.house/rosskeen.house/machine v0.0.0-20240520193117-1835255b6d02
|
||||
github.com/docker/docker v27.0.3+incompatible
|
||||
github.com/docker/go-connections v0.5.0
|
||||
@ -14,7 +14,10 @@ require (
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require google.golang.org/protobuf v1.33.0
|
||||
|
||||
require (
|
||||
gitea.rosskeen.house/pylon/luaruntime v0.0.0-20240924031921-4d00743b53e1 // indirect
|
||||
github.com/Microsoft/go-winio v0.4.14 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
|
4
go.sum
4
go.sum
@ -1,9 +1,9 @@
|
||||
gitea.rosskeen.house/pylon/luaruntime v0.0.0-20240513200425-f413d8adf7b3 h1:ge74Hmzxp+bqVwSK9hOOBlZB9KeL3xuwMIXAYLPHBxA=
|
||||
gitea.rosskeen.house/pylon/luaruntime v0.0.0-20240513200425-f413d8adf7b3/go.mod h1:9sKIXsGDcf1uBnHhY29wi38Vll8dpVNUOxkXphN2KEk=
|
||||
gitea.rosskeen.house/pylon/luaruntime v0.0.0-20240924031921-4d00743b53e1 h1:UT79l0TvkYjlAbJrsFIm6R0tL+Rl/814ThKbjOgrTPo=
|
||||
gitea.rosskeen.house/pylon/luaruntime v0.0.0-20240924031921-4d00743b53e1/go.mod h1:9sKIXsGDcf1uBnHhY29wi38Vll8dpVNUOxkXphN2KEk=
|
||||
gitea.rosskeen.house/rosskeen.house/machine v0.0.0-20240520193117-1835255b6d02 h1:FLRmUvu0mz8Ac+/VZf/P4yuv2e6++SSkKOcEIHSlpAI=
|
||||
gitea.rosskeen.house/rosskeen.house/machine v0.0.0-20240520193117-1835255b6d02/go.mod h1:5J2OFjFIBaCfsjcC9kSyycbIL8g/qAJH2A8BnbIig+Y=
|
||||
gitea.rosskeen.house/rosskeen.house/testing v0.0.0-20240509163950-64f2fc3e00d5 h1:1TUeKrJ12K6+Iobc8rpL/gUaGPFBmTqKjJnkT+2B5nM=
|
||||
gitea.rosskeen.house/rosskeen.house/testing v0.0.0-20240509163950-64f2fc3e00d5/go.mod h1:gbxopbzqpz0ZMAcsPu2XqtprOoFdxwTGz45p06zuI0A=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
|
||||
|
@ -10,7 +10,7 @@ _ "decl/internal/config"
|
||||
_ "decl/internal/resource"
|
||||
"decl/internal/fs"
|
||||
"decl/internal/builtin"
|
||||
_ "errors"
|
||||
"errors"
|
||||
"fmt"
|
||||
"context"
|
||||
"log/slog"
|
||||
@ -19,6 +19,7 @@ _ "errors"
|
||||
|
||||
|
||||
var (
|
||||
ErrFailedResources error = errors.New("Failed Resources")
|
||||
)
|
||||
|
||||
type App struct {
|
||||
@ -178,7 +179,7 @@ func (a *App) Apply(ctx context.Context, deleteResources bool) (err error) {
|
||||
return e
|
||||
}
|
||||
if d.Failures() > 0 {
|
||||
err = fmt.Errorf("Failed resources: %d, %w", d.Failures(), err)
|
||||
err = fmt.Errorf("%w: %d, %w", ErrFailedResources, d.Failures(), err)
|
||||
}
|
||||
}
|
||||
return
|
||||
@ -223,7 +224,10 @@ func (a *App) ApplyCmd(ctx context.Context, docs []string, quiet bool, deleteRes
|
||||
}
|
||||
|
||||
if err = a.Apply(ctx, deleteResources); err != nil {
|
||||
return
|
||||
slog.Info("Client.ApplyCmd()", "client", a, "error", err)
|
||||
if ! errors.Is(err, ErrFailedResources) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if quiet {
|
||||
|
@ -204,13 +204,21 @@ func (d *Declaration) Apply(stateTransition string) (result error) {
|
||||
}
|
||||
|
||||
func (d *Declaration) SetConfig(configDoc data.Document) {
|
||||
slog.Info("Declaration.SetConfig()", "config", configDoc)
|
||||
if configDoc != nil {
|
||||
if configDoc.Has(string(d.Config)) {
|
||||
v, _ := configDoc.Get(string(d.Config))
|
||||
d.configBlock = v.(data.Block)
|
||||
d.Attributes.UseConfig(d.configBlock)
|
||||
if v, ok := configDoc.Get(string(d.Config)); ok {
|
||||
d.configBlock = v.(data.Block)
|
||||
d.Attributes.UseConfig(d.configBlock)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if v, ok := DocumentRegistry.ConfigNameMap.Get(string(d.Config)); ok {
|
||||
d.configBlock = v
|
||||
d.Attributes.UseConfig(d.configBlock)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Declaration) SetURI(uri string) (err error) {
|
||||
|
@ -263,35 +263,37 @@ func (d *Document) Apply(state string) error {
|
||||
if state == "delete" {
|
||||
start = len(d.ResourceDeclarations) - 1
|
||||
}
|
||||
for {
|
||||
idx := i - start
|
||||
if idx < 0 { idx = - idx }
|
||||
if len(d.ResourceDeclarations) > 0 {
|
||||
for {
|
||||
idx := i - start
|
||||
if idx < 0 { idx = - idx }
|
||||
|
||||
slog.Info("Document.Apply() applying resource", "index", idx, "uri", d.ResourceDeclarations[idx].Resource().URI(), "resource", d.ResourceDeclarations[idx].Resource())
|
||||
d.ResourceDeclarations[idx].SetConfig(d.config)
|
||||
slog.Info("Document.Apply() applying resource", "index", idx, "uri", d.ResourceDeclarations[idx].Resource().URI(), "resource", d.ResourceDeclarations[idx].Resource())
|
||||
d.ResourceDeclarations[idx].SetConfig(d.config)
|
||||
|
||||
slog.Info("Document.Apply() applying resource", "index", idx, "uri", d.ResourceDeclarations[idx].Resource().URI(), "resource", d.ResourceDeclarations[idx].Resource())
|
||||
slog.Info("Document.Apply() applying resource", "index", idx, "uri", d.ResourceDeclarations[idx].Resource().URI(), "resource", d.ResourceDeclarations[idx].Resource())
|
||||
|
||||
if d.ResourceDeclarations[idx].Requires.Check() {
|
||||
if d.ResourceDeclarations[idx].Requires.Check() {
|
||||
|
||||
if e := d.ResourceDeclarations[idx].Apply(state); e != nil {
|
||||
slog.Error("Document.Apply() error applying resource", "index", idx, "uri", d.ResourceDeclarations[idx].Resource().URI())
|
||||
if e := d.ResourceDeclarations[idx].Apply(state); e != nil {
|
||||
slog.Error("Document.Apply() error applying resource", "index", idx, "uri", d.ResourceDeclarations[idx].Resource().URI())
|
||||
|
||||
d.ResourceDeclarations[idx].Error = e.Error()
|
||||
switch d.ResourceDeclarations[idx].OnError.GetStrategy() {
|
||||
case OnErrorStop:
|
||||
return e
|
||||
case OnErrorFail:
|
||||
d.failedResources++
|
||||
d.ResourceDeclarations[idx].Error = e.Error()
|
||||
switch d.ResourceDeclarations[idx].OnError.GetStrategy() {
|
||||
case OnErrorStop:
|
||||
return e
|
||||
case OnErrorFail:
|
||||
d.failedResources++
|
||||
}
|
||||
}
|
||||
} else {
|
||||
d.ResourceDeclarations[idx].Error = fmt.Sprintf("Constraint failure: %s", d.ResourceDeclarations[idx].Requires)
|
||||
}
|
||||
} else {
|
||||
d.ResourceDeclarations[idx].Error = fmt.Sprintf("Constraint failure: %s", d.ResourceDeclarations[idx].Requires)
|
||||
if i >= len(d.ResourceDeclarations) - 1 {
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
if i >= len(d.ResourceDeclarations) - 1 {
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -34,6 +34,26 @@ const (
|
||||
ContainerImageTypeName TypeName = "container-image"
|
||||
)
|
||||
|
||||
type ContainerProgressDetail struct {
|
||||
ProgressMessage string `json:"message,omitempty" yaml:"message,omitempty"`
|
||||
}
|
||||
|
||||
type ContainerLogStatus struct {
|
||||
Status string `json:"status,omitempty" yaml:"status,omitempty"`
|
||||
ProgressDetail ContainerProgressDetail `json:"progressDetail,omitempty" yaml:"progressDetail,omitempty"`
|
||||
Id string `json:"id,omitempty" yaml:"id,omitempty"`
|
||||
}
|
||||
|
||||
type ContainerLogStream struct {
|
||||
Stream string `json:"stream,omitempty" yaml:"stream,omitempty"`
|
||||
}
|
||||
|
||||
type ContainerLog struct {
|
||||
*ContainerLogStream `json:",inline" yaml:",inline"`
|
||||
*ContainerLogStatus `json:",inline" yaml:",inline"`
|
||||
*ContainerError `json:",inline" yaml:",inline"`
|
||||
}
|
||||
|
||||
type ContainerErrorDetail struct {
|
||||
ErrorMessage string `json:"message" yaml:"message"`
|
||||
}
|
||||
@ -69,7 +89,8 @@ type ContainerImage struct {
|
||||
ContextRef folio.ResourceReference `json:"contextref,omitempty" yaml:"contextref,omitempty"`
|
||||
InjectJX bool `json:"injectjx,omitempty" yaml:"injectjx,omitempty"`
|
||||
PushImage bool `json:"push,omitempty" yaml:"push,omitempty"`
|
||||
Output strings.Builder `json:"output,omitempty" yaml:"output,omitempty"`
|
||||
Output []ContainerLog `json:"output,omitempty" yaml:"output,omitempty"`
|
||||
outputWriter strings.Builder `json:"-" yaml:"-"`
|
||||
|
||||
apiClient ContainerImageClient
|
||||
Resources data.ResourceMapper `json:"-" yaml:"-"`
|
||||
@ -118,7 +139,7 @@ func (c *ContainerImage) RegistryAuthConfig() (authConfig registry.AuthConfig, e
|
||||
authConfig.Password = configValue.(string)
|
||||
}
|
||||
if configValue, err = c.config.GetValue("repo_server"); err != nil {
|
||||
return
|
||||
return authConfig, nil
|
||||
} else {
|
||||
authConfig.ServerAddress = configValue.(string)
|
||||
}
|
||||
@ -141,11 +162,13 @@ func (c *ContainerImage) RegistryLogin(context context.Context) (token string, e
|
||||
func (c *ContainerImage) RegistryAuth() (string, error) {
|
||||
if authConfig, err := c.RegistryAuthConfig(); err == nil {
|
||||
if encodedJSON, jsonErr := json.Marshal(authConfig); jsonErr == nil {
|
||||
slog.Info("ContainerImage.RegistryAuth()", "auth", authConfig, "encoded", encodedJSON, "error", jsonErr)
|
||||
return base64.URLEncoding.EncodeToString(encodedJSON), nil
|
||||
} else {
|
||||
return "", jsonErr
|
||||
}
|
||||
} else {
|
||||
slog.Info("ContainerImage.RegistryAuth()", "error", err)
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
@ -526,6 +549,38 @@ func JXPath() (jxPath folio.URI, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (c *ContainerImage) UnmarshalOutput() (err error) {
|
||||
var containerErr ContainerError
|
||||
var jsonBody string = c.outputWriter.String()
|
||||
|
||||
slog.Info("ContainerImage.UnmarshalOutput()", "json", jsonBody, "error", err)
|
||||
for _, v := range strings.Split(jsonBody, "\r\n") {
|
||||
var containerLog ContainerLog
|
||||
|
||||
outputDecoder := codec.NewJSONStringDecoder(v)
|
||||
if decodeErr := outputDecoder.Decode(&containerLog); decodeErr != nil {
|
||||
if decodeErr == io.EOF {
|
||||
break
|
||||
}
|
||||
slog.Info("ContainerImage.UnmarshalOutput()", "value", v, "error", decodeErr)
|
||||
err = decodeErr
|
||||
}
|
||||
if containerLog.ContainerLogStream != nil || containerLog.ContainerLogStatus != nil {
|
||||
c.Output = append(c.Output, containerLog)
|
||||
}
|
||||
if containerLog.ContainerError != nil {
|
||||
containerErr = *containerLog.ContainerError
|
||||
c.Output = append(c.Output, containerLog)
|
||||
}
|
||||
slog.Info("ContainerImage.UnmarshalOutput()", "value", v, "error", err)
|
||||
}
|
||||
|
||||
if len(containerErr.Error) > 0 {
|
||||
return fmt.Errorf("%s", containerErr.Error)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// The contextref can be a tar file or a directory or maybe a loaded document
|
||||
func (c *ContainerImage) Create(ctx context.Context) (err error) {
|
||||
dockerfileURI := c.DockerfileRef.Parse()
|
||||
@ -580,13 +635,18 @@ func (c *ContainerImage) Create(ctx context.Context) (err error) {
|
||||
}
|
||||
|
||||
defer buildResponse.Body.Close()
|
||||
if output, outputErr := io.ReadAll(buildResponse.Body); outputErr != nil {
|
||||
slog.Info("ContainerImage.Create() - ImageBuild()", "output", output, "error", outputErr)
|
||||
return fmt.Errorf("%w %s %s", outputErr, c.Type(), c.Name)
|
||||
copyBuffer := make([]byte, 32 * 1024)
|
||||
if _, err = io.CopyBuffer(&c.outputWriter, buildResponse.Body, copyBuffer); err != nil {
|
||||
slog.Info("ContainerImage.Create() - ImageBuild()", "error", err)
|
||||
return fmt.Errorf("%w %s %s", err, c.Type(), c.Name)
|
||||
} else {
|
||||
slog.Info("ContainerImage.Create() - ImageBuild()", "output", output, "error", outputErr)
|
||||
if err = c.UnmarshalOutput(); err != nil {
|
||||
return
|
||||
}
|
||||
/*
|
||||
slog.Info("ContainerImage.Create() - ImageBuild()", "error", err)
|
||||
var containerErr ContainerError
|
||||
for _, jsonBody := range strings.Split(string(output), "\r\n") {
|
||||
for _, jsonBody := range strings.Split(string(c.outputWriter.String()), "\r\n") {
|
||||
decoder := codec.NewJSONStringDecoder(jsonBody)
|
||||
decodeErr := decoder.Decode(&containerErr)
|
||||
slog.Info("ContainerImage.Create() - ImageBuild()", "output", jsonBody, "error", containerErr, "decodeErr", decodeErr)
|
||||
@ -594,11 +654,14 @@ func (c *ContainerImage) Create(ctx context.Context) (err error) {
|
||||
return fmt.Errorf("%s", containerErr.Error)
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
if c.PushImage {
|
||||
err = c.Push(ctx)
|
||||
slog.Info("ContainerImage.Create() - Push()", "error", err)
|
||||
}
|
||||
err = c.UnmarshalOutput()
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -628,7 +691,8 @@ func (c *ContainerImage) Push(ctx context.Context) (err error) {
|
||||
defer response.Close()
|
||||
|
||||
copyBuffer := make([]byte, 32 * 1024)
|
||||
_, err = io.CopyBuffer(&c.Output, response, copyBuffer)
|
||||
_, err = io.CopyBuffer(&c.outputWriter, response, copyBuffer)
|
||||
//c.Output = c.outputWriter.String()
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -25,6 +25,11 @@ _ "net/http/httptest"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type MockConfigValueGetter func(key string) (any, error)
|
||||
func (m MockConfigValueGetter) GetValue(key string) (any, error) {
|
||||
return m(key)
|
||||
}
|
||||
|
||||
func TestNewContainerImageResource(t *testing.T) {
|
||||
c := NewContainerImage(&mocks.MockContainerClient{})
|
||||
assert.NotNil(t, c)
|
||||
@ -147,11 +152,24 @@ func TestCreateContainerImagePush(t *testing.T) {
|
||||
assert.Nil(t, e)
|
||||
assert.Equal(t, "testcontainerimage", c.Name)
|
||||
|
||||
c.UseConfig(MockConfigValueGetter(func(key string) (any, error) {
|
||||
switch key {
|
||||
case "repo_password":
|
||||
return "bar", nil
|
||||
case "repo_username":
|
||||
return "foo", nil
|
||||
case "repo_server":
|
||||
return "", nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("%w: %s", data.ErrUnknownConfigurationKey, key)
|
||||
}))
|
||||
|
||||
assert.Nil(t, stater.Trigger("create"))
|
||||
|
||||
assert.Nil(t, c.Push(context.Background()))
|
||||
assert.True(t, c.PushImage)
|
||||
assert.Equal(t, "foo", c.Output.String())
|
||||
// assert.Equal(t, "foo", c.Output)
|
||||
}
|
||||
|
||||
func TestContainerImageContextDocument(t *testing.T) {
|
||||
@ -226,3 +244,103 @@ func TestContainerError(t *testing.T) {
|
||||
assert.Nil(t, decoder.Decode(&err))
|
||||
assert.Equal(t, expected, err)
|
||||
}
|
||||
|
||||
func TestContainerLogUnmarshal(t *testing.T) {
|
||||
/*
|
||||
m := &mocks.MockContainerClient{
|
||||
InjectImageBuild: func(ctx context.Context, buildContext io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
|
||||
return types.ImageBuildResponse{Body: io.NopCloser(strings.NewReader("image built")) }, nil
|
||||
},
|
||||
}
|
||||
|
||||
c := NewContainerImage(m)
|
||||
assert.NotNil(t, c)
|
||||
*/
|
||||
|
||||
buildOutput := `"{\"stream\":\"Step 1/6 : ARG DIST\"}\r\n{\"stream\":\"\\n\"}\r\n{\"stream\":\"Step 2/6 : FROM golang:${DIST}\"}\r\n{\"stream\":\"\\n\"}\r\n{\"errorDetail\":{\"message\":\"invalid reference format\"},\"error\":\"invalid reference format\"}\r\n"`
|
||||
unqBuildOutput, buildOutputErr := strconv.Unquote(buildOutput)
|
||||
assert.Nil(t, buildOutputErr)
|
||||
|
||||
for _, v := range strings.Split(unqBuildOutput, "\r\n") {
|
||||
var clog ContainerLog
|
||||
|
||||
outputDecoder := codec.NewJSONStringDecoder(v)
|
||||
err := outputDecoder.Decode(&clog)
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
|
||||
if clog.ContainerLogStream != nil {
|
||||
assert.Greater(t, len(clog.ContainerLogStream.Stream), 0)
|
||||
}
|
||||
}
|
||||
|
||||
//assert.Equal(t, "Step 1/6 : ARG DIST", clog[0].ContainerLogStream.Stream)
|
||||
}
|
||||
|
||||
func TestContainerImageRegistryAuthConfig(t *testing.T) {
|
||||
|
||||
m := &mocks.MockContainerClient{
|
||||
InjectImageBuild: func(ctx context.Context, buildContext io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
|
||||
return types.ImageBuildResponse{Body: io.NopCloser(strings.NewReader("image built")) }, nil
|
||||
},
|
||||
}
|
||||
|
||||
c := NewContainerImage(m)
|
||||
assert.NotNil(t, c)
|
||||
|
||||
c.UseConfig(MockConfigValueGetter(func(key string) (any, error) {
|
||||
switch key {
|
||||
case "repo_password":
|
||||
return "bar", nil
|
||||
case "repo_username":
|
||||
return "foo", nil
|
||||
case "repo_server":
|
||||
return "", nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("%w: %s", data.ErrUnknownConfigurationKey, key)
|
||||
}))
|
||||
|
||||
authConfig, err := c.RegistryAuthConfig()
|
||||
|
||||
assert.NotNil(t, authConfig)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "bar", authConfig.Password)
|
||||
assert.Equal(t, "foo", authConfig.Username)
|
||||
}
|
||||
|
||||
func TestContainerImageRegistryAuth(t *testing.T) {
|
||||
|
||||
m := &mocks.MockContainerClient{
|
||||
InjectImageBuild: func(ctx context.Context, buildContext io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
|
||||
return types.ImageBuildResponse{Body: io.NopCloser(strings.NewReader("image built")) }, nil
|
||||
},
|
||||
}
|
||||
|
||||
c := NewContainerImage(m)
|
||||
assert.NotNil(t, c)
|
||||
|
||||
c.UseConfig(MockConfigValueGetter(func(key string) (any, error) {
|
||||
switch key {
|
||||
case "repo_password":
|
||||
return "bar", nil
|
||||
case "repo_username":
|
||||
return "foo", nil
|
||||
case "repo_server":
|
||||
return "", nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("%w: %s", data.ErrUnknownConfigurationKey, key)
|
||||
}))
|
||||
|
||||
auth, err := c.RegistryAuth()
|
||||
|
||||
assert.NotNil(t, auth)
|
||||
assert.Nil(t, err)
|
||||
assert.Greater(t, len(auth), 1)
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -45,6 +45,8 @@ var (
|
||||
ErrRpmPackageInstalled error = errors.New("is already installed")
|
||||
)
|
||||
|
||||
var SupportedPackageTypes []PackageType = []PackageType{PackageTypeApk, PackageTypeApt, PackageTypeDeb, PackageTypeDnf, PackageTypeRpm, PackageTypePip, PackageTypeYum}
|
||||
|
||||
var SystemPackageType PackageType = FindSystemPackageType()
|
||||
|
||||
type Package struct {
|
||||
@ -76,7 +78,7 @@ func init() {
|
||||
}
|
||||
|
||||
func FindSystemPackageType() PackageType {
|
||||
for _, packageType := range []PackageType{PackageTypeApk, PackageTypeApt, PackageTypeDeb, PackageTypeDnf, PackageTypeRpm, PackageTypePip, PackageTypeYum} {
|
||||
for _, packageType := range SupportedPackageTypes {
|
||||
c := packageType.NewReadCommand()
|
||||
if c.Exists() {
|
||||
return packageType
|
||||
@ -497,15 +499,17 @@ func NewApkReadCommand() *command.Command {
|
||||
}
|
||||
c.Extractor = func(out []byte, target any) error {
|
||||
p := target.(*Package)
|
||||
pkg := strings.Split(string(out), "-")
|
||||
pkg := strings.Split(strings.TrimSpace(string(out)), "-")
|
||||
numberOfFields := len(pkg)
|
||||
packageName := strings.Join(pkg[0:numberOfFields - 3], "-")
|
||||
packageName := strings.Join(pkg[0:numberOfFields - 2], "-")
|
||||
packageVersion := strings.Join(pkg[numberOfFields - 2:numberOfFields - 1], "-")
|
||||
|
||||
if packageName == p.Name {
|
||||
p.Name = packageName
|
||||
p.Version = packageVersion
|
||||
p.State = "present"
|
||||
} else {
|
||||
slog.Info("NewApkReadCommand().Extrctor() mismatch", "name", p.Name, "parsed", packageName)
|
||||
p.State = "absent"
|
||||
}
|
||||
return nil
|
||||
|
@ -32,6 +32,246 @@ func TestPackageApplyResourceTransformation(t *testing.T) {
|
||||
//assert.Equal(t, nil, e)
|
||||
}
|
||||
|
||||
func TestCommandExtractor(t *testing.T) {
|
||||
packages := map[PackageType][]struct{ Name string; Version string; Input string } {
|
||||
PackageTypeApk: []struct{ Name string; Version string; Input string }{
|
||||
/*
|
||||
{ Name: "alpine-baselayout", Version: "3.6.5-r0", Input: `alpine-baselayout-3.6.5-r0 x86_64 {alpine-baselayout} (GPL-2.0-only) [installed]` },
|
||||
{ Name: "alpine-baselayout-data", Version: "3.6.5-r0", Input: `alpine-baselayout-data-3.6.5-r0 x86_64 {alpine-baselayout} (GPL-2.0-only) [installed]` },
|
||||
{ Name: "alpine-keys", Version: "2.4-r1", Input: `alpine-keys-2.4-r1 x86_64 {alpine-keys} (MIT) [installed]` },
|
||||
{ Name: "apk-tools", Version: "2.14.4-r0", Input: `apk-tools-2.14.4-r0 x86_64 {apk-tools} (GPL-2.0-only) [installed]` },
|
||||
{ Name: "busybox", Version: "1.36.1-r29", Input: `busybox-1.36.1-r29 x86_64 {busybox} (GPL-2.0-only) [installed]` },
|
||||
{ Name: "busybox-binsh", Version: "1.36.1-r20", Input: `busybox-binsh-1.36.1-r29 x86_64 {busybox} (GPL-2.0-only) [installed]` },
|
||||
{ Name: "ca-certificates", Version: "20240705-r0", Input: `ca-certificates-20240705-r0 x86_64 {ca-certificates} (MPL-2.0 AND MIT) [installed]` },
|
||||
{ Name: "ca-certificates-bundle", Version: "20240705-r0", Input: `ca-certificates-bundle-20240705-r0 x86_64 {ca-certificates} (MPL-2.0 AND MIT) [installed]` },
|
||||
{ Name: "libcrypto3", Version: "3.3.1-r3", Input: `libcrypto3-3.3.1-r3 x86_64 {openssl} (Apache-2.0) [installed]` },
|
||||
{ Name: "libssl3", Version: "3.3.1-r3", Input: `libssl3-3.3.1-r3 x86_64 {openssl} (Apache-2.0) [installed]` },
|
||||
{ Name: "musl", Version: "1.2.5-r0", Input: `musl-1.2.5-r0 x86_64 {musl} (MIT) [installed]` },
|
||||
{ Name: "musl-utils", Version: "1.2.5-r0", Input: `musl-utils-1.2.5-r0 x86_64 {musl} (MIT AND BSD-2-Clause AND GPL-2.0-or-later) [installed]` },
|
||||
{ Name: "scanelf", Version: "1.3.7-r2", Input: `scanelf-1.3.7-r2 x86_64 {pax-utils} (GPL-2.0-only) [installed]` },
|
||||
{ Name: "ssl_client", Version: "1.36.1-r29", Input: `ssl_client-1.36.1-r29 x86_64 {busybox} (GPL-2.0-only) [installed]` },
|
||||
{ Name: "zlib", Version: "1.3.1-r1", Input: `zlib-1.3.1-r1 x86_64 {zlib} (Zlib) [installed]` },
|
||||
*/
|
||||
{ Name: "alpine-baselayout", Version: "3.6.5", Input: `alpine-baselayout-3.6.5-r0` },
|
||||
{ Name: "alpine-baselayout-data", Version: "3.6.5", Input: `alpine-baselayout-data-3.6.5-r0` },
|
||||
{ Name: "alpine-keys", Version: "2.4", Input: `alpine-keys-2.4-r1` },
|
||||
{ Name: "apk-tools", Version: "2.14.4", Input: `apk-tools-2.14.4-r0` },
|
||||
{ Name: "busybox", Version: "1.36.1", Input: `busybox-1.36.1-r29` },
|
||||
{ Name: "busybox-binsh", Version: "1.36.1", Input: `busybox-binsh-1.36.1-r29` },
|
||||
{ Name: "ca-certificates", Version: "20240705", Input: `ca-certificates-20240705-r0` },
|
||||
{ Name: "ca-certificates-bundle", Version: "20240705", Input: `ca-certificates-bundle-20240705-r0` },
|
||||
{ Name: "libcrypto3", Version: "3.3.1", Input: `libcrypto3-3.3.1-r3` },
|
||||
{ Name: "libssl3", Version: "3.3.1", Input: `libssl3-3.3.1-r3` },
|
||||
{ Name: "musl", Version: "1.2.5", Input: `musl-1.2.5-r0` },
|
||||
{ Name: "musl-utils", Version: "1.2.5", Input: `musl-utils-1.2.5-r0` },
|
||||
{ Name: "scanelf", Version: "1.3.7", Input: `scanelf-1.3.7-r2` },
|
||||
{ Name: "ssl_client", Version: "1.36.1", Input: `ssl_client-1.36.1-r29` },
|
||||
{ Name: "zlib", Version: "1.3.1", Input: `zlib-1.3.1-r1` },
|
||||
|
||||
},
|
||||
PackageTypeApt: []struct{ Name string; Version string; Input string }{
|
||||
{ Name: "bluez-meshd", Version: "5.64-0ubuntu1pop1~1674313994~22.04~579884f~dev", Input: `
|
||||
Package: bluez-meshd
|
||||
Status: install ok installed
|
||||
Priority: optional
|
||||
Section: admin
|
||||
Installed-Size: 937
|
||||
Maintainer: Ubuntu Bluetooth team <ubuntu-bluetooth@lists.ubuntu.com>
|
||||
Architecture: amd64
|
||||
Source: bluez
|
||||
Version: 5.64-0ubuntu1pop1~1674313994~22.04~579884f~dev
|
||||
Depends: libc6 (>= 2.34), libdbus-1-3 (>= 1.9.14), libglib2.0-0 (>= 2.28.0), libjson-c5 (>= 0.15), libreadline8 (>= 6.0)
|
||||
Conffiles:
|
||||
/etc/dbus-1/system.d/bluetooth-mesh.conf 95c2a66615065ad1195d5b647555c393
|
||||
Description: bluetooth mesh daemon
|
||||
The Bluetooth Mesh network is a new Bluetooth feature that extends "Bluetooth
|
||||
Low Energy (BLE)".
|
||||
.
|
||||
This package provides daemon (meshd) and tools that provide Bluetooth mesh
|
||||
functionality.
|
||||
.
|
||||
BlueZ is the official Linux Bluetooth protocol stack. It is an Open Source
|
||||
project distributed under GNU General Public License (GPL).
|
||||
Homepage: http://www.bluez.org
|
||||
Original-Maintainer: Debian Bluetooth Maintainers <pkg-bluetooth-maintainers@lists.alioth.debian.org>
|
||||
` },
|
||||
{ Name: "dconf-gsettings-backend", Version: "0.40.0-3", Input: `
|
||||
Package: dconf-gsettings-backend
|
||||
Status: install ok installed
|
||||
Priority: optional
|
||||
Section: libs
|
||||
Installed-Size: 83
|
||||
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
|
||||
Architecture: amd64
|
||||
Multi-Arch: same
|
||||
Source: dconf
|
||||
Version: 0.40.0-3
|
||||
Provides: gsettings-backend
|
||||
Depends: dconf-service (<< 0.40.0-3.1~), dconf-service (>= 0.40.0-3), libdconf1 (= 0.40.0-3), libc6 (>= 2.14), libglib2.0-0 (>= 2.55.2)
|
||||
Description: simple configuration storage system - GSettings back-end
|
||||
DConf is a low-level key/value database designed for storing desktop
|
||||
environment settings.
|
||||
.
|
||||
This package contains a back-end for GSettings. It is needed by
|
||||
applications accessing settings through GSettings to set custom values
|
||||
and listen for changes.
|
||||
Original-Maintainer: Debian GNOME Maintainers <pkg-gnome-maintainers@lists.alioth.debian.org>
|
||||
Homepage: https://wiki.gnome.org/Projects/dconf
|
||||
` },
|
||||
{ Name: "cheese-common", Version: "41.1-1build1", Input: `
|
||||
Package: cheese-common
|
||||
Status: install ok installed
|
||||
Priority: optional
|
||||
Section: gnome
|
||||
Installed-Size: 912
|
||||
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
|
||||
Architecture: all
|
||||
Multi-Arch: foreign
|
||||
Source: cheese
|
||||
Version: 41.1-1build1
|
||||
Depends: dconf-gsettings-backend | gsettings-backend
|
||||
Description: Common files for the Cheese tool to take pictures and videos
|
||||
A webcam application that supports image and video capture. Makes
|
||||
it easy to take photos and videos of you, your friends, pets or whatever
|
||||
you want. Allows you to apply fancy visual effects, fine-control image
|
||||
settings and has features such as Multi-Burst mode, Countdown timer
|
||||
for photos.
|
||||
.
|
||||
This package contains the common files and translations.
|
||||
Original-Maintainer: Debian GNOME Maintainers <pkg-gnome-maintainers@lists.alioth.debian.org>
|
||||
Homepage: https://wiki.gnome.org/Apps/Cheese
|
||||
` },
|
||||
{ Name: "fonts-lohit-deva", Version: "2.95.4-4", Input: `
|
||||
Package: fonts-lohit-deva
|
||||
Status: install ok installed
|
||||
Priority: optional
|
||||
Section: fonts
|
||||
Installed-Size: 193
|
||||
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
|
||||
Architecture: all
|
||||
Multi-Arch: foreign
|
||||
Version: 2.95.4-4
|
||||
Replaces: ttf-devanagari-fonts (<= 1:0.5.12)
|
||||
Breaks: ttf-devanagari-fonts (<= 1:0.5.12)
|
||||
Conffiles:
|
||||
/etc/fonts/conf.avail/59-lohit-devanagari.conf 26750c27821421cef15176c5d6eb490e
|
||||
/etc/fonts/conf.avail/66-lohit-devanagari.conf dfac9388b18ece1d53fed86785070f55
|
||||
Description: Lohit TrueType font for Devanagari script
|
||||
This package provides Lohit TrueType font for Devanagari script which
|
||||
is used for writing Hindi, Kashmiri, Konkani, Marathi, Maithili, Nepali,
|
||||
Sanskrit, and Sindhi languages.
|
||||
Original-Maintainer: Debian Fonts Task Force <debian-fonts@lists.debian.org>
|
||||
Homepage: https://pagure.io/lohit
|
||||
` },
|
||||
{ Name: "zstd", Version: "1.4.8+dfsg-3build1", Input: `
|
||||
Package: zstd
|
||||
Status: install ok installed
|
||||
Priority: optional
|
||||
Section: utils
|
||||
Installed-Size: 1655
|
||||
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
|
||||
Architecture: amd64
|
||||
Source: libzstd
|
||||
Version: 1.4.8+dfsg-3build1
|
||||
Depends: libc6 (>= 2.34), libgcc-s1 (>= 3.3.1), liblz4-1 (>= 0.0~r127), liblzma5 (>= 5.1.1alpha+20120614), libstdc++6 (>= 12), zlib1g (>= 1:1.1.4)
|
||||
Description: fast lossless compression algorithm -- CLI tool
|
||||
Zstd, short for Zstandard, is a fast lossless compression algorithm, targeting
|
||||
real-time compression scenarios at zlib-level compression ratio.
|
||||
.
|
||||
This package contains the CLI program implementing zstd.
|
||||
Homepage: https://github.com/facebook/zstd
|
||||
Original-Maintainer: Debian Med Packaging Team <debian-med-packaging@lists.alioth.debian.org>
|
||||
` },
|
||||
},
|
||||
PackageTypeDnf: []struct{ Name string; Version string; Input string }{
|
||||
{ Name: "man-pages-zh-CN", Version: "1.6.3.6-9.fc40", Input: `
|
||||
man-pages-zh-CN.noarch 1.6.3.6-9.fc40 @fedora` },
|
||||
{ Name: "memstrack", Version: "0.2.5-4.fc40", Input: `
|
||||
memstrack.x86_64 0.2.5-4.fc40 @fedora` },
|
||||
{ Name: "mercurial", Version: "6.7.4-3.fc40", Input: `
|
||||
mercurial.x86_64 6.7.4-3.fc40 @updates` },
|
||||
{ Name: "mesa-dri-drivers", Version: "24.1.7-1.fc40", Input: `
|
||||
mesa-dri-drivers.x86_64 24.1.7-1.fc40 @updates` },
|
||||
{ Name: "mesa-filesystem", Version: "24.1.7-1.fc40", Input: `
|
||||
mesa-filesystem.x86_64 24.1.7-1.fc40 @updates` },
|
||||
{ Name: "mesa-libEGL", Version: "24.1.7-1.fc40", Input: `
|
||||
mesa-libEGL.x86_64 24.1.7-1.fc40 @updates` },
|
||||
{ Name: "mesa-libGL", Version: "24.1.7-1.fc40", Input: `
|
||||
mesa-libGL.x86_64 24.1.7-1.fc40 @updates` },
|
||||
{ Name: "mesa-libgbm", Version: "24.1.7-1.fc40", Input: `
|
||||
mesa-libgbm.x86_64 24.1.7-1.fc40 @updates` },
|
||||
{ Name: "mesa-libglapi", Version: "24.1.7-1.fc40", Input: `
|
||||
mesa-libglapi.x86_64 24.1.7-1.fc40 @updates` },
|
||||
{ Name: "mesa-va-drivers", Version: "24.1.7-1.fc40", Input: `
|
||||
mesa-va-drivers.x86_64 24.1.7-1.fc40 @updates` },
|
||||
{ Name: "mkfontscale", Version: "1.2.2-6.fc40", Input: `
|
||||
mkfontscale.x86_64 1.2.2-6.fc40 @fedora` },
|
||||
{ Name: "moby-engine", Version: "24.0.5-4.fc40", Input: `
|
||||
moby-engine.x86_64 24.0.5-4.fc40 @fedora` },
|
||||
{ Name: "mpdecimal", Version: "2.5.1-9.fc40", Input: `
|
||||
mpdecimal.x86_64 2.5.1-9.fc40 @2c98ee0d5281429683938d93eb2a9aa4` },
|
||||
{ Name: "mpfr", Version: "4.2.1-3.fc40", Input: `
|
||||
mpfr.x86_64 4.2.1-3.fc40 @2c98ee0d5281429683938d93eb2a9aa4` },
|
||||
{ Name: "mpg123-libs", Version: "1.31.3-4.fc40", Input: `
|
||||
mpg123-libs.x86_64 1.31.3-4.fc40 @fedora` },
|
||||
{ Name: "ncurses", Version: "6.4-12.20240127.fc40", Input: `
|
||||
ncurses.x86_64 6.4-12.20240127.fc40 @fedora` },
|
||||
{ Name: "ncurses-base", Version: "6.4-12.20240127.fc40", Input: `
|
||||
ncurses-base.noarch 6.4-12.20240127.fc40 @2c98ee0d5281429683938d93eb2a9aa4` },
|
||||
{ Name: "ncurses-libs", Version: "6.4-12.20240127.fc40", Input: `
|
||||
ncurses-libs.x86_64 6.4-12.20240127.fc40 @2c98ee0d5281429683938d93eb2a9aa4` },
|
||||
{ Name: "net-tools", Version: "2.0-0.69.20160912git.fc40", Input: `
|
||||
net-tools.x86_64 2.0-0.69.20160912git.fc40 @fedora` },
|
||||
{ Name: "nettle", Version: "3.9.1-6.fc40", Input: `
|
||||
nettle.x86_64 3.9.1-6.fc40 @2c98ee0d5281429683938d93eb2a9aa4` },
|
||||
{ Name: "nftables", Version: "1.0.9-3.fc40", Input: `
|
||||
nftables.x86_64 1:1.0.9-3.fc40 @fedora` },
|
||||
{ Name: "npth", Version: "1.7-1.fc40", Input: `
|
||||
npth.x86_64 1.7-1.fc40 @2c98ee0d5281429683938d93eb2a9aa4` },
|
||||
{ Name: "nspr", Version: "4.35.0-28.fc40", Input: `
|
||||
nspr.x86_64 4.35.0-28.fc40 @updates` },
|
||||
{ Name: "nss", Version: "3.103.0-1.fc40", Input: `
|
||||
nss.x86_64 3.103.0-1.fc40 @updates` },
|
||||
{ Name: "nss-softokn", Version: "3.103.0-1.fc40", Input: `
|
||||
nss-softokn.x86_64 3.103.0-1.fc40 @updates` },
|
||||
{ Name: "nss-softokn-freebl", Version: "3.103.0-1.fc40", Input: `
|
||||
nss-softokn-freebl.x86_64 3.103.0-1.fc40 @updates` },
|
||||
{ Name: "nss-sysinit", Version: "3.103.0-1.fc40", Input: `
|
||||
nss-sysinit.x86_64 3.103.0-1.fc40 @updates` },
|
||||
{ Name: "nss-util", Version: "3.103.0-1.fc40", Input: `
|
||||
nss-util.x86_64 3.103.0-1.fc40 @updates` },
|
||||
{ Name: "openjpeg2", Version: "2.5.2-1.fc40", Input: `
|
||||
openjpeg2.x86_64 2.5.2-1.fc40 @fedora` },
|
||||
{ Name: "openldap", Version: "2.6.7-1.fc40", Input: `
|
||||
openldap.x86_64 2.6.7-1.fc40 @2c98ee0d5281429683938d93eb2a9aa4` },
|
||||
{ Name: "openssh", Version: "9.6p1-1.fc40.4", Input: `
|
||||
openssh.x86_64 9.6p1-1.fc40.4 @updates` },
|
||||
{ Name: "openssh-clients", Version: "9.6p1-1.fc40.4", Input: `
|
||||
openssh-clients.x86_64 9.6p1-1.fc40.4 @updates` },
|
||||
{ Name: "openssl", Version: "3.2.2-3.fc40", Input: `
|
||||
openssl.x86_64 1:3.2.2-3.fc40 @updates` },
|
||||
{ Name: "openssl-libs", Version: "3.2.2-3.fc40", Input: `
|
||||
openssl-libs.x86_64 1:3.2.2-3.fc40 @updates` },
|
||||
{ Name: "opus", Version: "1.5.1-1.fc40", Input: `
|
||||
opus.x86_64 1.5.1-1.fc40 @fedora` },
|
||||
{ Name: "orc", Version: "0.4.39-1.fc40", Input: `
|
||||
orc.x86_64 0.4.39-1.fc40 @updates` },
|
||||
},
|
||||
}
|
||||
for _, pt := range SupportedPackageTypes {
|
||||
cmd := pt.NewReadCommand()
|
||||
for _, v := range packages[pt] {
|
||||
pkg := NewPackage()
|
||||
pkg.Name = v.Name
|
||||
assert.Nil(t, cmd.Extractor([]byte(v.Input), pkg))
|
||||
slog.Info("TestCommandExtractor()", "packagetype", pt, "name", pkg.Name, "package", pkg)
|
||||
assert.Equal(t, v.Name, pkg.Name)
|
||||
assert.Equal(t, v.Version, pkg.Version)
|
||||
assert.Equal(t, "present", pkg.State)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadPackage(t *testing.T) {
|
||||
decl := `
|
||||
name: vim
|
||||
|
Loading…
Reference in New Issue
Block a user