package capability import ( "fmt" "sort" "strings" wh "edge-infra.dev/pkg/f8n/warehouse" ) type ( // Capability is a K8s cluster capability that a package integrates with. Capability string Capabilities []Capability // Type is a string that categorizes capabilities. A capability can // either be infrastructure (and subject to split scheduling), or a runtime // capability (optionally applied to the target cluster). Type string ) const ( TypeInfra Type = "infrastructure" TypeRuntime Type = "runtime" // Infrastructure capability is handled specially and is always referred to by // the constant "infrastructure" // // TODO(aw185176): Support multiple infrastructure providers CapabilityInfra Capability = Capability(TypeInfra) ) // OCIAnnotations converts the set of capabilities to the OCI annotation added // to Pallet artifacts. If the set of capabilities is empty, nil is returned. func (c Capabilities) OCIAnnotations() map[string]string { if len(c) == 0 { return nil } return map[string]string{ wh.AnnotationCapabilities: strings.Join(c.StrArray(), ","), } } func (c Capabilities) StrArray() []string { s := make([]string, len(c)) for i, capability := range c { s[i] = string(capability) } sort.Strings(s) return s } func (c Capabilities) String() string { return strings.Join(c.StrArray(), ",") } // Set implements [flag.Value]. It accepts comma separated strings and accumulates // values from repeated occurrences of the flag. It also handles edge cases // like trailing / leading commas and duplicate values. func (c *Capabilities) Set(v string) error { nc := append(*c, FromString(v)...) j := 0 for i := 1; i < len(nc); i++ { if nc[j] == nc[i] { continue } j++ nc[j] = nc[i] } *c = nc[:j+1] return nil } // Get implements [flag.Getter] func (c *Capabilities) Get() any { return c } // Type implements [edge-infra.dev/pkg/lib/cli/rags.TypedValue] func (c *Capabilities) Type() string { return "capabilities" } // Assert that Capabilities implements the sort interface var _ sort.Interface = Capabilities{} func (c Capabilities) Len() int { return len(c) } func (c Capabilities) Less(i, j int) bool { return c[i] < c[j] } func (c Capabilities) Swap(i, j int) { c[i], c[j] = c[j], c[i] } // IsValid returns an error if the Type isn't either "runtime" or // "infrastructure" func (c Type) IsValid() error { if c != TypeInfra && c != TypeRuntime { return fmt.Errorf( "%s is not a valid capability type: expected one of [%s, %s]", c, TypeInfra, TypeRuntime, ) } return nil } // FromAnnotations parses the capabilities that a package integrates with from // an OCI annotation map. func FromAnnotations(a map[string]string) Capabilities { switch s := a[wh.AnnotationCapabilities]; s { case "": return nil default: var cc Capabilities tt := strings.Split(s, ",") for _, t := range tt { cc = append(cc, Capability(t)) } return cc } } // FromString parses an array of Capabilities from a comma separated string. func FromString(s string) Capabilities { tokens := strings.Split(strings.Trim(s, ","), ",") c := make([]Capability, 0, len(tokens)) for _, cap := range strings.Split(strings.Trim(s, ","), ",") { c = append(c, Capability(cap)) } return c }