2022-09-19 15:24:54 +00:00
|
|
|
//
|
|
|
|
// DISCLAIMER
|
|
|
|
//
|
2023-02-20 11:20:01 +00:00
|
|
|
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
|
2022-09-19 15:24:54 +00:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
//
|
|
|
|
// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
|
|
|
//
|
|
|
|
|
|
|
|
package internal
|
|
|
|
|
|
|
|
import (
|
|
|
|
_ "embed"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"path"
|
|
|
|
"sort"
|
|
|
|
"text/template"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"sigs.k8s.io/yaml"
|
|
|
|
|
|
|
|
"github.com/arangodb/kube-arangodb/internal/md"
|
|
|
|
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
|
2022-12-22 09:49:51 +00:00
|
|
|
"github.com/arangodb/kube-arangodb/pkg/util/strings"
|
2022-09-19 15:24:54 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
//go:embed actions.yaml
|
|
|
|
var actions []byte
|
|
|
|
|
|
|
|
//go:embed actions.go.tmpl
|
|
|
|
var actionsGoTemplate []byte
|
|
|
|
|
|
|
|
//go:embed actions.register.go.tmpl
|
|
|
|
var actionsRegisterGoTemplate []byte
|
|
|
|
|
2023-08-15 18:22:15 +00:00
|
|
|
//go:embed actions.config.go.tmpl
|
|
|
|
var actionsConfigGoTemplate []byte
|
|
|
|
|
2022-09-19 15:24:54 +00:00
|
|
|
//go:embed actions.register.test.go.tmpl
|
|
|
|
var actionsRegisterTestGoTemplate []byte
|
|
|
|
|
|
|
|
type ActionsInput struct {
|
|
|
|
DefaultTimeout meta.Duration `json:"default_timeout"`
|
|
|
|
|
|
|
|
Actions map[string]Action `json:"actions"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i ActionsInput) Keys() []string {
|
|
|
|
z := make([]string, 0, len(i.Actions))
|
|
|
|
|
|
|
|
for k := range i.Actions {
|
|
|
|
z = append(z, k)
|
|
|
|
}
|
|
|
|
|
|
|
|
sort.Strings(z)
|
|
|
|
|
|
|
|
return z
|
|
|
|
}
|
|
|
|
|
2023-02-20 11:20:01 +00:00
|
|
|
func (i ActionsInput) Optionals() map[string]bool {
|
|
|
|
r := map[string]bool{}
|
|
|
|
|
|
|
|
for k, v := range i.Actions {
|
|
|
|
r[k] = v.Optional
|
|
|
|
}
|
|
|
|
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
2022-09-19 15:24:54 +00:00
|
|
|
type Scopes struct {
|
|
|
|
Normal, High, Resource bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s Scopes) String() string {
|
|
|
|
q := make([]string, 0, 3)
|
|
|
|
if s.High {
|
|
|
|
q = append(q, "High")
|
|
|
|
}
|
|
|
|
if s.Normal {
|
|
|
|
q = append(q, "Normal")
|
|
|
|
}
|
|
|
|
if s.Resource {
|
|
|
|
q = append(q, "Resource")
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(q) > 2 {
|
|
|
|
q = []string{
|
|
|
|
strings.Join(q[0:len(q)-1], ", "),
|
|
|
|
q[len(q)-1],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return strings.Join(q, " and ")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i ActionsInput) Scopes() map[string]Scopes {
|
|
|
|
r := map[string]Scopes{}
|
|
|
|
for k, a := range i.Actions {
|
|
|
|
r[k] = Scopes{
|
|
|
|
Normal: a.InScope("normal"),
|
|
|
|
High: a.InScope("high"),
|
|
|
|
Resource: a.InScope("resource"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i ActionsInput) StartFailureGracePeriods() map[string]string {
|
|
|
|
r := map[string]string{}
|
|
|
|
for k, a := range i.Actions {
|
|
|
|
if a.StartupFailureGracePeriod == nil {
|
|
|
|
r[k] = ""
|
|
|
|
} else {
|
|
|
|
r[k] = fmt.Sprintf("%d * time.Second", a.StartupFailureGracePeriod.Duration/time.Second)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
2022-11-03 13:39:46 +00:00
|
|
|
func (i ActionsInput) Internal() map[string]string {
|
|
|
|
r := map[string]string{}
|
|
|
|
|
|
|
|
for a, spec := range i.Actions {
|
|
|
|
if spec.IsInternal {
|
|
|
|
r[a] = "true"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
2022-09-19 15:24:54 +00:00
|
|
|
func (i ActionsInput) HighestScopes() map[string]string {
|
|
|
|
r := map[string]string{}
|
|
|
|
for k, a := range i.Scopes() {
|
|
|
|
if a.High {
|
|
|
|
r[k] = "High"
|
|
|
|
} else if a.Normal {
|
|
|
|
r[k] = "Normal"
|
|
|
|
} else if a.Resource {
|
|
|
|
r[k] = "Resource"
|
|
|
|
} else {
|
|
|
|
r[k] = "Unknown"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i ActionsInput) Descriptions() map[string]string {
|
|
|
|
r := map[string]string{}
|
|
|
|
for k, a := range i.Actions {
|
|
|
|
r[k] = a.Description
|
|
|
|
}
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i ActionsInput) Timeouts() map[string]string {
|
|
|
|
r := map[string]string{}
|
|
|
|
for k, a := range i.Actions {
|
|
|
|
if a.Timeout != nil {
|
|
|
|
r[k] = fmt.Sprintf("%d * time.Second // %s", a.Timeout.Duration/time.Second, a.Timeout.Duration.String())
|
|
|
|
} else {
|
|
|
|
r[k] = "ActionsDefaultTimeout"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
2023-08-15 18:22:15 +00:00
|
|
|
func (i ActionsInput) Configurable() []string {
|
|
|
|
var r []string
|
|
|
|
for k, a := range i.Actions {
|
|
|
|
if a.Configurable {
|
|
|
|
r = append(r, k)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
2022-09-19 15:24:54 +00:00
|
|
|
type Action struct {
|
|
|
|
Timeout *meta.Duration `json:"timeout,omitempty"`
|
|
|
|
StartupFailureGracePeriod *meta.Duration `json:"startupFailureGracePeriod,omitempty"`
|
|
|
|
|
|
|
|
Scopes []string `json:"scopes,omitempty"`
|
|
|
|
|
|
|
|
Description string `json:"description"`
|
|
|
|
|
|
|
|
Enterprise bool `json:"enterprise"`
|
2022-11-03 13:39:46 +00:00
|
|
|
|
|
|
|
IsInternal bool `json:"isInternal"`
|
2023-02-20 11:20:01 +00:00
|
|
|
|
|
|
|
Optional bool `json:"optional"`
|
2023-08-15 18:22:15 +00:00
|
|
|
|
|
|
|
Configurable bool `json:"configurable"`
|
2022-09-19 15:24:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (a Action) InScope(scope string) bool {
|
|
|
|
if a.Scopes == nil {
|
|
|
|
return strings.Title(scope) == "Normal"
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, x := range a.Scopes {
|
|
|
|
if strings.Title(scope) == strings.Title(x) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func RenderActions(root string) error {
|
|
|
|
var in ActionsInput
|
|
|
|
|
|
|
|
if err := yaml.Unmarshal(actions, &in); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
actions := path.Join(root, "pkg", "apis", "deployment", "v1", "actions.generated.go")
|
|
|
|
|
|
|
|
out, err := os.OpenFile(actions, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
i, err := template.New("actions").Parse(string(actionsGoTemplate))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := i.Execute(out, map[string]interface{}{
|
|
|
|
"actions": in.Keys(),
|
|
|
|
"scopes": in.Scopes(),
|
|
|
|
"highestScopes": in.HighestScopes(),
|
2022-11-03 13:39:46 +00:00
|
|
|
"internal": in.Internal(),
|
2022-09-19 15:24:54 +00:00
|
|
|
"timeouts": in.Timeouts(),
|
|
|
|
"descriptions": in.Descriptions(),
|
2023-02-20 11:20:01 +00:00
|
|
|
"optionals": in.Optionals(),
|
2022-09-19 15:24:54 +00:00
|
|
|
"defaultTimeout": fmt.Sprintf("%d * time.Second // %s", in.DefaultTimeout.Duration/time.Second, in.DefaultTimeout.Duration.String()),
|
|
|
|
}); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := out.Close(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
actions := path.Join(root, "pkg", "deployment", "reconcile", "action.register.generated.go")
|
|
|
|
|
|
|
|
out, err := os.OpenFile(actions, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
i, err := template.New("actions").Parse(string(actionsRegisterGoTemplate))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := i.Execute(out, map[string]interface{}{
|
|
|
|
"actions": in.Keys(),
|
|
|
|
"startupFailureGracePeriods": in.StartFailureGracePeriods(),
|
|
|
|
}); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := out.Close(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-15 18:22:15 +00:00
|
|
|
{
|
|
|
|
actions := path.Join(root, "pkg", "deployment", "reconcile", "action.config.generated.go")
|
|
|
|
|
|
|
|
out, err := os.OpenFile(actions, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
i, err := template.New("actions").Parse(string(actionsConfigGoTemplate))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := i.Execute(out, map[string]interface{}{
|
|
|
|
"configurable": in.Configurable(),
|
|
|
|
}); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := out.Close(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-19 15:24:54 +00:00
|
|
|
{
|
|
|
|
actions := path.Join(root, "pkg", "deployment", "reconcile", "action.register.generated_test.go")
|
|
|
|
|
|
|
|
out, err := os.OpenFile(actions, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
i, err := template.New("actions").Parse(string(actionsRegisterTestGoTemplate))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := i.Execute(out, map[string]interface{}{
|
|
|
|
"actions": in.Keys(),
|
|
|
|
"startupFailureGracePeriods": in.StartFailureGracePeriods(),
|
2022-11-03 13:39:46 +00:00
|
|
|
"internal": in.Internal(),
|
2023-02-20 11:20:01 +00:00
|
|
|
"optional": in.Optionals(),
|
2022-09-19 15:24:54 +00:00
|
|
|
}); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := out.Close(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
actions := path.Join(root, "docs", "generated", "actions.md")
|
|
|
|
|
|
|
|
action := md.NewColumn("Action", md.ColumnCenterAlign)
|
|
|
|
timeout := md.NewColumn("Timeout", md.ColumnCenterAlign)
|
|
|
|
description := md.NewColumn("Description", md.ColumnCenterAlign)
|
2022-11-03 13:39:46 +00:00
|
|
|
internal := md.NewColumn("Internal", md.ColumnCenterAlign)
|
2023-02-20 11:20:01 +00:00
|
|
|
optional := md.NewColumn("Optional", md.ColumnCenterAlign)
|
2022-09-19 15:24:54 +00:00
|
|
|
edition := md.NewColumn("Edition", md.ColumnCenterAlign)
|
|
|
|
t := md.NewTable(
|
|
|
|
action,
|
2022-11-03 13:39:46 +00:00
|
|
|
internal,
|
2022-09-19 15:24:54 +00:00
|
|
|
timeout,
|
2023-02-20 11:20:01 +00:00
|
|
|
optional,
|
2022-09-19 15:24:54 +00:00
|
|
|
edition,
|
|
|
|
description,
|
|
|
|
)
|
|
|
|
|
|
|
|
for _, k := range in.Keys() {
|
|
|
|
a := in.Actions[k]
|
|
|
|
v := in.DefaultTimeout.Duration.String()
|
|
|
|
if t := a.Timeout; t != nil {
|
|
|
|
v = t.Duration.String()
|
|
|
|
}
|
|
|
|
|
|
|
|
vr := "Community & Enterprise"
|
|
|
|
if a.Enterprise {
|
|
|
|
vr = "Enterprise Only"
|
|
|
|
}
|
2022-11-03 13:39:46 +00:00
|
|
|
int := "yes"
|
|
|
|
if !a.IsInternal {
|
|
|
|
int = "no"
|
|
|
|
}
|
2023-02-20 11:20:01 +00:00
|
|
|
opt := "yes"
|
|
|
|
if !a.Optional {
|
|
|
|
opt = "no"
|
|
|
|
}
|
2022-09-19 15:24:54 +00:00
|
|
|
|
|
|
|
if err := t.AddRow(map[md.Column]string{
|
|
|
|
action: k,
|
|
|
|
timeout: v,
|
|
|
|
description: a.Description,
|
|
|
|
edition: vr,
|
2023-02-20 11:20:01 +00:00
|
|
|
optional: opt,
|
2022-11-03 13:39:46 +00:00
|
|
|
internal: int,
|
2022-09-19 15:24:54 +00:00
|
|
|
}); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
timeouts := api.ActionTimeouts{}
|
|
|
|
|
|
|
|
for _, k := range in.Keys() {
|
|
|
|
a := in.Actions[k]
|
|
|
|
if a.Timeout != nil {
|
|
|
|
timeouts[api.ActionType(k)] = api.NewTimeout(a.Timeout.Duration)
|
|
|
|
} else {
|
|
|
|
timeouts[api.ActionType(k)] = api.NewTimeout(in.DefaultTimeout.Duration)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
d, err := yaml.Marshal(map[string]interface{}{
|
|
|
|
"spec": map[string]interface{}{
|
|
|
|
"timeouts": map[string]interface{}{
|
|
|
|
"actions": timeouts,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-02-24 08:29:35 +00:00
|
|
|
if err := md.ReplaceSectionsInFile(actions, map[string]string{
|
|
|
|
"actionsTable": md.WrapWithNewLines(t.Render()),
|
|
|
|
"actionsModYaml": md.WrapWithNewLines(md.WrapWithYAMLSegment(string(d))),
|
2022-09-19 15:24:54 +00:00
|
|
|
}); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|