Skip to content

Commit

Permalink
Add support for charm-user.
Browse files Browse the repository at this point in the history
  • Loading branch information
hpidcock committed Dec 4, 2023
1 parent 1268fe2 commit 1815c9f
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 8 deletions.
54 changes: 46 additions & 8 deletions meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,16 @@ func (r Relation) IsImplicit() bool {
r.Role == RoleProvider)
}

// RunAs defines which user to run a certain process as.
type RunAs string

const (
RunAsDefault RunAs = ""
RunAsRoot RunAs = "root"
RunAsSudoer RunAs = "sudoer"
RunAsNonRoot RunAs = "non-root"
)

// Meta represents all the known content that may be defined
// within a charm's metadata.yaml file.
// Note: Series is serialised for backward compatibility
Expand Down Expand Up @@ -280,6 +290,7 @@ type Meta struct {
// v2
Containers map[string]Container `bson:"containers,omitempty" json:"containers,omitempty" yaml:"containers,omitempty"`
Assumes *assumes.ExpressionTree `bson:"assumes,omitempty" json:"assumes,omitempty" yaml:"assumes,omitempty"`
CharmUser RunAs `bson:"charm-user,omitempty" json:"charm-user,omitempty" yaml:"charm-user,omitempty"`
}

// Container specifies the possible systems it supports and mounts it wants.
Expand Down Expand Up @@ -563,13 +574,9 @@ func parseMeta(m map[string]interface{}) (*Meta, error) {
return nil, err
}
meta.PayloadClasses = parsePayloadClasses(m["payloads"])

if ver := m["min-juju-version"]; ver != nil {
minver, err := version.Parse(ver.(string))
if err != nil {
return &meta, errors.Annotate(err, "invalid min-juju-version")
}
meta.MinJujuVersion = minver
meta.MinJujuVersion, err = parseMinJujuVersion(m["min-juju-version"])
if err != nil {
return nil, err
}
meta.Terms = parseStringList(m["terms"])

Expand All @@ -583,6 +590,10 @@ func parseMeta(m map[string]interface{}) (*Meta, error) {
if err != nil {
return nil, errors.Annotatef(err, "parsing containers")
}
meta.CharmUser, err = parseCharmUser(m["charm-user"])
if err != nil {
return nil, errors.Annotatef(err, "parsing charm-user")
}
return &meta, nil
}

Expand Down Expand Up @@ -1224,6 +1235,31 @@ func parseMounts(input interface{}, storage map[string]Storage) ([]Mount, error)
return mounts, nil
}

func parseMinJujuVersion(value any) (version.Number, error) {
if value == nil {
return version.Zero, nil
}
ver, err := version.Parse(value.(string))
if err != nil {
return version.Zero, errors.Annotate(err, "invalid min-juju-version")
}
return ver, nil
}

func parseCharmUser(value any) (RunAs, error) {
if value == nil {
return RunAsDefault, nil
}
v := RunAs(value.(string))
switch v {
case RunAsRoot, RunAsSudoer, RunAsNonRoot:
return v, nil
default:
return RunAsDefault, errors.Errorf("invalid charm-user %q expected one of %s, %s or %s", v,
RunAsRoot, RunAsSudoer, RunAsNonRoot)
}
}

var storageSchema = schema.FieldMap(
schema.Fields{
"type": schema.OneOf(schema.Const(string(StorageBlock)), schema.Const(string(StorageFilesystem))),
Expand Down Expand Up @@ -1405,6 +1441,7 @@ var charmSchema = schema.FieldMap(
"min-juju-version": schema.String(),
"assumes": schema.List(schema.Any()),
"containers": schema.StringMap(containerSchema),
"charm-user": schema.String(),
},
schema.Defaults{
"provides": schema.Omit,
Expand All @@ -1426,6 +1463,7 @@ var charmSchema = schema.FieldMap(
"min-juju-version": schema.Omit,
"assumes": schema.Omit,
"containers": schema.Omit,
"charm-user": schema.Omit,
},
)

Expand All @@ -1449,7 +1487,7 @@ func ensureUnambiguousFormat(raw map[interface{}]interface{}) error {
for _, key := range keys {
detected := FormatUnknown
switch key {
case "containers", "assumes":
case "containers", "assumes", "charm-user":
detected = FormatV2
case "series", "deployment", "min-juju-version":
detected = FormatV1
Expand Down
45 changes: 45 additions & 0 deletions meta_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2050,3 +2050,48 @@ func (FormatMetaSuite) TestCheckV2WithDeployment(c *gc.C) {
err := meta.Check(charm.FormatV2, charm.SelectionManifest, charm.SelectionBases)
c.Assert(err, gc.ErrorMatches, `deployment in metadata v2 not valid`)
}

func (s *MetaSuite) TestCharmUser(c *gc.C) {
meta, err := charm.ReadMeta(strings.NewReader(`
name: a
summary: b
description: c
charm-user: root
`))
c.Assert(err, gc.IsNil)
c.Assert(meta.CharmUser, gc.Equals, charm.RunAsRoot)

meta, err = charm.ReadMeta(strings.NewReader(`
name: a
summary: b
description: c
charm-user: sudoer
`))
c.Assert(err, gc.IsNil)
c.Assert(meta.CharmUser, gc.Equals, charm.RunAsSudoer)

meta, err = charm.ReadMeta(strings.NewReader(`
name: a
summary: b
description: c
charm-user: non-root
`))
c.Assert(err, gc.IsNil)
c.Assert(meta.CharmUser, gc.Equals, charm.RunAsNonRoot)

meta, err = charm.ReadMeta(strings.NewReader(`
name: a
summary: b
description: c
`))
c.Assert(err, gc.IsNil)
c.Assert(meta.CharmUser, gc.Equals, charm.RunAsDefault)

_, err = charm.ReadMeta(strings.NewReader(`
name: a
summary: b
description: c
charm-user: barry
`))
c.Assert(err, gc.ErrorMatches, `parsing charm-user: invalid charm-user "barry" expected one of root, sudoer or non-root`)
}

0 comments on commit 1815c9f

Please sign in to comment.