feat: add scheduler-k3s annotations:report and labels:report
The scheduler-k3s plugin exposes `annotations:set` and `labels:set` but no matching report subcommands, so scripts could not inspect the configured state for idempotent management without reading the property files directly. The new `scheduler-k3s:annotations:report` and `scheduler-k3s:labels:report` surface the configured entries with stdout, JSON, single-flag query, and `--process-type` / `--resource-type` filtering, mirroring the recently added `scheduler-k3s:charts:report`. The literal `GlobalProcessType` value `--global` is rendered as `global` in report keys to avoid leading dashes. The `scheduler-k3s:autoscaling-auth:report` command is updated alongside to loop over every app when no app and no `--global` flag is provided, matching the convention used by `scheduler-k3s:report`.
This commit is contained in:
@@ -5,8 +5,9 @@
|
||||
|
||||
```
|
||||
scheduler-k3s:annotations:set <app|--global> <property> (<value>) [--process-type PROCESS_TYPE] <--resource-type RESOURCE_TYPE>, Set or clear an annotation for a given app/process-type/resource-type combination
|
||||
scheduler-k3s:annotations:report [<app>|--global] [--format stdout|json] [--process-type PROCESS_TYPE] [--resource-type RESOURCE_TYPE] # Displays a scheduler-k3s annotations report for one or more apps
|
||||
scheduler-k3s:autoscaling-auth:set <app|--global> <trigger> [<--metadata key=value>...], Set or clear a scheduler-k3s autoscaling keda trigger authentication resource for an app
|
||||
scheduler-k3s:autoscaling-auth:report <app|--global> [--format stdout|json] [--include-metadata] # Displays a scheduler-k3s autoscaling auth report for an app
|
||||
scheduler-k3s:autoscaling-auth:report [<app>|--global] [--format stdout|json] [--include-metadata] # Displays a scheduler-k3s autoscaling auth report for one or more apps
|
||||
scheduler-k3s:charts:report [<chart>] [--format stdout|json] # Displays a scheduler-k3s chart override report
|
||||
scheduler-k3s:charts:set <chart-name.property> (<value>) # Set or clear a chart-specific helm value
|
||||
scheduler-k3s:cluster:add [ssh://user@host:port] # Adds a server node to a Dokku-managed cluster
|
||||
@@ -15,6 +16,7 @@ scheduler-k3s:cluster:remove [node-id] # Removes client node to a D
|
||||
scheduler-k3s:ensure-charts # Ensures the k3s charts are installed
|
||||
scheduler-k3s:initialize # Initializes a cluster
|
||||
scheduler-k3s:labels:set <app|--global> <property> (<value>) [--process-type PROCESS_TYPE] <--resource-type RESOURCE_TYPE> # Set or clear a label for a given app/process-type/resource-type combination
|
||||
scheduler-k3s:labels:report [<app>|--global] [--format stdout|json] [--process-type PROCESS_TYPE] [--resource-type RESOURCE_TYPE] # Displays a scheduler-k3s labels report for one or more apps
|
||||
scheduler-k3s:profiles:add <profile> [--role ROLE] [--insecure-allow-unknown-hosts] [--taint-scheduling] [--kubelet-args KUBELET_ARGS] Adds a node profile to the k3s cluster
|
||||
scheduler-k3s:profiles:list [--format json|stdout] # Lists all node profiles in the k3s cluster
|
||||
scheduler-k3s:profiles:remove <profile> # Removes a node profile from the k3s cluster
|
||||
@@ -387,6 +389,35 @@ dokku scheduler-k3s:annotations:set node-js-app annotation.key --resource-type d
|
||||
|
||||
A `ps:restart` is required after removing annotations in order to remove them from running resources.
|
||||
|
||||
#### Displaying annotations
|
||||
|
||||
Configured annotations can be inspected with the `scheduler-k3s:annotations:report` command. Without arguments, it iterates every app and prints all annotations. Passing an app name (or `--global`) scopes the report:
|
||||
|
||||
```shell
|
||||
dokku scheduler-k3s:annotations:report
|
||||
dokku scheduler-k3s:annotations:report node-js-app
|
||||
dokku scheduler-k3s:annotations:report --global
|
||||
```
|
||||
|
||||
`--process-type` and `--resource-type` flags narrow the output to a specific scope, matching the flags accepted by `scheduler-k3s:annotations:set`:
|
||||
|
||||
```shell
|
||||
dokku scheduler-k3s:annotations:report node-js-app --resource-type deployment
|
||||
dokku scheduler-k3s:annotations:report node-js-app --process-type web --resource-type deployment
|
||||
```
|
||||
|
||||
JSON output emits flat keys of the form `{process_type}.{resource_type}.{annotation_key}`. The literal `--global` process type is rendered as `global` to keep keys free of leading dashes:
|
||||
|
||||
```shell
|
||||
dokku scheduler-k3s:annotations:report node-js-app --format json
|
||||
```
|
||||
|
||||
A single value can also be read directly with a flag of the form `--scheduler-k3s-annotations.{process_type}.{resource_type}.{annotation_key}`:
|
||||
|
||||
```shell
|
||||
dokku scheduler-k3s:annotations:report node-js-app --scheduler-k3s-annotations.global.deployment.annotation.key
|
||||
```
|
||||
|
||||
#### Setting Labels
|
||||
|
||||
Dokku injects certain labels into each created resource by default, but it may be necessary to inject others for tighter integration with third-party tools. The `scheduler-k3s:labels:set` command can be used to perform this task. The command takes an app name and a required `--resource-type` flag.
|
||||
@@ -428,6 +459,20 @@ dokku scheduler-k3s:labels:set node-js-app label.key --resource-type deployment
|
||||
|
||||
A `ps:restart` is required after removing labels in order to remove them from running resources.
|
||||
|
||||
#### Displaying labels
|
||||
|
||||
Configured labels can be inspected with the `scheduler-k3s:labels:report` command. The surface mirrors `scheduler-k3s:annotations:report`:
|
||||
|
||||
```shell
|
||||
dokku scheduler-k3s:labels:report
|
||||
dokku scheduler-k3s:labels:report node-js-app
|
||||
dokku scheduler-k3s:labels:report --global
|
||||
dokku scheduler-k3s:labels:report node-js-app --resource-type deployment
|
||||
dokku scheduler-k3s:labels:report node-js-app --process-type web --resource-type deployment
|
||||
dokku scheduler-k3s:labels:report node-js-app --format json
|
||||
dokku scheduler-k3s:labels:report node-js-app --scheduler-k3s-labels.global.deployment.label.key
|
||||
```
|
||||
|
||||
### Autoscaling
|
||||
|
||||
#### Workload Autoscaling
|
||||
@@ -566,10 +611,12 @@ dokku scheduler-k3s:autoscaling-auth:set $APP $TRIGGER_TYPE
|
||||
|
||||
##### Displaying an Authentication Resource report
|
||||
|
||||
To see a list of authentication resources managed by Dokku, run the `scheduler-k3s:autoscaling-auth:report` command.
|
||||
To see a list of authentication resources managed by Dokku, run the `scheduler-k3s:autoscaling-auth:report` command. Without arguments, the report iterates every app; passing an app name (or `--global`) scopes the report:
|
||||
|
||||
```shell
|
||||
dokku scheduler-k3s:autoscaling-auth:report
|
||||
dokku scheduler-k3s:autoscaling-auth:report node-js-app
|
||||
dokku scheduler-k3s:autoscaling-auth:report --global
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
SUBCOMMANDS = subcommands/annotations:set subcommands/autoscaling-auth:set subcommands/autoscaling-auth:report subcommands/charts:report subcommands/charts:set subcommands/cluster:add subcommands/cluster:list subcommands/cluster:remove subcommands/ensure-charts subcommands/initialize subcommands/labels:set subcommands/profiles:add subcommands/profiles:list subcommands/profiles:remove subcommands/report subcommands/set subcommands/show-kubeconfig subcommands/uninstall
|
||||
SUBCOMMANDS = subcommands/annotations:set subcommands/annotations:report subcommands/autoscaling-auth:set subcommands/autoscaling-auth:report subcommands/charts:report subcommands/charts:set subcommands/cluster:add subcommands/cluster:list subcommands/cluster:remove subcommands/ensure-charts subcommands/initialize subcommands/labels:set subcommands/labels:report subcommands/profiles:add subcommands/profiles:list subcommands/profiles:remove subcommands/report subcommands/set subcommands/show-kubeconfig subcommands/uninstall
|
||||
TRIGGERS = triggers/core-post-deploy triggers/core-post-extract triggers/install triggers/post-app-clone-setup triggers/post-app-rename-setup triggers/post-certs-update triggers/post-certs-remove triggers/post-create triggers/post-delete triggers/report triggers/scheduler-app-status triggers/scheduler-deploy triggers/scheduler-enter triggers/scheduler-is-deployed triggers/scheduler-logs triggers/scheduler-proxy-config triggers/scheduler-proxy-logs triggers/scheduler-post-delete triggers/scheduler-run triggers/scheduler-run-list triggers/scheduler-stop triggers/scheduler-cron-write triggers/storage-create triggers/storage-destroy triggers/storage-status triggers/scheduler-storage-exec
|
||||
BUILD = commands subcommands triggers
|
||||
PLUGIN_NAME = scheduler-k3s
|
||||
|
||||
@@ -1,12 +1,24 @@
|
||||
package scheduler_k3s
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
)
|
||||
|
||||
const (
|
||||
annotationsReportType = "scheduler-k3s-annotations"
|
||||
labelsReportType = "scheduler-k3s-labels"
|
||||
|
||||
// reportProcessTypeGlobal is the rendered form of GlobalProcessType in annotation
|
||||
// and label report keys (both JSON and single-flag). Real process types cannot
|
||||
// collide because they cannot contain "--".
|
||||
reportProcessTypeGlobal = "global"
|
||||
)
|
||||
|
||||
// tokenMask is shown in place of the raw token value in default stdout output.
|
||||
const tokenMask = "*******"
|
||||
|
||||
@@ -161,6 +173,304 @@ func ReportAutoscalingAuthSingleApp(appName string, format string, includeMetada
|
||||
})
|
||||
}
|
||||
|
||||
// ExtractReportInfoFlag scans arguments for a single info flag whose name starts with
|
||||
// the given prefix (e.g. "--scheduler-k3s-annotations.") and returns it separately from
|
||||
// the remaining passthrough arguments. Returns an error if more than one matching flag
|
||||
// is present. Matching args are removed from the passthrough list so the caller's
|
||||
// flag.FlagSet sees only its own flags and positional arguments.
|
||||
func ExtractReportInfoFlag(prefix string, arguments []string) ([]string, string, error) {
|
||||
passthrough := []string{}
|
||||
infoFlag := ""
|
||||
for _, argument := range arguments {
|
||||
if strings.HasPrefix(argument, prefix) {
|
||||
if infoFlag != "" {
|
||||
return nil, "", fmt.Errorf("only a single info flag may be specified")
|
||||
}
|
||||
infoFlag = argument
|
||||
continue
|
||||
}
|
||||
passthrough = append(passthrough, argument)
|
||||
}
|
||||
return passthrough, infoFlag, nil
|
||||
}
|
||||
|
||||
// annotationsLabelsReportEntry is a parsed (processType, resourceType, key) triple
|
||||
// produced when scanning the property store for annotations or labels.
|
||||
type annotationsLabelsReportEntry struct {
|
||||
ProcessType string
|
||||
ResourceType string
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
|
||||
// ReportAnnotationsSingleApp displays the scheduler-k3s annotations report for one app.
|
||||
func ReportAnnotationsSingleApp(appName string, format string, processType string, resourceType string, infoFlag string) error {
|
||||
if appName != "--global" {
|
||||
if err := common.VerifyAppName(appName); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
entries, err := collectAnnotationsEntries(appName, processType, resourceType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return renderAnnotationsLabelsReport(annotationsLabelsRenderInput{
|
||||
AppName: appName,
|
||||
ReportType: annotationsReportType,
|
||||
Heading: "annotations",
|
||||
RowLabel: "Annotation",
|
||||
Entries: entries,
|
||||
Format: format,
|
||||
InfoFlag: infoFlag,
|
||||
})
|
||||
}
|
||||
|
||||
// ReportLabelsSingleApp displays the scheduler-k3s labels report for one app.
|
||||
func ReportLabelsSingleApp(appName string, format string, processType string, resourceType string, infoFlag string) error {
|
||||
if appName != "--global" {
|
||||
if err := common.VerifyAppName(appName); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
entries, err := collectLabelsEntries(appName, processType, resourceType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return renderAnnotationsLabelsReport(annotationsLabelsRenderInput{
|
||||
AppName: appName,
|
||||
ReportType: labelsReportType,
|
||||
Heading: "labels",
|
||||
RowLabel: "Label",
|
||||
Entries: entries,
|
||||
Format: format,
|
||||
InfoFlag: infoFlag,
|
||||
})
|
||||
}
|
||||
|
||||
// collectAnnotationsEntries scans the property store for annotation entries on appName,
|
||||
// optionally filtered by processType/resourceType.
|
||||
func collectAnnotationsEntries(appName string, processType string, resourceType string) ([]annotationsLabelsReportEntry, error) {
|
||||
properties, err := common.PropertyGetAllByPrefix("scheduler-k3s", appName, "")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to get property list: %w", err)
|
||||
}
|
||||
|
||||
knownResourceTypes := map[string]bool{}
|
||||
for _, rt := range AnnotationResourceTypes {
|
||||
knownResourceTypes[rt] = true
|
||||
}
|
||||
|
||||
entries := []annotationsLabelsReportEntry{}
|
||||
for propertyName := range properties {
|
||||
if isReservedAnnotationProperty(propertyName) {
|
||||
continue
|
||||
}
|
||||
|
||||
dot := strings.LastIndex(propertyName, ".")
|
||||
if dot <= 0 || dot == len(propertyName)-1 {
|
||||
continue
|
||||
}
|
||||
|
||||
propProcessType := propertyName[:dot]
|
||||
propResourceType := propertyName[dot+1:]
|
||||
if !knownResourceTypes[propResourceType] {
|
||||
continue
|
||||
}
|
||||
|
||||
if processType != "" && propProcessType != processType {
|
||||
continue
|
||||
}
|
||||
if resourceType != "" && propResourceType != resourceType {
|
||||
continue
|
||||
}
|
||||
|
||||
annotationMap, err := getAnnotation(appName, propProcessType, propResourceType)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to read annotation %s: %w", propertyName, err)
|
||||
}
|
||||
|
||||
for key, value := range annotationMap {
|
||||
entries = append(entries, annotationsLabelsReportEntry{
|
||||
ProcessType: propProcessType,
|
||||
ResourceType: propResourceType,
|
||||
Key: key,
|
||||
Value: value,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return entries, nil
|
||||
}
|
||||
|
||||
// collectLabelsEntries scans the property store for label entries on appName,
|
||||
// optionally filtered by processType/resourceType.
|
||||
func collectLabelsEntries(appName string, processType string, resourceType string) ([]annotationsLabelsReportEntry, error) {
|
||||
properties, err := common.PropertyGetAllByPrefix("scheduler-k3s", appName, "labels.")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to get property list: %w", err)
|
||||
}
|
||||
|
||||
knownResourceTypes := map[string]bool{}
|
||||
for _, rt := range LabelResourceTypes {
|
||||
knownResourceTypes[rt] = true
|
||||
}
|
||||
|
||||
entries := []annotationsLabelsReportEntry{}
|
||||
for propertyName := range properties {
|
||||
suffix := strings.TrimPrefix(propertyName, "labels.")
|
||||
dot := strings.LastIndex(suffix, ".")
|
||||
if dot <= 0 || dot == len(suffix)-1 {
|
||||
continue
|
||||
}
|
||||
|
||||
propProcessType := suffix[:dot]
|
||||
propResourceType := suffix[dot+1:]
|
||||
if !knownResourceTypes[propResourceType] {
|
||||
continue
|
||||
}
|
||||
|
||||
if processType != "" && propProcessType != processType {
|
||||
continue
|
||||
}
|
||||
if resourceType != "" && propResourceType != resourceType {
|
||||
continue
|
||||
}
|
||||
|
||||
labelMap, err := getLabel(appName, propProcessType, propResourceType)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to read label %s: %w", propertyName, err)
|
||||
}
|
||||
|
||||
for key, value := range labelMap {
|
||||
entries = append(entries, annotationsLabelsReportEntry{
|
||||
ProcessType: propProcessType,
|
||||
ResourceType: propResourceType,
|
||||
Key: key,
|
||||
Value: value,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return entries, nil
|
||||
}
|
||||
|
||||
func isReservedAnnotationProperty(propertyName string) bool {
|
||||
for _, prefix := range reservedAnnotationPrefixes {
|
||||
if strings.HasPrefix(propertyName, prefix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type annotationsLabelsRenderInput struct {
|
||||
AppName string
|
||||
ReportType string
|
||||
// Heading is the plural noun used in stdout headers (e.g. "annotations", "labels").
|
||||
Heading string
|
||||
// RowLabel is the singular noun used to prefix each stdout row (e.g. "Annotation").
|
||||
RowLabel string
|
||||
Entries []annotationsLabelsReportEntry
|
||||
Format string
|
||||
InfoFlag string
|
||||
}
|
||||
|
||||
// renderAnnotationsLabelsReport dispatches to stdout/json/single-flag rendering for the
|
||||
// annotations and labels reports.
|
||||
func renderAnnotationsLabelsReport(input annotationsLabelsRenderInput) error {
|
||||
if input.Format != "stdout" && input.Format != "json" {
|
||||
return fmt.Errorf("Invalid format: %s", input.Format)
|
||||
}
|
||||
if input.Format == "json" && input.InfoFlag != "" {
|
||||
return fmt.Errorf("--format flag cannot be specified when specifying an info flag")
|
||||
}
|
||||
|
||||
flatValues := map[string]string{}
|
||||
flagToValue := map[string]string{}
|
||||
flagPrefix := "--" + input.ReportType + "."
|
||||
for _, entry := range input.Entries {
|
||||
composedKey := renderProcessType(entry.ProcessType) + "." + entry.ResourceType + "." + entry.Key
|
||||
flatValues[composedKey] = entry.Value
|
||||
flagToValue[flagPrefix+composedKey] = entry.Value
|
||||
}
|
||||
|
||||
if input.InfoFlag != "" {
|
||||
value, ok := flagToValue[input.InfoFlag]
|
||||
if !ok {
|
||||
validFlags := []string{}
|
||||
for flag := range flagToValue {
|
||||
validFlags = append(validFlags, flag)
|
||||
}
|
||||
sort.Strings(validFlags)
|
||||
return fmt.Errorf("Invalid flag passed, valid flags: %s", strings.Join(validFlags, ", "))
|
||||
}
|
||||
fmt.Println(value)
|
||||
return nil
|
||||
}
|
||||
|
||||
if input.Format == "json" {
|
||||
b, err := json.Marshal(flatValues)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to marshal json: %w", err)
|
||||
}
|
||||
fmt.Println(string(b))
|
||||
return nil
|
||||
}
|
||||
|
||||
entriesByGroup := map[string][]annotationsLabelsReportEntry{}
|
||||
for _, entry := range input.Entries {
|
||||
groupKey := renderProcessType(entry.ProcessType) + "/" + entry.ResourceType
|
||||
entriesByGroup[groupKey] = append(entriesByGroup[groupKey], entry)
|
||||
}
|
||||
|
||||
groupKeys := []string{}
|
||||
for groupKey := range entriesByGroup {
|
||||
groupKeys = append(groupKeys, groupKey)
|
||||
}
|
||||
sort.Strings(groupKeys)
|
||||
|
||||
common.LogInfo2Quiet(fmt.Sprintf("%s %s information", input.AppName, input.Heading))
|
||||
if len(groupKeys) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, groupKey := range groupKeys {
|
||||
groupEntries := entriesByGroup[groupKey]
|
||||
sort.Slice(groupEntries, func(i, j int) bool {
|
||||
return groupEntries[i].Key < groupEntries[j].Key
|
||||
})
|
||||
|
||||
length := 31
|
||||
for _, entry := range groupEntries {
|
||||
label := fmt.Sprintf("%s (%s) %s:", input.RowLabel, groupKey, entry.Key)
|
||||
if len(label) > length {
|
||||
length = len(label)
|
||||
}
|
||||
}
|
||||
|
||||
for _, entry := range groupEntries {
|
||||
label := fmt.Sprintf("%s (%s) %s:", input.RowLabel, groupKey, entry.Key)
|
||||
common.LogVerbose(fmt.Sprintf("%s%s", common.RightPad(label, length, " "), entry.Value))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// renderProcessType normalizes the in-storage process type for display in JSON keys,
|
||||
// stdout headers, and single-flag lookups. GlobalProcessType (literal "--global") is
|
||||
// rendered as "global"; real process types pass through unchanged.
|
||||
func renderProcessType(processType string) string {
|
||||
if processType == GlobalProcessType {
|
||||
return reportProcessTypeGlobal
|
||||
}
|
||||
return processType
|
||||
}
|
||||
|
||||
func reportComputedDeployTimeout(appName string) string {
|
||||
return getComputedDeployTimeout(appName)
|
||||
}
|
||||
|
||||
@@ -52,6 +52,54 @@ const KubeConfigPath = "/etc/rancher/k3s/k3s.yaml"
|
||||
const DefaultKubeContext = ""
|
||||
const TriggerAuthPropertyPrefix = "trigger-auth."
|
||||
|
||||
// AnnotationResourceTypes lists the kubernetes resource types that scheduler-k3s
|
||||
// supports user-provided annotations for. The order here is also the iteration order
|
||||
// used when rendering reports.
|
||||
var AnnotationResourceTypes = []string{
|
||||
"certificate",
|
||||
"cronjob",
|
||||
"deployment",
|
||||
"ingress",
|
||||
"job",
|
||||
"keda_scaled_object",
|
||||
"keda_secret",
|
||||
"keda_trigger_authentication",
|
||||
"pod",
|
||||
"secret",
|
||||
"service",
|
||||
"serviceaccount",
|
||||
"traefik_ingressroute",
|
||||
"traefik_middleware",
|
||||
}
|
||||
|
||||
// LabelResourceTypes lists the kubernetes resource types that scheduler-k3s
|
||||
// supports user-provided labels for. Differs from AnnotationResourceTypes because
|
||||
// keda resources do not currently flow user labels through.
|
||||
var LabelResourceTypes = []string{
|
||||
"certificate",
|
||||
"cronjob",
|
||||
"deployment",
|
||||
"ingress",
|
||||
"job",
|
||||
"pod",
|
||||
"secret",
|
||||
"service",
|
||||
"serviceaccount",
|
||||
"traefik_ingressroute",
|
||||
"traefik_middleware",
|
||||
}
|
||||
|
||||
// reservedAnnotationPrefixes lists property name prefixes that are not annotations
|
||||
// even though their trailing segment may collide with an AnnotationResourceTypes value
|
||||
// (e.g. "chart.cert-manager.deployment"). The annotations report uses this list to
|
||||
// exclude such properties when scanning the property store.
|
||||
var reservedAnnotationPrefixes = []string{
|
||||
"chart.",
|
||||
"labels.",
|
||||
"node-profile-",
|
||||
TriggerAuthPropertyPrefix,
|
||||
}
|
||||
|
||||
var (
|
||||
runtimeScheme = runtime.NewScheme()
|
||||
codecs = serializer.NewCodecFactory(runtimeScheme)
|
||||
|
||||
@@ -19,6 +19,7 @@ Additional commands:`
|
||||
helpContent = `
|
||||
scheduler-k3s:autoscaling-auth:set <app|--global> <trigger> [<--metadata key=value>...], Set or clear a scheduler-k3s autoscaling keda trigger authentication resource for an app
|
||||
scheduler-k3s:annotations:set <app|--global> <property> (<value>) [--process-type PROCESS_TYPE] <--resource-type RESOURCE_TYPE>, Set or clear an annotation for a given app/process-type/resource-type combination
|
||||
scheduler-k3s:annotations:report [<app>|--global] [--format stdout|json] [--process-type PROCESS_TYPE] [--resource-type RESOURCE_TYPE], Displays a scheduler-k3s annotations report for one or more apps
|
||||
scheduler-k3s:charts:report [<chart>] [--format stdout|json], Displays a scheduler-k3s chart override report
|
||||
scheduler-k3s:charts:set <chart-name.property> (<value>), Set or clear a chart-specific helm value
|
||||
scheduler-k3s:cluster:add [--profile PROFILE] [--role ROLE] [--insecure-allow-unknown-hosts] [--server-ip SERVER_IP] [--taint-scheduling] [--kubelet-args KUBELET_ARGS] <ssh://user@host:port>, Adds a server node to a Dokku-managed cluster
|
||||
@@ -27,6 +28,7 @@ Additional commands:`
|
||||
scheduler-k3s:ensure-charts, Ensures the k3s charts are installed
|
||||
scheduler-k3s:initialize [--server-ip SERVER_IP] [--taint-scheduling], Initializes a cluster
|
||||
scheduler-k3s:labels:set <app|--global> <property> (<value>) [--process-type PROCESS_TYPE] <--resource-type RESOURCE_TYPE>, Set or clear a label for a given app/process-type/resource-type combination
|
||||
scheduler-k3s:labels:report [<app>|--global] [--format stdout|json] [--process-type PROCESS_TYPE] [--resource-type RESOURCE_TYPE], Displays a scheduler-k3s labels report for one or more apps
|
||||
scheduler-k3s:profiles:add <profile> [--role ROLE] [--insecure-allow-unknown-hosts] [--taint-scheduling] [--kubelet-args KUBELET_ARGS], Adds a node profile to the k3s cluster
|
||||
scheduler-k3s:profiles:list [--format json|stdout], Lists all node profiles in the k3s cluster
|
||||
scheduler-k3s:profiles:remove <profile>, Removes a node profile from the k3s cluster
|
||||
|
||||
@@ -34,6 +34,23 @@ func main() {
|
||||
}
|
||||
|
||||
err = scheduler_k3s.CommandAnnotationsSet(appName, *processType, *resourceType, property, value)
|
||||
case "annotations:report":
|
||||
args := flag.NewFlagSet("scheduler-k3s:annotations:report", flag.ExitOnError)
|
||||
global := args.Bool("global", false, "--global: show the global report")
|
||||
format := args.String("format", "stdout", "format: [ stdout | json ]")
|
||||
processType := args.String("process-type", "", "--process-type: filter by process-type")
|
||||
resourceType := args.String("resource-type", "", "--resource-type: filter by resource-type")
|
||||
passthroughArgs, infoFlag, flagErr := scheduler_k3s.ExtractReportInfoFlag("--scheduler-k3s-annotations.", os.Args[2:])
|
||||
if flagErr != nil {
|
||||
err = flagErr
|
||||
break
|
||||
}
|
||||
args.Parse(passthroughArgs)
|
||||
appName := args.Arg(0)
|
||||
if *global {
|
||||
appName = "--global"
|
||||
}
|
||||
err = scheduler_k3s.CommandAnnotationsReport(appName, *format, *processType, *resourceType, infoFlag)
|
||||
case "autoscaling-auth:set":
|
||||
args := flag.NewFlagSet("scheduler-k3s:autoscaling-auth:set", flag.ExitOnError)
|
||||
global := args.Bool("global", false, "--global: set a global property")
|
||||
@@ -48,12 +65,15 @@ func main() {
|
||||
err = scheduler_k3s.CommandAutoscalingAuthSet(appName, trigger, *metadata, *global)
|
||||
case "autoscaling-auth:report":
|
||||
args := flag.NewFlagSet("scheduler-k3s:autoscaling-auth:report", flag.ExitOnError)
|
||||
global := args.Bool("global", false, "--global: show a global report")
|
||||
global := args.Bool("global", false, "--global: show the global report")
|
||||
includeMetadata := args.Bool("include-metadata", false, "--include-metadata: include metadata in the report")
|
||||
format := args.String("format", "stdout", "format: [ stdout | json ]")
|
||||
args.Parse(os.Args[2:])
|
||||
appName := args.Arg(0)
|
||||
err = scheduler_k3s.CommandAutoscalingAuthReport(appName, *format, *global, *includeMetadata)
|
||||
if *global {
|
||||
appName = "--global"
|
||||
}
|
||||
err = scheduler_k3s.CommandAutoscalingAuthReport(appName, *format, *includeMetadata)
|
||||
case "charts:set":
|
||||
args := flag.NewFlagSet("scheduler-k3s:charts:set", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
@@ -121,6 +141,23 @@ func main() {
|
||||
}
|
||||
|
||||
err = scheduler_k3s.CommandLabelsSet(appName, *processType, *resourceType, property, value)
|
||||
case "labels:report":
|
||||
args := flag.NewFlagSet("scheduler-k3s:labels:report", flag.ExitOnError)
|
||||
global := args.Bool("global", false, "--global: show the global report")
|
||||
format := args.String("format", "stdout", "format: [ stdout | json ]")
|
||||
processType := args.String("process-type", "", "--process-type: filter by process-type")
|
||||
resourceType := args.String("resource-type", "", "--resource-type: filter by resource-type")
|
||||
passthroughArgs, infoFlag, flagErr := scheduler_k3s.ExtractReportInfoFlag("--scheduler-k3s-labels.", os.Args[2:])
|
||||
if flagErr != nil {
|
||||
err = flagErr
|
||||
break
|
||||
}
|
||||
args.Parse(passthroughArgs)
|
||||
appName := args.Arg(0)
|
||||
if *global {
|
||||
appName = "--global"
|
||||
}
|
||||
err = scheduler_k3s.CommandLabelsReport(appName, *format, *processType, *resourceType, infoFlag)
|
||||
case "profiles:add":
|
||||
args := flag.NewFlagSet("scheduler-k3s:profiles:add", flag.ExitOnError)
|
||||
role := args.String("role", "worker", "role: [ server | worker ]")
|
||||
|
||||
@@ -124,26 +124,69 @@ func CommandAutoscalingAuthSet(appName string, trigger string, metadata map[stri
|
||||
}
|
||||
|
||||
// CommandAutoscalingAuthReport displays a scheduler-k3s autoscaling keda trigger authentication report for one or more apps
|
||||
func CommandAutoscalingAuthReport(appName string, format string, global bool, includeMetadata bool) error {
|
||||
if len(appName) == 0 && !global {
|
||||
return fmt.Errorf("Missing required app name or --global flag")
|
||||
}
|
||||
|
||||
if len(appName) > 0 && global {
|
||||
return fmt.Errorf("Cannot specify both app name and --global flag")
|
||||
}
|
||||
|
||||
if !global {
|
||||
if err := common.VerifyAppName(appName); err != nil {
|
||||
func CommandAutoscalingAuthReport(appName string, format string, includeMetadata bool) error {
|
||||
if len(appName) == 0 {
|
||||
apps, err := common.DokkuApps()
|
||||
if err != nil {
|
||||
if errors.Is(err, common.NoAppsExist) {
|
||||
common.LogWarn(err.Error())
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
for _, app := range apps {
|
||||
if err := ReportAutoscalingAuthSingleApp(app, format, includeMetadata); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(appName) > 0 {
|
||||
return ReportAutoscalingAuthSingleApp(appName, format, includeMetadata)
|
||||
return ReportAutoscalingAuthSingleApp(appName, format, includeMetadata)
|
||||
}
|
||||
|
||||
// CommandAnnotationsReport displays a scheduler-k3s annotations report for one or more apps
|
||||
func CommandAnnotationsReport(appName string, format string, processType string, resourceType string, infoFlag string) error {
|
||||
if len(appName) == 0 {
|
||||
apps, err := common.DokkuApps()
|
||||
if err != nil {
|
||||
if errors.Is(err, common.NoAppsExist) {
|
||||
common.LogWarn(err.Error())
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
for _, app := range apps {
|
||||
if err := ReportAnnotationsSingleApp(app, format, processType, resourceType, infoFlag); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return ReportAutoscalingAuthSingleApp("--global", format, includeMetadata)
|
||||
return ReportAnnotationsSingleApp(appName, format, processType, resourceType, infoFlag)
|
||||
}
|
||||
|
||||
// CommandLabelsReport displays a scheduler-k3s labels report for one or more apps
|
||||
func CommandLabelsReport(appName string, format string, processType string, resourceType string, infoFlag string) error {
|
||||
if len(appName) == 0 {
|
||||
apps, err := common.DokkuApps()
|
||||
if err != nil {
|
||||
if errors.Is(err, common.NoAppsExist) {
|
||||
common.LogWarn(err.Error())
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
for _, app := range apps {
|
||||
if err := ReportLabelsSingleApp(app, format, processType, resourceType, infoFlag); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return ReportLabelsSingleApp(appName, format, processType, resourceType, infoFlag)
|
||||
}
|
||||
|
||||
// CommandInitialize initializes a k3s cluster on the local server
|
||||
|
||||
88
tests/unit/scheduler-k3s-annotations.bats
Normal file
88
tests/unit/scheduler-k3s-annotations.bats
Normal file
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
load test_helper
|
||||
|
||||
setup() {
|
||||
global_setup
|
||||
dokku apps:create $TEST_APP >/dev/null 2>/dev/null || true
|
||||
}
|
||||
|
||||
teardown() {
|
||||
dokku --force apps:destroy $TEST_APP >/dev/null 2>/dev/null || true
|
||||
dokku --force apps:destroy ${TEST_APP}-2 >/dev/null 2>/dev/null || true
|
||||
for resource in deployment service pod cronjob job secret ingress serviceaccount; do
|
||||
dokku scheduler-k3s:annotations:set --global --resource-type "$resource" foo "" >/dev/null 2>/dev/null || true
|
||||
dokku scheduler-k3s:annotations:set --global --resource-type "$resource" bar "" >/dev/null 2>/dev/null || true
|
||||
done
|
||||
global_teardown
|
||||
}
|
||||
|
||||
@test "(scheduler-k3s:annotations:report) lists annotations after set, clears them after unset" {
|
||||
run /bin/bash -c "dokku scheduler-k3s:annotations:set $TEST_APP --resource-type deployment foo bar"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku scheduler-k3s:annotations:report $TEST_APP --format json | jq -r '.\"global.deployment.foo\"'"
|
||||
assert_success
|
||||
assert_output "bar"
|
||||
|
||||
run /bin/bash -c "dokku scheduler-k3s:annotations:report $TEST_APP"
|
||||
assert_success
|
||||
assert_output_contains "$TEST_APP annotations information"
|
||||
assert_output_contains "Annotation (global/deployment) foo:"
|
||||
assert_output_contains "bar"
|
||||
|
||||
run /bin/bash -c "dokku scheduler-k3s:annotations:report $TEST_APP --scheduler-k3s-annotations.global.deployment.foo"
|
||||
assert_success
|
||||
assert_output "bar"
|
||||
|
||||
run /bin/bash -c "dokku scheduler-k3s:annotations:set $TEST_APP --resource-type deployment foo"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku scheduler-k3s:annotations:report $TEST_APP --format json"
|
||||
assert_success
|
||||
assert_output "{}"
|
||||
}
|
||||
|
||||
@test "(scheduler-k3s:annotations:report) honours --process-type and --resource-type filters" {
|
||||
run /bin/bash -c "dokku scheduler-k3s:annotations:set $TEST_APP --resource-type deployment foo bar"
|
||||
assert_success
|
||||
run /bin/bash -c "dokku scheduler-k3s:annotations:set $TEST_APP --process-type web --resource-type deployment baz qux"
|
||||
assert_success
|
||||
run /bin/bash -c "dokku scheduler-k3s:annotations:set $TEST_APP --resource-type service alpha beta"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku scheduler-k3s:annotations:report $TEST_APP --resource-type deployment --format json | jq -r 'keys | sort | join(\",\")'"
|
||||
assert_success
|
||||
assert_output "global.deployment.foo,web.deployment.baz"
|
||||
|
||||
run /bin/bash -c "dokku scheduler-k3s:annotations:report $TEST_APP --process-type web --format json | jq -r 'keys | sort | join(\",\")'"
|
||||
assert_success
|
||||
assert_output "web.deployment.baz"
|
||||
|
||||
run /bin/bash -c "dokku scheduler-k3s:annotations:report $TEST_APP --process-type web --resource-type deployment --format json | jq -r '.\"web.deployment.baz\"'"
|
||||
assert_success
|
||||
assert_output "qux"
|
||||
}
|
||||
|
||||
@test "(scheduler-k3s:annotations:report) supports --global scope and no-arg multi-app loop" {
|
||||
run /bin/bash -c "dokku apps:create ${TEST_APP}-2"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku scheduler-k3s:annotations:set --global --resource-type deployment foo global-val"
|
||||
assert_success
|
||||
run /bin/bash -c "dokku scheduler-k3s:annotations:set $TEST_APP --resource-type deployment foo app1-val"
|
||||
assert_success
|
||||
run /bin/bash -c "dokku scheduler-k3s:annotations:set ${TEST_APP}-2 --resource-type deployment bar app2-val"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku scheduler-k3s:annotations:report --global --format json | jq -r '.\"global.deployment.foo\"'"
|
||||
assert_success
|
||||
assert_output "global-val"
|
||||
|
||||
run /bin/bash -c "dokku scheduler-k3s:annotations:report"
|
||||
assert_success
|
||||
assert_output_contains "$TEST_APP annotations information"
|
||||
assert_output_contains "${TEST_APP}-2 annotations information"
|
||||
assert_output_contains "app1-val"
|
||||
assert_output_contains "app2-val"
|
||||
}
|
||||
30
tests/unit/scheduler-k3s-autoscaling-auth.bats
Normal file
30
tests/unit/scheduler-k3s-autoscaling-auth.bats
Normal file
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
load test_helper
|
||||
|
||||
setup() {
|
||||
global_setup
|
||||
dokku apps:create $TEST_APP >/dev/null 2>/dev/null || true
|
||||
dokku apps:create ${TEST_APP}-2 >/dev/null 2>/dev/null || true
|
||||
}
|
||||
|
||||
teardown() {
|
||||
dokku scheduler-k3s:autoscaling-auth:set $TEST_APP datadog >/dev/null 2>/dev/null || true
|
||||
dokku scheduler-k3s:autoscaling-auth:set ${TEST_APP}-2 datadog >/dev/null 2>/dev/null || true
|
||||
dokku --force apps:destroy $TEST_APP >/dev/null 2>/dev/null || true
|
||||
dokku --force apps:destroy ${TEST_APP}-2 >/dev/null 2>/dev/null || true
|
||||
global_teardown
|
||||
}
|
||||
|
||||
@test "(scheduler-k3s:autoscaling-auth:report) no-arg loops all apps" {
|
||||
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:set $TEST_APP datadog --metadata apiKey=secret-1"
|
||||
assert_success
|
||||
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:set ${TEST_APP}-2 datadog --metadata apiKey=secret-2"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:report"
|
||||
assert_success
|
||||
assert_output_contains "$TEST_APP scheduler-k3s information"
|
||||
assert_output_contains "${TEST_APP}-2 scheduler-k3s information"
|
||||
assert_output_contains "Datadog:" 2
|
||||
}
|
||||
88
tests/unit/scheduler-k3s-labels.bats
Normal file
88
tests/unit/scheduler-k3s-labels.bats
Normal file
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
load test_helper
|
||||
|
||||
setup() {
|
||||
global_setup
|
||||
dokku apps:create $TEST_APP >/dev/null 2>/dev/null || true
|
||||
}
|
||||
|
||||
teardown() {
|
||||
dokku --force apps:destroy $TEST_APP >/dev/null 2>/dev/null || true
|
||||
dokku --force apps:destroy ${TEST_APP}-2 >/dev/null 2>/dev/null || true
|
||||
for resource in deployment service pod cronjob job secret ingress serviceaccount; do
|
||||
dokku scheduler-k3s:labels:set --global --resource-type "$resource" foo "" >/dev/null 2>/dev/null || true
|
||||
dokku scheduler-k3s:labels:set --global --resource-type "$resource" bar "" >/dev/null 2>/dev/null || true
|
||||
done
|
||||
global_teardown
|
||||
}
|
||||
|
||||
@test "(scheduler-k3s:labels:report) lists labels after set, clears them after unset" {
|
||||
run /bin/bash -c "dokku scheduler-k3s:labels:set $TEST_APP --resource-type deployment foo bar"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku scheduler-k3s:labels:report $TEST_APP --format json | jq -r '.\"global.deployment.foo\"'"
|
||||
assert_success
|
||||
assert_output "bar"
|
||||
|
||||
run /bin/bash -c "dokku scheduler-k3s:labels:report $TEST_APP"
|
||||
assert_success
|
||||
assert_output_contains "$TEST_APP labels information"
|
||||
assert_output_contains "Label (global/deployment) foo:"
|
||||
assert_output_contains "bar"
|
||||
|
||||
run /bin/bash -c "dokku scheduler-k3s:labels:report $TEST_APP --scheduler-k3s-labels.global.deployment.foo"
|
||||
assert_success
|
||||
assert_output "bar"
|
||||
|
||||
run /bin/bash -c "dokku scheduler-k3s:labels:set $TEST_APP --resource-type deployment foo"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku scheduler-k3s:labels:report $TEST_APP --format json"
|
||||
assert_success
|
||||
assert_output "{}"
|
||||
}
|
||||
|
||||
@test "(scheduler-k3s:labels:report) honours --process-type and --resource-type filters" {
|
||||
run /bin/bash -c "dokku scheduler-k3s:labels:set $TEST_APP --resource-type deployment foo bar"
|
||||
assert_success
|
||||
run /bin/bash -c "dokku scheduler-k3s:labels:set $TEST_APP --process-type web --resource-type deployment baz qux"
|
||||
assert_success
|
||||
run /bin/bash -c "dokku scheduler-k3s:labels:set $TEST_APP --resource-type service alpha beta"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku scheduler-k3s:labels:report $TEST_APP --resource-type deployment --format json | jq -r 'keys | sort | join(\",\")'"
|
||||
assert_success
|
||||
assert_output "global.deployment.foo,web.deployment.baz"
|
||||
|
||||
run /bin/bash -c "dokku scheduler-k3s:labels:report $TEST_APP --process-type web --format json | jq -r 'keys | sort | join(\",\")'"
|
||||
assert_success
|
||||
assert_output "web.deployment.baz"
|
||||
|
||||
run /bin/bash -c "dokku scheduler-k3s:labels:report $TEST_APP --process-type web --resource-type deployment --format json | jq -r '.\"web.deployment.baz\"'"
|
||||
assert_success
|
||||
assert_output "qux"
|
||||
}
|
||||
|
||||
@test "(scheduler-k3s:labels:report) supports --global scope and no-arg multi-app loop" {
|
||||
run /bin/bash -c "dokku apps:create ${TEST_APP}-2"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku scheduler-k3s:labels:set --global --resource-type deployment foo global-val"
|
||||
assert_success
|
||||
run /bin/bash -c "dokku scheduler-k3s:labels:set $TEST_APP --resource-type deployment foo app1-val"
|
||||
assert_success
|
||||
run /bin/bash -c "dokku scheduler-k3s:labels:set ${TEST_APP}-2 --resource-type deployment bar app2-val"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku scheduler-k3s:labels:report --global --format json | jq -r '.\"global.deployment.foo\"'"
|
||||
assert_success
|
||||
assert_output "global-val"
|
||||
|
||||
run /bin/bash -c "dokku scheduler-k3s:labels:report"
|
||||
assert_success
|
||||
assert_output_contains "$TEST_APP labels information"
|
||||
assert_output_contains "${TEST_APP}-2 labels information"
|
||||
assert_output_contains "app1-val"
|
||||
assert_output_contains "app2-val"
|
||||
}
|
||||
Reference in New Issue
Block a user