move SetResourceMapper to common
This commit is contained in:
parent
eaac8c8800
commit
24a18c3094
@ -9,6 +9,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"decl/internal/data"
|
"decl/internal/data"
|
||||||
"decl/internal/folio"
|
"decl/internal/folio"
|
||||||
|
_ "decl/internal/mapper"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"errors"
|
"errors"
|
||||||
)
|
)
|
||||||
@ -31,7 +32,7 @@ type Common struct {
|
|||||||
|
|
||||||
State string `json:"state,omitempty" yaml:"state,omitempty"`
|
State string `json:"state,omitempty" yaml:"state,omitempty"`
|
||||||
config data.ConfigurationValueGetter
|
config data.ConfigurationValueGetter
|
||||||
Resources data.ResourceMapper `json:"-" yaml:"-"`
|
Resources folio.ResourceMapper `json:"-" yaml:"-"`
|
||||||
Errors []error `json:"-" yaml:"-"`
|
Errors []error `json:"-" yaml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +54,7 @@ func (c *Common) ContentType() string {
|
|||||||
return c.exttype
|
return c.exttype
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Common) SetResourceMapper(resources data.ResourceMapper) {
|
func (c *Common) SetResourceMapper(resources folio.ResourceMapper) {
|
||||||
c.Resources = resources
|
c.Resources = resources
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,6 +159,7 @@ func (c *Common) IsResourceInconsistent() (result bool) {
|
|||||||
|
|
||||||
func (c *Common) AddError(err error) (error) {
|
func (c *Common) AddError(err error) (error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
slog.Info("Common.AddError()", "errors", c.Errors, "err", err)
|
||||||
c.Errors = append(c.Errors, err)
|
c.Errors = append(c.Errors, err)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
|
@ -32,15 +32,22 @@ _ "os/exec"
|
|||||||
"decl/internal/containerlog"
|
"decl/internal/containerlog"
|
||||||
"bytes"
|
"bytes"
|
||||||
_ "encoding/base64"
|
_ "encoding/base64"
|
||||||
|
"time"
|
||||||
|
"errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ContainerTypeName TypeName = "container"
|
ContainerTypeName TypeName = "container"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrContainerWaitTimeOut = errors.New("Container wait timed out waiting for state")
|
||||||
|
)
|
||||||
|
|
||||||
type ContainerClient interface {
|
type ContainerClient interface {
|
||||||
ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, platform *ocispec.Platform, containerName string) (container.CreateResponse, error)
|
ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, platform *ocispec.Platform, containerName string) (container.CreateResponse, error)
|
||||||
ContainerStart(ctx context.Context, containerID string, options container.StartOptions) error
|
ContainerStart(ctx context.Context, containerID string, options container.StartOptions) error
|
||||||
|
ContainerRestart(ctx context.Context, containerID string, options container.StopOptions) error
|
||||||
ContainerList(context.Context, container.ListOptions) ([]types.Container, error)
|
ContainerList(context.Context, container.ListOptions) ([]types.Container, error)
|
||||||
ContainerInspect(context.Context, string) (types.ContainerJSON, error)
|
ContainerInspect(context.Context, string) (types.ContainerJSON, error)
|
||||||
ContainerRemove(context.Context, string, container.RemoveOptions) error
|
ContainerRemove(context.Context, string, container.RemoveOptions) error
|
||||||
@ -91,7 +98,6 @@ type Container struct {
|
|||||||
Stderr string `json:"stderr,omitempty" yaml:"stderr,omitempty"`
|
Stderr string `json:"stderr,omitempty" yaml:"stderr,omitempty"`
|
||||||
|
|
||||||
apiClient ContainerClient
|
apiClient ContainerClient
|
||||||
Resources data.ResourceMapper `json:"-" yaml:"-"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -137,10 +143,6 @@ func (c *Container) SetParsedURI(u data.URIParser) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Container) SetResourceMapper(resources data.ResourceMapper) {
|
|
||||||
c.Resources = resources
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Container) Clone() data.Resource {
|
func (c *Container) Clone() data.Resource {
|
||||||
return &Container {
|
return &Container {
|
||||||
Id: c.Id,
|
Id: c.Id,
|
||||||
@ -233,7 +235,6 @@ func (c *Container) Notify(m *machine.EventMessage) {
|
|||||||
panic(createErr)
|
panic(createErr)
|
||||||
}
|
}
|
||||||
case "start_delete":
|
case "start_delete":
|
||||||
slog.Info("Container.Notify()", "event", "start_delete")
|
|
||||||
if deleteErr := c.Delete(ctx); deleteErr == nil {
|
if deleteErr := c.Delete(ctx); deleteErr == nil {
|
||||||
if triggerErr := c.StateMachine().Trigger("deleted"); triggerErr == nil {
|
if triggerErr := c.StateMachine().Trigger("deleted"); triggerErr == nil {
|
||||||
return
|
return
|
||||||
@ -245,6 +246,26 @@ func (c *Container) Notify(m *machine.EventMessage) {
|
|||||||
c.Common.State = "present"
|
c.Common.State = "present"
|
||||||
panic(deleteErr)
|
panic(deleteErr)
|
||||||
}
|
}
|
||||||
|
case "restarting":
|
||||||
|
if restartErr := c.Restart(ctx); restartErr == nil {
|
||||||
|
if triggerErr := c.StateMachine().Trigger("restarted"); triggerErr == nil {
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
_ = c.AddError(triggerErr)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_ = c.AddError(restartErr)
|
||||||
|
if c.IsResourceInconsistent() {
|
||||||
|
if triggerErr := c.StateMachine().Trigger("restart-failed"); triggerErr == nil {
|
||||||
|
panic(restartErr)
|
||||||
|
} else {
|
||||||
|
_ = c.AddError(triggerErr)
|
||||||
|
panic(fmt.Errorf("%w - %w", restartErr, triggerErr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ = c.StateMachine().Trigger("notexists")
|
||||||
|
panic(restartErr)
|
||||||
|
}
|
||||||
case "present", "created", "read":
|
case "present", "created", "read":
|
||||||
c.Common.State = "present"
|
c.Common.State = "present"
|
||||||
case "running":
|
case "running":
|
||||||
@ -475,10 +496,10 @@ func (c *Container) Read(ctx context.Context) ([]byte, error) {
|
|||||||
|
|
||||||
func (c *Container) Inspect(ctx context.Context, containerID string) error {
|
func (c *Container) Inspect(ctx context.Context, containerID string) error {
|
||||||
containerJSON, err := c.apiClient.ContainerInspect(ctx, containerID)
|
containerJSON, err := c.apiClient.ContainerInspect(ctx, containerID)
|
||||||
if client.IsErrNotFound(err) {
|
if client.IsErrNotFound(err) || containerJSON.State == nil {
|
||||||
c.Common.State = "absent"
|
c.Common.State = "absent"
|
||||||
} else {
|
} else {
|
||||||
c.Common.State = "present"
|
c.Common.State = containerJSON.State.Status
|
||||||
c.Id = containerJSON.ID
|
c.Id = containerJSON.ID
|
||||||
if c.Name == "" {
|
if c.Name == "" {
|
||||||
if containerJSON.Name[0] == '/' {
|
if containerJSON.Name[0] == '/' {
|
||||||
@ -583,3 +604,64 @@ func (c *Container) ResolveId(ctx context.Context) string {
|
|||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WaitCondition func(state *types.ContainerState) bool
|
||||||
|
func (c *Container) wait(ctx context.Context, untilstate WaitCondition) error {
|
||||||
|
statusCh := make(chan bool)
|
||||||
|
timeoutCtx, cancel := context.WithTimeout(ctx, 60 * time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
if containerJSON, err := c.apiClient.ContainerInspect(ctx, c.Id); err == nil {
|
||||||
|
statusCh <- untilstate(containerJSON.State)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-timeoutCtx.Done():
|
||||||
|
return ErrContainerWaitTimeOut
|
||||||
|
case <-statusCh:
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Container) Restart(ctx context.Context) (err error) {
|
||||||
|
if err = c.apiClient.ContainerRestart(ctx, c.Id, container.StopOptions{}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = c.wait(ctx, func(state *types.ContainerState) bool {
|
||||||
|
return state.Running
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
waitTimeout := 60 * time.Second
|
||||||
|
interval := 2 * time.Second
|
||||||
|
deadline := time.Now().Add(waitTimeout)
|
||||||
|
|
||||||
|
for {
|
||||||
|
if time.Now().After(deadline) {
|
||||||
|
panic("")
|
||||||
|
}
|
||||||
|
if state.Running {
|
||||||
|
if state.Health != nil {
|
||||||
|
fmt.Println("Health status:", state.Health.Status)
|
||||||
|
if state.Health.Status == "healthy" {
|
||||||
|
fmt.Println("Container is healthy and running.")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Println("Container is running (no health check defined).")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(interval)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -93,7 +93,6 @@ type ContainerImage struct {
|
|||||||
outputWriter strings.Builder `json:"-" yaml:"-"`
|
outputWriter strings.Builder `json:"-" yaml:"-"`
|
||||||
|
|
||||||
apiClient ContainerImageClient
|
apiClient ContainerImageClient
|
||||||
Resources data.ResourceMapper `json:"-" yaml:"-"`
|
|
||||||
contextDocument data.Document `json:"-" yaml:"-"`
|
contextDocument data.Document `json:"-" yaml:"-"`
|
||||||
ConverterTypes data.TypesRegistry[data.Converter] `json:"-" yaml:"-"`
|
ConverterTypes data.TypesRegistry[data.Converter] `json:"-" yaml:"-"`
|
||||||
|
|
||||||
@ -193,10 +192,6 @@ func (c *ContainerImage) NormalizePath() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ContainerImage) SetResourceMapper(resources data.ResourceMapper) {
|
|
||||||
c.Resources = resources
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ContainerImage) Clone() data.Resource {
|
func (c *ContainerImage) Clone() data.Resource {
|
||||||
return &ContainerImage {
|
return &ContainerImage {
|
||||||
Common: c.Common,
|
Common: c.Common,
|
||||||
|
@ -49,7 +49,6 @@ type ContainerNetwork struct {
|
|||||||
Created time.Time `json:"created" yaml:"created"`
|
Created time.Time `json:"created" yaml:"created"`
|
||||||
|
|
||||||
apiClient ContainerNetworkClient
|
apiClient ContainerNetworkClient
|
||||||
Resources data.ResourceMapper `json:"-" yaml:"-"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -92,10 +91,6 @@ func (n *ContainerNetwork) NormalizePath() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *ContainerNetwork) SetResourceMapper(resources data.ResourceMapper) {
|
|
||||||
n.Resources = resources
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *ContainerNetwork) Clone() data.Resource {
|
func (n *ContainerNetwork) Clone() data.Resource {
|
||||||
return &ContainerNetwork {
|
return &ContainerNetwork {
|
||||||
Common: n.Common.Clone(),
|
Common: n.Common.Clone(),
|
||||||
|
@ -34,8 +34,6 @@ type Exec struct {
|
|||||||
ReadTemplate *command.Command `yaml:"read,omitempty" json:"read,omitempty"`
|
ReadTemplate *command.Command `yaml:"read,omitempty" json:"read,omitempty"`
|
||||||
UpdateTemplate *command.Command `yaml:"update,omitempty" json:"update,omitempty"`
|
UpdateTemplate *command.Command `yaml:"update,omitempty" json:"update,omitempty"`
|
||||||
DeleteTemplate *command.Command `yaml:"delete,omitempty" json:"delete,omitempty"`
|
DeleteTemplate *command.Command `yaml:"delete,omitempty" json:"delete,omitempty"`
|
||||||
|
|
||||||
Resources data.ResourceMapper `yaml:"-" json:"-"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -63,10 +61,6 @@ func NewExec() *Exec {
|
|||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Exec) SetResourceMapper(resources data.ResourceMapper) {
|
|
||||||
x.Resources = resources
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Exec) Clone() data.Resource {
|
func (x *Exec) Clone() data.Resource {
|
||||||
return &Exec {
|
return &Exec {
|
||||||
Common: x.Common.Clone(),
|
Common: x.Common.Clone(),
|
||||||
|
@ -48,7 +48,6 @@ type Group struct {
|
|||||||
ReadCommand *command.Command `json:"-" yaml:"-"`
|
ReadCommand *command.Command `json:"-" yaml:"-"`
|
||||||
UpdateCommand *command.Command `json:"-" yaml:"-"`
|
UpdateCommand *command.Command `json:"-" yaml:"-"`
|
||||||
DeleteCommand *command.Command `json:"-" yaml:"-"`
|
DeleteCommand *command.Command `json:"-" yaml:"-"`
|
||||||
Resources data.ResourceMapper `json:"-" yaml:"-"`
|
|
||||||
groupStatus *user.Group `json:"-" yaml:"-"`
|
groupStatus *user.Group `json:"-" yaml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,10 +101,6 @@ func (g *Group) NormalizePath() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Group) SetResourceMapper(resources data.ResourceMapper) {
|
|
||||||
g.Resources = resources
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Group) Clone() data.Resource {
|
func (g *Group) Clone() data.Resource {
|
||||||
newg := &Group {
|
newg := &Group {
|
||||||
Common: g.Common,
|
Common: g.Common,
|
||||||
|
@ -91,7 +91,6 @@ type HTTP struct {
|
|||||||
LastModified time.Time `json:"lastmodified,omitempty" yaml:"lastmodified,omitempty"`
|
LastModified time.Time `json:"lastmodified,omitempty" yaml:"lastmodified,omitempty"`
|
||||||
Size int64 `yaml:"size,omitempty" json:"size,omitempty"`
|
Size int64 `yaml:"size,omitempty" json:"size,omitempty"`
|
||||||
SignatureValue string `yaml:"signature,omitempty" json:"signature,omitempty"`
|
SignatureValue string `yaml:"signature,omitempty" json:"signature,omitempty"`
|
||||||
Resources data.ResourceMapper `yaml:"-" json:"-"`
|
|
||||||
reader *transport.Reader `yaml:"-" json:"-"`
|
reader *transport.Reader `yaml:"-" json:"-"`
|
||||||
writer *transport.ReadWriter `yaml:"-" json:"-"`
|
writer *transport.ReadWriter `yaml:"-" json:"-"`
|
||||||
}
|
}
|
||||||
@ -127,10 +126,6 @@ func (h *HTTP) NormalizePath() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HTTP) SetResourceMapper(resources data.ResourceMapper) {
|
|
||||||
h.Resources = resources
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HTTP) Open() (err error) {
|
func (h *HTTP) Open() (err error) {
|
||||||
u := h.Common.parsedURI
|
u := h.Common.parsedURI
|
||||||
if u == nil {
|
if u == nil {
|
||||||
|
@ -136,8 +136,6 @@ type Iptable struct {
|
|||||||
ReadChainCommand *command.Command `yaml:"-" json:"-"`
|
ReadChainCommand *command.Command `yaml:"-" json:"-"`
|
||||||
UpdateCommand *command.Command `yaml:"-" json:"-"`
|
UpdateCommand *command.Command `yaml:"-" json:"-"`
|
||||||
DeleteCommand *command.Command `yaml:"-" json:"-"`
|
DeleteCommand *command.Command `yaml:"-" json:"-"`
|
||||||
|
|
||||||
Resources data.ResourceMapper `yaml:"-" json:"-"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -185,10 +183,6 @@ func (i *Iptable) Init(u data.URIParser) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Iptable) SetResourceMapper(resources data.ResourceMapper) {
|
|
||||||
i.Resources = resources
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *Iptable) Clone() data.Resource {
|
func (i *Iptable) Clone() data.Resource {
|
||||||
newIpt := &Iptable {
|
newIpt := &Iptable {
|
||||||
Common: i.Common,
|
Common: i.Common,
|
||||||
@ -286,13 +280,13 @@ func (i *Iptable) Notify(m *machine.EventMessage) {
|
|||||||
// Set the chain ID and update the mapped URI
|
// Set the chain ID and update the mapped URI
|
||||||
func (i *Iptable) SetId(id uint) {
|
func (i *Iptable) SetId(id uint) {
|
||||||
if i.Id != id {
|
if i.Id != id {
|
||||||
uri := i.URI()
|
uri := folio.URI(i.URI())
|
||||||
i.Id = id
|
i.Id = id
|
||||||
decl, ok := i.Resources.Get(uri)
|
decl, ok := i.Resources.Get(uri)
|
||||||
if ok {
|
if ok {
|
||||||
i.Resources.Delete(uri)
|
i.Resources.Delete(uri)
|
||||||
}
|
}
|
||||||
i.Resources.Set(i.URI(), decl)
|
i.Resources.Set(folio.URI(i.URI()), decl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ _ "syscall"
|
|||||||
"testing"
|
"testing"
|
||||||
_ "time"
|
_ "time"
|
||||||
"decl/internal/command"
|
"decl/internal/command"
|
||||||
"decl/internal/data"
|
"decl/internal/folio"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewIptableResource(t *testing.T) {
|
func TestNewIptableResource(t *testing.T) {
|
||||||
@ -167,7 +167,7 @@ func TestIptableRuleExtractorById(t *testing.T) {
|
|||||||
|
|
||||||
func TestIptableRuleExtractorByFlags(t *testing.T) {
|
func TestIptableRuleExtractorByFlags(t *testing.T) {
|
||||||
ipt := NewIptable()
|
ipt := NewIptable()
|
||||||
ipt.Resources = data.NewResourceMapper()
|
ipt.Resources = folio.NewResourceMapper()
|
||||||
assert.NotNil(t, ipt)
|
assert.NotNil(t, ipt)
|
||||||
ipt.Table = IptableName("filter")
|
ipt.Table = IptableName("filter")
|
||||||
ipt.Chain = IptableChain("FOO")
|
ipt.Chain = IptableChain("FOO")
|
||||||
|
@ -96,8 +96,6 @@ type NetworkRoute struct {
|
|||||||
ReadCommand *command.Command `yaml:"-" json:"-"`
|
ReadCommand *command.Command `yaml:"-" json:"-"`
|
||||||
UpdateCommand *command.Command `yaml:"-" json:"-"`
|
UpdateCommand *command.Command `yaml:"-" json:"-"`
|
||||||
DeleteCommand *command.Command `yaml:"-" json:"-"`
|
DeleteCommand *command.Command `yaml:"-" json:"-"`
|
||||||
|
|
||||||
Resources data.ResourceMapper `json:"-" yaml:"-"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNetworkRoute() *NetworkRoute {
|
func NewNetworkRoute() *NetworkRoute {
|
||||||
@ -119,10 +117,6 @@ func (n *NetworkRoute) NormalizePath() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NetworkRoute) SetResourceMapper(resources data.ResourceMapper) {
|
|
||||||
n.Resources = resources
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NetworkRoute) Clone() data.Resource {
|
func (n *NetworkRoute) Clone() data.Resource {
|
||||||
newn := &NetworkRoute {
|
newn := &NetworkRoute {
|
||||||
Common: n.Common,
|
Common: n.Common,
|
||||||
|
@ -28,6 +28,7 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
ErrOpenPGPEncryptionFailure error = errors.New("OpenPGP encryption failure")
|
ErrOpenPGPEncryptionFailure error = errors.New("OpenPGP encryption failure")
|
||||||
|
ErrOpenPGPDecryptionFailure error = errors.New("OpenPGP decryption failure")
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -48,14 +49,14 @@ func init() {
|
|||||||
|
|
||||||
|
|
||||||
type OpenPGPKeyRing struct {
|
type OpenPGPKeyRing struct {
|
||||||
*Common `json:",inline" yaml:",inline"`
|
*Common `json:",inline" yaml:",inline"`
|
||||||
stater machine.Stater `json:"-" yaml:"-"`
|
stater machine.Stater `json:"-" yaml:"-"`
|
||||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||||
Comment string `json:"comment,omitempty" yaml:"comment,omitempty"`
|
Comment string `json:"comment,omitempty" yaml:"comment,omitempty"`
|
||||||
Email string `json:"email,omitempty" yaml:"email,omitempty"`
|
Email string `json:"email,omitempty" yaml:"email,omitempty"`
|
||||||
KeyRing string `json:"keyring,omitempty" yaml:"keyring,omitempty"`
|
KeyRing string `json:"keyring,omitempty" yaml:"keyring,omitempty"`
|
||||||
Bits int `json:"bits" yaml:"bits"`
|
Bits int `json:"bits" yaml:"bits"`
|
||||||
KeyRingRef folio.ResourceReference `json:"keyringref,omitempty" yaml:"keyringref,omitempty"`
|
KeyRingRef folio.ResourceReference `json:"keyringref,omitempty" yaml:"keyringref,omitempty"`
|
||||||
|
|
||||||
entityList openpgp.EntityList
|
entityList openpgp.EntityList
|
||||||
}
|
}
|
||||||
@ -65,6 +66,7 @@ func NewOpenPGPKeyRing() (o *OpenPGPKeyRing) {
|
|||||||
Common: NewCommon(OpenPGPKeyRingTypeName, false),
|
Common: NewCommon(OpenPGPKeyRingTypeName, false),
|
||||||
Bits: 2048,
|
Bits: 2048,
|
||||||
}
|
}
|
||||||
|
o.Common.NormalizePath = o.NormalizePath
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +83,6 @@ func (o *OpenPGPKeyRing) NormalizePath() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (o *OpenPGPKeyRing) Validate() (err error) {
|
func (o *OpenPGPKeyRing) Validate() (err error) {
|
||||||
var keyringJson []byte
|
var keyringJson []byte
|
||||||
if keyringJson, err = o.JSON(); err == nil {
|
if keyringJson, err = o.JSON(); err == nil {
|
||||||
@ -124,8 +125,29 @@ func (o *OpenPGPKeyRing) EncryptPrivateKey(entity *openpgp.Entity) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *OpenPGPKeyRing) DecryptPrivateKey(entity *openpgp.Entity) error {
|
||||||
|
if o.config != nil && entity.PrivateKey != nil {
|
||||||
|
passphraseConfig, _ := o.config.GetValue("passphrase")
|
||||||
|
passphrase := []byte(passphraseConfig.(string))
|
||||||
|
if len(passphrase) > 0 {
|
||||||
|
if decryptErr := entity.PrivateKey.Decrypt(passphrase); decryptErr != nil {
|
||||||
|
return fmt.Errorf("%w private key: %w", ErrOpenPGPDecryptionFailure, decryptErr)
|
||||||
|
}
|
||||||
|
for _, subkey := range entity.Subkeys {
|
||||||
|
if decryptErr := subkey.PrivateKey.Encrypt(passphrase); decryptErr != nil {
|
||||||
|
return fmt.Errorf("%w subkey (private key): %w", ErrOpenPGPDecryptionFailure, decryptErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (o *OpenPGPKeyRing) Create(ctx context.Context) (err error) {
|
func (o *OpenPGPKeyRing) Create(ctx context.Context) (err error) {
|
||||||
var entity *openpgp.Entity
|
var entity *openpgp.Entity
|
||||||
|
var keyRingFileStream io.WriteCloser
|
||||||
|
var keyRingBuffer bytes.Buffer
|
||||||
|
|
||||||
cfg := o.Config()
|
cfg := o.Config()
|
||||||
entity, err = openpgp.NewEntity(o.Name, o.Comment, o.Email, cfg)
|
entity, err = openpgp.NewEntity(o.Name, o.Comment, o.Email, cfg)
|
||||||
o.entityList = append(o.entityList, entity)
|
o.entityList = append(o.entityList, entity)
|
||||||
@ -142,25 +164,37 @@ func (o *OpenPGPKeyRing) Create(ctx context.Context) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(o.KeyRing) == 0 {
|
if len(o.KeyRing) == 0 { // XXX this should probably always overwrite the value of KeyRing
|
||||||
var keyringBuffer bytes.Buffer
|
if privateKeyWriter, err := armor.Encode(&keyRingBuffer, openpgp.PrivateKeyType, nil); err == nil {
|
||||||
if publicKeyWriter, err := armor.Encode(&keyringBuffer, openpgp.PublicKeyType, nil); err == nil {
|
|
||||||
if err = entity.Serialize(publicKeyWriter); err == nil {
|
|
||||||
|
|
||||||
}
|
|
||||||
publicKeyWriter.Close()
|
|
||||||
}
|
|
||||||
keyringBuffer.WriteString("\n")
|
|
||||||
if privateKeyWriter, err := armor.Encode(&keyringBuffer, openpgp.PrivateKeyType, nil); err == nil {
|
|
||||||
if err = entity.SerializePrivateWithoutSigning(privateKeyWriter, nil); err == nil {
|
if err = entity.SerializePrivateWithoutSigning(privateKeyWriter, nil); err == nil {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
slog.Error("Failed writing privatekey", "err", err)
|
||||||
}
|
}
|
||||||
privateKeyWriter.Close()
|
privateKeyWriter.Close()
|
||||||
|
keyRingBuffer.WriteString("\n")
|
||||||
|
}
|
||||||
|
if publicKeyWriter, err := armor.Encode(&keyRingBuffer, openpgp.PublicKeyType, nil); err == nil {
|
||||||
|
if err = entity.Serialize(publicKeyWriter); err == nil {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
slog.Error("Failed writing public key", "err", err)
|
||||||
|
}
|
||||||
|
publicKeyWriter.Close()
|
||||||
|
keyRingBuffer.WriteString("\n")
|
||||||
}
|
}
|
||||||
keyringBuffer.WriteString("\n")
|
|
||||||
|
|
||||||
o.KeyRing = keyringBuffer.String()
|
o.KeyRing = keyRingBuffer.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(o.KeyRingRef) > 0 {
|
||||||
|
keyRingFileStream, _ = o.KeyRingRef.Lookup(o.Resources).ContentWriterStream()
|
||||||
|
defer keyRingFileStream.Close()
|
||||||
|
if _, writeErr := keyRingFileStream.Write([]byte(o.KeyRing)); writeErr != nil {
|
||||||
|
err = writeErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,6 +367,8 @@ func (o *OpenPGPKeyRing) ResolveId(ctx context.Context) string {
|
|||||||
if e := o.NormalizePath(); e != nil {
|
if e := o.NormalizePath(); e != nil {
|
||||||
panic(e)
|
panic(e)
|
||||||
}
|
}
|
||||||
|
o.GetIdentityFromKeyRing()
|
||||||
|
o.Common.Path = fmt.Sprintf("%s/%s/%s", o.Name, o.Comment, o.Email)
|
||||||
return o.Common.Path
|
return o.Common.Path
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -363,6 +399,33 @@ func (o *OpenPGPKeyRing) ReadStat() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *OpenPGPKeyRing) GetIdentityFromKeyRing() error {
|
||||||
|
if len(o.KeyRing) > 0 {
|
||||||
|
if keyring, err := openpgp.ReadArmoredKeyRing(bytes.NewReader([]byte(o.KeyRing))); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
for _, entity := range keyring {
|
||||||
|
for identityName, identity := range entity.Identities {
|
||||||
|
slog.Info("OpenPGPKeyRing.GetIdentityFromKeyRing()", "identity", identityName)
|
||||||
|
if identity.UserId != nil {
|
||||||
|
if len(identity.UserId.Name) > 0 {
|
||||||
|
o.Name = identity.UserId.Name
|
||||||
|
}
|
||||||
|
if len(identity.UserId.Comment) > 0 {
|
||||||
|
o.Comment = identity.UserId.Comment
|
||||||
|
}
|
||||||
|
if len(identity.UserId.Email) > 0 {
|
||||||
|
o.Email = identity.UserId.Email
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (o *OpenPGPKeyRing) Read(ctx context.Context) (yamlData []byte, err error) {
|
func (o *OpenPGPKeyRing) Read(ctx context.Context) (yamlData []byte, err error) {
|
||||||
var keyringReader io.ReadCloser
|
var keyringReader io.ReadCloser
|
||||||
statErr := o.ReadStat()
|
statErr := o.ReadStat()
|
||||||
@ -371,11 +434,19 @@ func (o *OpenPGPKeyRing) Read(ctx context.Context) (yamlData []byte, err error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if keyringReader, err = o.GetContent(nil); err == nil {
|
if keyringReader, err = o.GetContent(nil); err == nil {
|
||||||
|
defer keyringReader.Close()
|
||||||
if krData, krErr := io.ReadAll(keyringReader); krErr == nil {
|
if krData, krErr := io.ReadAll(keyringReader); krErr == nil {
|
||||||
o.KeyRing = string(krData)
|
o.KeyRing = string(krData)
|
||||||
o.entityList, err = openpgp.ReadArmoredKeyRing(strings.NewReader(o.KeyRing))
|
o.entityList, err = openpgp.ReadArmoredKeyRing(strings.NewReader(o.KeyRing))
|
||||||
} else {
|
} else {
|
||||||
err = krErr
|
return nil, fmt.Errorf("%w - %w: %s", ErrResourceStateAbsent, krErr, o.Path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
o.GetIdentityFromKeyRing()
|
||||||
|
|
||||||
|
for i := range o.entityList {
|
||||||
|
if decryptErr := o.DecryptPrivateKey(o.entityList[i]); decryptErr != nil {
|
||||||
|
return nil, fmt.Errorf("%w - %w: %s", ErrResourceStateAbsent, decryptErr, o.Path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,19 +479,24 @@ func (o *OpenPGPKeyRing) readThru() (contentReader io.ReadCloser, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *OpenPGPKeyRing) URI() string { return string(o.Common.URI()) }
|
func (o *OpenPGPKeyRing) URI() string {
|
||||||
|
return fmt.Sprintf("%s://%s/%s/%s", o.Type(), o.Name, o.Comment, o.Email)
|
||||||
|
}
|
||||||
|
|
||||||
func (o *OpenPGPKeyRing) Type() string { return "openpgp-keyring" }
|
func (o *OpenPGPKeyRing) Type() string { return string(OpenPGPKeyRingTypeName) }
|
||||||
|
|
||||||
func (o *OpenPGPKeyRing) ContentReaderStream() (*transport.Reader, error) {
|
func (o *OpenPGPKeyRing) ContentReaderStream() (*transport.Reader, error) {
|
||||||
if len(o.KeyRing) == 0 && ! o.KeyRingRef.IsEmpty() {
|
//if len(o.KeyRing) == 0 && ! o.KeyRingRef.IsEmpty() {
|
||||||
|
if ! o.KeyRingRef.IsEmpty() {
|
||||||
|
slog.Info("OpenPGPKeyRing.ContentReaderStream()", "keyring", o)
|
||||||
return o.KeyRingRef.Lookup(nil).ContentReaderStream()
|
return o.KeyRingRef.Lookup(nil).ContentReaderStream()
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("Cannot provide transport reader for string content")
|
return nil, fmt.Errorf("Cannot provide transport reader for string content")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *OpenPGPKeyRing) ContentWriterStream() (*transport.Writer, error) {
|
func (o *OpenPGPKeyRing) ContentWriterStream() (*transport.Writer, error) {
|
||||||
if len(o.KeyRing) == 0 && ! o.KeyRingRef.IsEmpty() {
|
//if len(o.KeyRing) == 0 && ! o.KeyRingRef.IsEmpty() {
|
||||||
|
if ! o.KeyRingRef.IsEmpty() {
|
||||||
return o.KeyRingRef.Lookup(nil).ContentWriterStream()
|
return o.KeyRingRef.Lookup(nil).ContentWriterStream()
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("Cannot provide transport writer for string content")
|
return nil, fmt.Errorf("Cannot provide transport writer for string content")
|
||||||
|
@ -8,6 +8,112 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"fmt"
|
"fmt"
|
||||||
"decl/internal/data"
|
"decl/internal/data"
|
||||||
|
"decl/internal/codec"
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp"
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/armor"
|
||||||
|
"bytes"
|
||||||
|
"log/slog"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"path/filepath"
|
||||||
|
"io/ioutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
var(
|
||||||
|
TestUserKeyPublic string = `
|
||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
xsBNBGhI/VUBCADDVSm3mKY5JsncMMJFV0zELMrmip7dkK3vvMvVWVmMHiC4akDH
|
||||||
|
WPxUdWNQPjE2e5HGF9Ebg0c7gu634VG470MnTzFdPV6f5zA+yJfdKrLq7gpl9QGW
|
||||||
|
jFLIeK/l4xc+MIpOE1rD9WqYUUw2IYY8YANYq4yB36rq41VuZps/adI9Go5IhfcU
|
||||||
|
3SVb7o7pa/gWE0FVu9ze31j2agC8FIKHgB++7bmYgbAQz5Qi1qgtG0Kn25QUacJ6
|
||||||
|
Akm2+h4w3SQCR6HLRV2BO29x9mFBszf2KQ7DW2VNiGyUuQQ3m8v2ZidG/11ff6U6
|
||||||
|
ad5tvr/8sYr5jOnKEJyDP9v9yQ04cU94GmsPABEBAAHNL1Rlc3RVc2VyMSAoVGVz
|
||||||
|
dFVzZXIxKSA8dGVzdHVzZXJAcm9zc2tlZW4uaG91c2U+wsCKBBMBCAA+BQJoSP1V
|
||||||
|
CRDfB5I2FtNl1xYhBADOnA8Aah3FXyl/m98HkjYW02XXAhsDAh4BAhkBAgsHAhUI
|
||||||
|
AxYAAgMnBwIAAGKLB/9whwgfLkoTYI+Q0Te2uZXl7FPyW0t4tbUSoI1aiVw+ymND
|
||||||
|
V+wuqYsjYDob2MyK/TAFkSCqZhBIRbGLRJtwzQwkF/amGuelHSSBX3LdxK/sp2UU
|
||||||
|
+zv/NBEP1LlUNKchuxpdBPYjKHdbOLPoKqFfdCujSxpWTIeKCwvnDtuP+PlsjUgc
|
||||||
|
afxMx+cVwe77AZ1Fi5CBD9Dr7nNsLovywrSiszyVh5eT0pbcu8Elf5oYQNT1q3ms
|
||||||
|
aqrw95shlGQiwVgrfTvRCDeZnKafHwMUoh48otsNI9aS0HpChi+JNd+PLe/Wlsj5
|
||||||
|
x+q0sHc+5/24zQvN0Wx9fPE4/7z8Pr+CUhAxjI7hzsBNBGhI/VUBCACfahoi2GRx
|
||||||
|
OfOqJ4ZN8Te+4bJeOQdzTofAisfCU736q+MvEKtAuY72vzWdERWpn7XABmtkfII8
|
||||||
|
Xyya8iHKuEGCETy0YoZ15GLBgSHhLnlN2U/4BkrUjGvUjZWquW22gfFB1q8ZdSGw
|
||||||
|
pg8hrspY/b+nnAGdawq+hfE6YRQTmG5tkBrctxfxglBnKzezmL1a3arTHWf2SRlL
|
||||||
|
eAWNI4sACryP/5plD6+9Z9YXTKeDlXnga6BzB80y7F2g0cPdtX20dWAGx4irq2I2
|
||||||
|
SxlABvWMZrdm2Upr6yLHD2zTpbf1FkKFUw9j0lrL1fMq0/j9zbKJsTh6CtOlF04s
|
||||||
|
AeoEV9SZ36GvABEBAAHCwHYEGAEIACoFAmhI/VUJEN8HkjYW02XXFiEEAM6cDwBq
|
||||||
|
HcVfKX+b3weSNhbTZdcCGwwAAFxWB/9Af7qpYKldDz5iNYQluFoPfyHAVlOpiakf
|
||||||
|
hvnu7hijTEgB1frByKu2m+k4m7gANBgfWldsYi1feWBVn6fspXuCc0k7opmQgol7
|
||||||
|
ueTrsGnNB7U0l14HcKSTLZ2c/Jt7ZS6aXXjxpYPq0/5lt8+5sRkXxHI9HhAx6gK/
|
||||||
|
RJCNITRt/V/gT4YWWbz8VHgkPIfHFsjr8brVhm4V/+JKZAG4eSNQp4QrTpdIjdfa
|
||||||
|
1rd91qffyrWhPNTQErE2jFOXSU/OojdDjGJ7pwr0qj4FHACVL3/oqYog2NrUWf92
|
||||||
|
QcwwWrEZNZUpJEMUB5q+tOoZ40ll0A8lsvABULZDqWveYpRQF+rQ
|
||||||
|
=jBvZ
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
|
`
|
||||||
|
TestUserKeyPair string = `
|
||||||
|
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||||
|
|
||||||
|
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
|
||||||
|
=BAfD
|
||||||
|
-----END PGP PRIVATE KEY BLOCK-----
|
||||||
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewOpenPGPKeyRingResource(t *testing.T) {
|
func TestNewOpenPGPKeyRingResource(t *testing.T) {
|
||||||
@ -106,3 +212,81 @@ func TestReadKeyRing(t *testing.T) {
|
|||||||
assert.Contains(t, testKeyRing.entityList[0].Identities, "TestUser (TestUser) <matthewrich.conf@gmail.com>")
|
assert.Contains(t, testKeyRing.entityList[0].Identities, "TestUser (TestUser) <matthewrich.conf@gmail.com>")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDecryptKeyPairRing(t *testing.T) {
|
||||||
|
keyReader := bytes.NewBufferString(TestUserKeyPair)
|
||||||
|
block, err := armor.Decode(keyReader)
|
||||||
|
|
||||||
|
assert.NotEqual(t, err, io.EOF)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.False(t, block.Type != openpgp.PublicKeyType && block.Type != openpgp.PrivateKeyType)
|
||||||
|
|
||||||
|
slog.Info("TestDecryptKeyPairRing", "block", block)
|
||||||
|
|
||||||
|
entityList, err := openpgp.ReadKeyRing(block.Body)
|
||||||
|
assert.True(t, entityList[0].PrivateKey.Encrypted)
|
||||||
|
|
||||||
|
// entityList, err := openpgp.ReadArmoredKeyRing(bytes.NewBufferString(TestUserKeyPair))
|
||||||
|
slog.Info("TestDecryptKeyPairRing", "entity", entityList[0], "err", err)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.NotNil(t, entityList)
|
||||||
|
|
||||||
|
entityList[0].PrivateKey.Decrypt([]byte("foo"))
|
||||||
|
assert.False(t, entityList[0].PrivateKey.Encrypted)
|
||||||
|
|
||||||
|
/*
|
||||||
|
for _, subkey := range entity.Subkeys {
|
||||||
|
if decryptErr := subkey.PrivateKey.Encrypt(passphrase); decryptErr != nil {
|
||||||
|
return fmt.Errorf("%w subkey (private key): %w", ErrOpenPGPDecryptionFailure, decryptErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadKeyPairRing(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
testDataDir := "../../tests/data/openpgp-keyring"
|
||||||
|
files, err := os.ReadDir(testDataDir)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
for _, entry := range files {
|
||||||
|
if entry.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ! strings.HasSuffix(strings.ToLower(entry.Name()), ".asc") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
path := filepath.Join(testDataDir, entry.Name())
|
||||||
|
fileData, err := ioutil.ReadFile(path)
|
||||||
|
|
||||||
|
declarationAttributes := strings.Builder{}
|
||||||
|
enc := codec.NewYAMLEncoder(&declarationAttributes)
|
||||||
|
type kr struct {
|
||||||
|
KeyRing string `yaml:"keyring"`
|
||||||
|
}
|
||||||
|
assert.Nil(t, enc.Encode(&kr{ KeyRing: string(fileData) }))
|
||||||
|
|
||||||
|
testKeyRing := NewOpenPGPKeyRing()
|
||||||
|
|
||||||
|
testKeyRing.UseConfig(MockConfigValueGetter(func(key string) (any, error) {
|
||||||
|
switch key {
|
||||||
|
case "passphrase":
|
||||||
|
return "foo", nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("%w: %s", data.ErrUnknownConfigurationKey, key)
|
||||||
|
}))
|
||||||
|
|
||||||
|
e := testKeyRing.LoadDecl(declarationAttributes.String())
|
||||||
|
assert.Nil(t, e)
|
||||||
|
y, err := testKeyRing.Read(ctx)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.NotNil(t, y)
|
||||||
|
assert.Greater(t, len(testKeyRing.entityList), 0)
|
||||||
|
|
||||||
|
if strings.HasSuffix(strings.ToLower(entry.Name()), "_private.asc") {
|
||||||
|
assert.NotNil(t, testKeyRing.entityList[0].PrivateKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -66,7 +66,6 @@ type Package struct {
|
|||||||
ReadCommand *command.Command `yaml:"-" json:"-"`
|
ReadCommand *command.Command `yaml:"-" json:"-"`
|
||||||
UpdateCommand *command.Command `yaml:"-" json:"-"`
|
UpdateCommand *command.Command `yaml:"-" json:"-"`
|
||||||
DeleteCommand *command.Command `yaml:"-" json:"-"`
|
DeleteCommand *command.Command `yaml:"-" json:"-"`
|
||||||
Resources data.ResourceMapper `yaml:"-" json:"-"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -123,10 +122,6 @@ func (p *Package) Init(u data.URIParser) error {
|
|||||||
return p.SetParsedURI(u)
|
return p.SetParsedURI(u)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Package) SetResourceMapper(resources data.ResourceMapper) {
|
|
||||||
p.Resources = resources
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Package) Clone() data.Resource {
|
func (p *Package) Clone() data.Resource {
|
||||||
newp := &Package {
|
newp := &Package {
|
||||||
Common: p.Common.Clone(),
|
Common: p.Common.Clone(),
|
||||||
|
@ -88,7 +88,6 @@ type PKI struct {
|
|||||||
|
|
||||||
Bits int `json:"bits" yaml:"bits"`
|
Bits int `json:"bits" yaml:"bits"`
|
||||||
EncodingType EncodingType `json:"type" yaml:"type"`
|
EncodingType EncodingType `json:"type" yaml:"type"`
|
||||||
Resources data.ResourceMapper `json:"-" yaml:"-"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPKI() *PKI {
|
func NewPKI() *PKI {
|
||||||
@ -96,11 +95,6 @@ func NewPKI() *PKI {
|
|||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *PKI) SetResourceMapper(resources data.ResourceMapper) {
|
|
||||||
slog.Info("PKI.SetResourceMapper()", "resources", resources)
|
|
||||||
k.Resources = resources
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *PKI) Clone() data.Resource {
|
func (k *PKI) Clone() data.Resource {
|
||||||
return &PKI {
|
return &PKI {
|
||||||
Common: k.Common.Clone(),
|
Common: k.Common.Clone(),
|
||||||
|
@ -60,7 +60,6 @@ type User struct {
|
|||||||
ReadCommand *command.Command `json:"-" yaml:"-"`
|
ReadCommand *command.Command `json:"-" yaml:"-"`
|
||||||
UpdateCommand *command.Command `json:"-" yaml:"-"`
|
UpdateCommand *command.Command `json:"-" yaml:"-"`
|
||||||
DeleteCommand *command.Command `json:"-" yaml:"-"`
|
DeleteCommand *command.Command `json:"-" yaml:"-"`
|
||||||
Resources data.ResourceMapper `json:"-" yaml:"-"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUser() *User {
|
func NewUser() *User {
|
||||||
@ -107,10 +106,6 @@ func (u *User) NormalizePath() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) SetResourceMapper(resources data.ResourceMapper) {
|
|
||||||
u.Resources = resources
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *User) Clone() data.Resource {
|
func (u *User) Clone() data.Resource {
|
||||||
newu := &User {
|
newu := &User {
|
||||||
Common: u.Common,
|
Common: u.Common,
|
||||||
|
Loading…
Reference in New Issue
Block a user