feat: port apply command from influxdb (#160)

This commit is contained in:
Daniel Moran
2021-06-30 14:47:23 -04:00
committed by GitHub
parent d7b2983dd4
commit a3f36a9821
8 changed files with 1037 additions and 8 deletions

729
clients/apply/apply.go Normal file
View File

@ -0,0 +1,729 @@
package apply
import (
"context"
"encoding/json"
"errors"
"fmt"
"reflect"
"strconv"
"strings"
"time"
"github.com/influxdata/influx-cli/v2/api"
"github.com/influxdata/influx-cli/v2/clients"
"github.com/influxdata/influx-cli/v2/pkg/influxid"
"github.com/influxdata/influx-cli/v2/pkg/template"
)
type Client struct {
clients.CLI
api.TemplatesApi
api.OrganizationsApi
}
type Params struct {
OrgId string
OrgName string
StackId string
Sources []TemplateSource
Recursive bool
Secrets map[string]string
EnvVars map[string]string
Filters []ResourceFilter
Force bool
OverwriteConflicts bool
Quiet bool
RenderTableColors bool
RenderTableBorders bool
}
type ResourceFilter struct {
Kind string
Name *string
}
func (c Client) Apply(ctx context.Context, params *Params) error {
if params.OrgId == "" && params.OrgName == "" && c.ActiveConfig.Org == "" {
return clients.ErrMustSpecifyOrg
}
orgID := params.OrgId
if orgID == "" {
orgName := params.OrgName
if orgName == "" {
orgName = c.ActiveConfig.Org
}
orgs, err := c.GetOrgs(ctx).Org(orgName).Execute()
if err != nil {
return fmt.Errorf("failed to get ID for org %q: %w", orgName, err)
}
if len(orgs.GetOrgs()) == 0 {
return fmt.Errorf("no orgs found with name %q: %w", orgName, err)
}
orgID = orgs.GetOrgs()[0].GetId()
}
templates, err := readTemplates(ctx, params.Sources)
if err != nil {
return err
}
req := api.TemplateApply{
DryRun: true,
OrgID: orgID,
Templates: templates,
EnvRefs: params.EnvVars,
Secrets: params.Secrets,
Actions: make([]api.TemplateApplyAction, len(params.Filters)),
}
if params.StackId != "" {
req.StackID = &params.StackId
}
for i, f := range params.Filters {
req.Actions[i].Action = api.TEMPLATEAPPLYACTIONKIND_SKIP_KIND
if f.Name != nil {
req.Actions[i].Action = api.TEMPLATEAPPLYACTIONKIND_SKIP_RESOURCE
}
req.Actions[i].Properties = api.TemplateApplyActionProperties{
Kind: f.Kind,
ResourceTemplateName: f.Name,
}
}
// Initial dry-run to make the server summarize the template & report any missing env/secret values.
res, err := c.ApplyTemplate(ctx).TemplateApply(req).Execute()
if err != nil {
return fmt.Errorf("failed to check template impact: %w", err)
}
if c.StdIO.InputIsInteractive() && (len(res.Summary.MissingEnvRefs) > 0 || len(res.Summary.MissingSecrets) > 0) {
for _, e := range res.Summary.MissingEnvRefs {
val, err := c.StdIO.GetStringInput(fmt.Sprintf("Please provide environment reference value for key %s", e), "")
if err != nil {
return err
}
req.EnvRefs[e] = val
}
for _, s := range res.Summary.MissingSecrets {
val, err := c.StdIO.GetSecret(fmt.Sprintf("Please provide secret value for key %s (optional, press enter to skip)", s), 0)
if err != nil {
return err
}
if val != "" {
req.Secrets[s] = val
}
}
// 2nd dry-run to see the diff after resolving all env/secret values.
res, err = c.ApplyTemplate(ctx).TemplateApply(req).Execute()
if err != nil {
return fmt.Errorf("failed to check template impact: %w", err)
}
}
if !params.Quiet {
if err := c.printDiff(res.Diff, params); err != nil {
return err
}
}
if c.StdIO.InputIsInteractive() && !params.Force {
if confirmed := c.StdIO.GetConfirm("Confirm application of the above resources"); !confirmed {
return errors.New("aborted application of template")
}
}
if !params.OverwriteConflicts && hasConflicts(res.Diff) {
return errors.New("template has conflicts with existing resources and cannot safely apply")
}
// Flip the dry-run flag and apply the template.
req.DryRun = false
res, err = c.ApplyTemplate(ctx).TemplateApply(req).Execute()
if err != nil {
return fmt.Errorf("failed to apply template: %w", err)
}
params.StackId = res.StackID
if !params.Quiet {
if err := c.printSummary(res.Summary, params); err != nil {
return err
}
}
return nil
}
func readTemplates(ctx context.Context, sources []TemplateSource) ([]api.TemplateApplyTemplate, error) {
templates := make([]api.TemplateApplyTemplate, 0, len(sources))
for _, source := range sources {
tmpl, err := source.Read(ctx)
if err != nil {
return nil, err
}
// We always send the templates as JSON.
tmpl.ContentType = "json"
templates = append(templates, tmpl)
}
return templates, nil
}
func (c Client) printDiff(diff api.TemplateSummaryDiff, params *Params) error {
if c.PrintAsJSON {
return c.PrintJSON(diff)
}
newDiffPrinter := func(title string, headers []string) *template.DiffPrinter {
return template.NewDiffPrinter(c.StdIO, params.RenderTableColors, params.RenderTableBorders).
Title(title).
SetHeaders(append([]string{"Metadata Name", "ID", "Resource Name"}, headers...)...)
}
if labels := diff.Labels; len(labels) > 0 {
printer := newDiffPrinter("Labels", []string{"Color", "Description"})
buildRow := func(metaName string, id string, lf api.TemplateSummaryDiffLabelFields) []string {
var desc string
if lf.Description != nil {
desc = *lf.Description
}
return []string{metaName, id, lf.Name, lf.Color, desc}
}
for _, l := range labels {
var oldRow, newRow []string
hexId := influxid.ID(l.Id).String()
if l.Old != nil {
oldRow = buildRow(l.TemplateMetaName, hexId, *l.Old)
}
if l.New != nil {
newRow = buildRow(l.TemplateMetaName, hexId, *l.New)
}
printer.AppendDiff(oldRow, newRow)
}
printer.Render()
_, _ = c.StdIO.Write([]byte("\n"))
}
if bkts := diff.Buckets; len(bkts) > 0 {
printer := newDiffPrinter("Buckets", []string{"Retention Period", "Description", "Schema Type", "Num Measurements"})
buildRow := func(metaName string, id string, bf api.TemplateSummaryDiffBucketFields) []string {
var desc string
if bf.Description != nil {
desc = *bf.Description
}
var retention time.Duration
if len(bf.RetentionRules) > 0 {
retention = time.Duration(bf.RetentionRules[0].EverySeconds) * time.Second
}
schemaType := api.SCHEMATYPE_IMPLICIT
if bf.SchemaType != nil {
schemaType = *bf.SchemaType
}
return []string{metaName, id, bf.Name, retention.String(), desc, schemaType.String(), strconv.Itoa(len(bf.MeasurementSchemas))}
}
for _, b := range bkts {
var oldRow, newRow []string
hexId := influxid.ID(b.Id).String()
if b.Old != nil {
oldRow = buildRow(b.TemplateMetaName, hexId, *b.Old)
}
if b.New != nil {
newRow = buildRow(b.TemplateMetaName, hexId, *b.New)
}
printer.AppendDiff(oldRow, newRow)
}
printer.Render()
_, _ = c.StdIO.Write([]byte("\n"))
}
if checks := diff.Checks; len(checks) > 0 {
printer := newDiffPrinter("Checks", []string{"Description"})
buildRow := func(metaName string, id string, cf api.TemplateSummaryDiffCheckFields) []string {
var desc string
if cf.Description != nil {
desc = *cf.Description
}
return []string{metaName, id, cf.Name, desc}
}
for _, c := range checks {
var oldRow, newRow []string
hexId := influxid.ID(c.Id).String()
if c.Old != nil {
oldRow = buildRow(c.TemplateMetaName, hexId, *c.Old)
}
if c.New != nil {
newRow = buildRow(c.TemplateMetaName, hexId, *c.New)
}
printer.AppendDiff(oldRow, newRow)
}
printer.Render()
_, _ = c.StdIO.Write([]byte("\n"))
}
if dashboards := diff.Dashboards; len(dashboards) > 0 {
printer := newDiffPrinter("Dashboards", []string{"Description", "Num Charts"})
buildRow := func(metaName string, id string, df api.TemplateSummaryDiffDashboardFields) []string {
var desc string
if df.Description != nil {
desc = *df.Description
}
return []string{metaName, id, df.Name, desc, strconv.Itoa(len(df.Charts))}
}
for _, d := range dashboards {
var oldRow, newRow []string
hexId := influxid.ID(d.Id).String()
if d.Old != nil {
oldRow = buildRow(d.TemplateMetaName, hexId, *d.Old)
}
if d.New != nil {
newRow = buildRow(d.TemplateMetaName, hexId, *d.New)
}
printer.AppendDiff(oldRow, newRow)
}
printer.Render()
_, _ = c.StdIO.Write([]byte("\n"))
}
if endpoints := diff.NotificationEndpoints; len(endpoints) > 0 {
printer := newDiffPrinter("Notification Endpoints", nil)
buildRow := func(metaName string, id string, nef api.TemplateSummaryDiffNotificationEndpointFields) []string {
return []string{metaName, id, nef.Name}
}
for _, e := range endpoints {
var oldRow, newRow []string
hexId := influxid.ID(e.Id).String()
if e.Old != nil {
oldRow = buildRow(e.TemplateMetaName, hexId, *e.Old)
}
if e.New != nil {
newRow = buildRow(e.TemplateMetaName, hexId, *e.New)
}
printer.AppendDiff(oldRow, newRow)
}
printer.Render()
_, _ = c.StdIO.Write([]byte("\n"))
}
if rules := diff.NotificationRules; len(rules) > 0 {
printer := newDiffPrinter("Notification Rules", []string{"Description", "Every", "Offset", "Endpoint Name", "Endpoint ID", "Endpoint Type"})
buildRow := func(metaName string, id string, nrf api.TemplateSummaryDiffNotificationRuleFields) []string {
var desc string
if nrf.Description != nil {
desc = *nrf.Description
}
eid := influxid.ID(nrf.EndpointID).String()
return []string{metaName, id, nrf.Name, desc, nrf.Every, nrf.Offset, nrf.EndpointName, eid, nrf.EndpointType}
}
for _, r := range rules {
var oldRow, newRow []string
hexId := influxid.ID(r.Id).String()
if r.Old != nil {
oldRow = buildRow(r.TemplateMetaName, hexId, *r.Old)
}
if r.New != nil {
newRow = buildRow(r.TemplateMetaName, hexId, *r.New)
}
printer.AppendDiff(oldRow, newRow)
}
printer.Render()
_, _ = c.StdIO.Write([]byte("\n"))
}
if teles := diff.TelegrafConfigs; len(teles) > 0 {
printer := newDiffPrinter("Telegraf Configurations", []string{"Description"})
buildRow := func(metaName string, id string, tc api.TemplateSummaryTelegrafConfig) []string {
var desc string
if tc.Description != nil {
desc = *tc.Description
}
return []string{metaName, id, tc.Name, desc}
}
for _, t := range teles {
var oldRow, newRow []string
hexId := influxid.ID(t.Id).String()
if t.Old != nil {
oldRow = buildRow(t.TemplateMetaName, hexId, *t.Old)
}
if t.New != nil {
newRow = buildRow(t.TemplateMetaName, hexId, *t.New)
}
printer.AppendDiff(oldRow, newRow)
}
printer.Render()
_, _ = c.StdIO.Write([]byte("\n"))
}
if tasks := diff.Tasks; len(tasks) > 0 {
printer := newDiffPrinter("Tasks", []string{"Description", "Cycle"})
buildRow := func(metaName string, id string, tf api.TemplateSummaryDiffTaskFields) []string {
var desc string
if tf.Description != nil {
desc = *tf.Description
}
var timing string
if tf.Cron != nil {
timing = *tf.Cron
} else {
offset := time.Duration(0).String()
if tf.Offset != nil {
offset = *tf.Offset
}
// If `cron` isn't set, `every` must be set
timing = fmt.Sprintf("every: %s offset: %s", *tf.Every, offset)
}
return []string{metaName, id, tf.Name, desc, timing}
}
for _, t := range tasks {
var oldRow, newRow []string
hexId := influxid.ID(t.Id).String()
if t.Old != nil {
oldRow = buildRow(t.TemplateMetaName, hexId, *t.Old)
}
if t.New != nil {
newRow = buildRow(t.TemplateMetaName, hexId, *t.New)
}
printer.AppendDiff(oldRow, newRow)
}
printer.Render()
_, _ = c.StdIO.Write([]byte("\n"))
}
if vars := diff.Variables; len(vars) > 0 {
printer := newDiffPrinter("Variables", []string{"Description", "Arg Type", "Arg Values"})
buildRow := func(metaName string, id string, vf api.TemplateSummaryDiffVariableFields) []string {
var desc, argType string
if vf.Description != nil {
desc = *vf.Description
}
if vf.Args != nil {
argType = vf.Args.Type
}
return []string{metaName, id, vf.Name, desc, argType, sprintVarArgs(vf.Args)}
}
for _, v := range vars {
var oldRow, newRow []string
hexId := influxid.ID(v.Id).String()
if v.Old != nil {
oldRow = buildRow(v.TemplateMetaName, hexId, *v.Old)
}
if v.New != nil {
newRow = buildRow(v.TemplateMetaName, hexId, *v.New)
}
printer.AppendDiff(oldRow, newRow)
}
printer.Render()
_, _ = c.StdIO.Write([]byte("\n"))
}
if mappings := diff.LabelMappings; len(mappings) > 0 {
printer := template.NewDiffPrinter(c.StdIO, params.RenderTableColors, params.RenderTableBorders).
Title("Label Associations").
SetHeaders("Resource Type", "Resource Meta Name", "Resource Name", "Resource ID", "Label Package Name", "Label Name", "Label ID")
for _, m := range mappings {
resId := influxid.ID(m.ResourceID).String()
labelId := influxid.ID(m.LabelID).String()
row := []string{m.ResourceType, m.ResourceName, resId, m.LabelTemplateMetaName, m.LabelName, labelId}
switch m.StateStatus {
case "new":
printer.AppendDiff(nil, row)
case "remove":
printer.AppendDiff(row, nil)
default:
printer.AppendDiff(row, row)
}
}
printer.Render()
}
return nil
}
func sprintVarArgs(args *api.TemplateSummaryVariableArgs) string {
if args == nil {
return "<nil>"
}
switch args.Type {
case "map":
b, err := json.Marshal(args.Values)
if err != nil {
return "{}"
}
return string(b)
case "constant":
values, ok := args.Values.([]interface{})
if !ok {
return "[]"
}
var out []string
for _, v := range values {
out = append(out, fmt.Sprintf("%q", v))
}
return fmt.Sprintf("[%s]", strings.Join(out, " "))
case "query":
values, ok := args.Values.(map[string]interface{})
if !ok {
return ""
}
qVal, ok := values["query"]
if !ok {
return ""
}
lVal, ok := values["language"]
if !ok {
return ""
}
return fmt.Sprintf("language=%q query=%q", lVal, qVal)
default:
}
return "unknown variable argument"
}
func hasConflicts(diff api.TemplateSummaryDiff) bool {
for _, l := range diff.Labels {
if l.StateStatus != "new" && l.Old != nil && l.New != nil && !reflect.DeepEqual(l.Old, l.New) {
return true
}
}
for _, b := range diff.Buckets {
if b.StateStatus != "new" && b.Old != nil && b.New != nil && !reflect.DeepEqual(b.Old, b.New) {
return true
}
}
for _, c := range diff.Checks {
if c.StateStatus != "new" && c.Old != nil && c.New != nil && !reflect.DeepEqual(c.Old, c.New) {
return true
}
}
for _, d := range diff.Dashboards {
if d.StateStatus != "new" && d.Old != nil && d.New != nil && !reflect.DeepEqual(d.Old, d.New) {
return true
}
}
for _, e := range diff.NotificationEndpoints {
if e.StateStatus != "new" && e.Old != nil && e.New != nil && !reflect.DeepEqual(e.Old, e.New) {
return true
}
}
for _, r := range diff.NotificationRules {
if r.StateStatus != "new" && r.Old != nil && r.New != nil && !reflect.DeepEqual(r.Old, r.New) {
return true
}
}
for _, t := range diff.TelegrafConfigs {
if t.StateStatus != "new" && t.Old != nil && t.New != nil && !reflect.DeepEqual(t.Old, t.New) {
return true
}
}
for _, t := range diff.Tasks {
if t.StateStatus != "new" && t.Old != nil && t.New != nil && !reflect.DeepEqual(t.Old, t.New) {
return true
}
}
for _, v := range diff.Variables {
if v.StateStatus != "new" && v.Old != nil && v.New != nil && !reflect.DeepEqual(v.Old, v.New) {
return true
}
}
return false
}
func (c Client) printSummary(summary api.TemplateSummaryResources, params *Params) error {
if c.PrintAsJSON {
return c.PrintJSON(struct {
StackID string `json:"stackID"`
Summary api.TemplateSummaryResources
}{
StackID: params.StackId,
Summary: summary,
})
}
newPrinter := func(title string, headers []string) *template.TablePrinter {
return template.NewTablePrinter(c.StdIO, params.RenderTableColors, params.RenderTableBorders).
Title(title).
SetHeaders(append([]string{"Package Name", "ID", "Resource Name"}, headers...)...)
}
if labels := summary.Labels; len(labels) > 0 {
printer := newPrinter("LABELS", []string{"Description", "Color"})
for _, l := range labels {
id := influxid.ID(l.Id).String()
var desc string
if l.Properties.Description != nil {
desc = *l.Properties.Description
}
printer.Append([]string{l.TemplateMetaName, id, l.Name, desc, l.Properties.Color})
}
printer.Render()
_, _ = c.StdIO.Write([]byte("\n"))
}
if buckets := summary.Buckets; len(buckets) > 0 {
printer := newPrinter("BUCKETS", []string{"Retention", "Description", "Schema Type"})
for _, b := range buckets {
id := influxid.ID(b.Id).String()
var desc string
if b.Description != nil {
desc = *b.Description
}
rp := "inf"
if b.RetentionPeriod != 0 {
rp = time.Duration(b.RetentionPeriod).String()
}
schemaType := api.SCHEMATYPE_IMPLICIT
if b.SchemaType != nil {
schemaType = *b.SchemaType
}
printer.Append([]string{b.TemplateMetaName, id, b.Name, rp, desc, schemaType.String()})
}
printer.Render()
_, _ = c.StdIO.Write([]byte("\n"))
}
if checks := summary.Checks; len(checks) > 0 {
printer := newPrinter("CHECKS", []string{"Description"})
for _, c := range checks {
id := influxid.ID(c.Id).String()
var desc string
if c.Description != nil {
desc = *c.Description
}
printer.Append([]string{c.TemplateMetaName, id, c.Name, desc})
}
printer.Render()
_, _ = c.StdIO.Write([]byte("\n"))
}
if dashboards := summary.Dashboards; len(dashboards) > 0 {
printer := newPrinter("DASHBOARDS", []string{"Description"})
for _, d := range dashboards {
id := influxid.ID(d.Id).String()
var desc string
if d.Description != nil {
desc = *d.Description
}
printer.Append([]string{d.TemplateMetaName, id, d.Name, desc})
}
printer.Render()
_, _ = c.StdIO.Write([]byte("\n"))
}
if endpoints := summary.NotificationEndpoints; len(endpoints) > 0 {
printer := newPrinter("NOTIFICATION ENDPOINTS", []string{"Description", "Status"})
for _, e := range endpoints {
id := influxid.ID(e.Id).String()
var desc string
if e.Description != nil {
desc = *e.Description
}
printer.Append([]string{e.TemplateMetaName, id, e.Name, desc, e.Status})
}
printer.Render()
_, _ = c.StdIO.Write([]byte("\n"))
}
if rules := summary.NotificationRules; len(rules) > 0 {
printer := newPrinter("NOTIFICATION RULES", []string{"Description", "Every", "Offset", "Endpoint Name", "Endpoint ID", "Endpoint Type"})
for _, r := range rules {
id := influxid.ID(r.Id).String()
eid := influxid.ID(r.EndpointID).String()
var desc string
if r.Description != nil {
desc = *r.Description
}
printer.Append([]string{r.TemplateMetaName, id, r.Name, desc, r.Every, r.Offset, r.EndpointTemplateMetaName, eid, r.EndpointType})
}
printer.Render()
_, _ = c.StdIO.Write([]byte("\n"))
}
if tasks := summary.Tasks; len(tasks) > 0 {
printer := newPrinter("TASKS", []string{"Description", "Cycle"})
for _, t := range tasks {
id := influxid.ID(t.Id).String()
var desc string
if t.Description != nil {
desc = *t.Description
}
var timing string
if t.Cron != nil {
timing = *t.Cron
} else {
offset := time.Duration(0).String()
if t.Offset != nil {
offset = *t.Offset
}
// If `cron` isn't set, `every` must be set
timing = fmt.Sprintf("every: %s offset: %s", *t.Every, offset)
}
printer.Append([]string{t.TemplateMetaName, id, t.Name, desc, timing})
}
printer.Render()
_, _ = c.StdIO.Write([]byte("\n"))
}
if teles := summary.TelegrafConfigs; len(teles) > 0 {
printer := newPrinter("TELEGRAF CONFIGS", []string{"Description"})
for _, t := range teles {
var desc string
if t.TelegrafConfig.Description != nil {
desc = *t.TelegrafConfig.Description
}
printer.Append([]string{t.TemplateMetaName, t.TelegrafConfig.Id, t.TelegrafConfig.Name, desc})
}
printer.Render()
_, _ = c.StdIO.Write([]byte("\n"))
}
if vars := summary.Variables; len(vars) > 0 {
printer := newPrinter("VARIABLES", []string{"Description", "Arg Type", "Arg Values"})
for _, v := range vars {
id := influxid.ID(v.Id).String()
var desc string
if v.Description != nil {
desc = *v.Description
}
var argType string
if v.Arguments != nil {
argType = v.Arguments.Type
}
printer.Append([]string{v.TemplateMetaName, id, v.Name, desc, argType, sprintVarArgs(v.Arguments)})
}
printer.Render()
_, _ = c.StdIO.Write([]byte("\n"))
}
if mappings := summary.LabelMappings; len(mappings) > 0 {
printer := template.NewTablePrinter(c.StdIO, params.RenderTableColors, params.RenderTableBorders).
Title("LABEL ASSOCIATIONS").
SetHeaders("Resource Type", "Resource Name", "Resource ID", "Label Name", "Label ID")
for _, m := range mappings {
rid := influxid.ID(m.ResourceID).String()
lid := influxid.ID(m.LabelID).String()
printer.Append([]string{m.ResourceType, m.ResourceName, rid, m.LabelName, lid})
}
printer.Render()
_, _ = c.StdIO.Write([]byte("\n"))
}
if secrets := summary.MissingSecrets; len(secrets) > 0 {
printer := template.NewTablePrinter(c.StdIO, params.RenderTableColors, params.RenderTableBorders).
Title("MISSING SECRETS").
SetHeaders("Secret Key")
for _, sk := range secrets {
printer.Append([]string{sk})
}
printer.Render()
_, _ = c.StdIO.Write([]byte("\n"))
}
if params.StackId != "" {
_, _ = c.StdIO.Write([]byte(fmt.Sprintf("Stack ID: %s\n", params.StackId)))
}
return nil
}

View File

@ -180,7 +180,7 @@ func SourceFromReader(r io.Reader, encoding TemplateEncoding) TemplateSource {
}
}
func (s TemplateSource) Read(ctx context.Context) ([]api.TemplateEntry, error) {
func (s TemplateSource) Read(ctx context.Context) (api.TemplateApplyTemplate, error) {
var entries []api.TemplateEntry
if err := func() error {
in, err := s.Open(ctx)
@ -210,8 +210,11 @@ func (s TemplateSource) Read(ctx context.Context) ([]api.TemplateEntry, error) {
}
return err
}(); err != nil {
return nil, fmt.Errorf("failed to read template(s) from %q: %w", s.Name, err)
return api.TemplateApplyTemplate{}, fmt.Errorf("failed to read template(s) from %q: %w", s.Name, err)
}
return entries, nil
return api.TemplateApplyTemplate{
Sources: []string{s.Name},
Contents: entries,
}, nil
}

View File

@ -377,7 +377,7 @@ spec:
"name": "test",
"retentionRules": []interface{}{
map[string]interface{}{
"type": "expire",
"type": "expire",
},
},
},
@ -389,7 +389,7 @@ spec:
"name": "test2",
"retentionRules": []interface{}{
map[string]interface{}{
"type": "expire",
"type": "expire",
},
},
},
@ -424,10 +424,13 @@ spec:
t.Parallel()
source := apply.SourceFromReader(strings.NewReader(tc.data), tc.encoding)
tmpls, err := source.Read(context.Background())
tmpl, err := source.Read(context.Background())
require.NoError(t, err)
require.Equal(t, parsed, tmpls)
expected := api.TemplateApplyTemplate{
Sources: []string{source.Name},
Contents: parsed,
}
require.Equal(t, expected, tmpl)
})
}
}