Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add --show-pristine option #197

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions internal/commands/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ type config struct {
stdout io.Writer // standard output
stderr io.Writer // standard error
cleanEvalMode bool // clean mode for eval
showPristine bool // generate last-applied annotation
}

// init checks variables and sets up defaults. In strict mode, it requires all variables
Expand Down
3 changes: 2 additions & 1 deletion internal/commands/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/splunk/qbec/internal/diff"
"github.com/splunk/qbec/internal/model"
"github.com/splunk/qbec/internal/objsort"
"github.com/splunk/qbec/internal/pristine"
"github.com/splunk/qbec/internal/remote"
"github.com/splunk/qbec/internal/sio"
"github.com/splunk/qbec/internal/types"
Expand Down Expand Up @@ -283,7 +284,7 @@ func (d *differ) diff(ob model.K8sMeta) error {
var left, right *unstructured.Unstructured
if remoteObject != nil {
var source string
left, source = remote.GetPristineVersionForDiff(remoteObject)
left, source = pristine.GetPristineVersionForDiff(remoteObject)
leftName += " (source: " + source + ")"
}
left = fixup(left)
Expand Down
14 changes: 13 additions & 1 deletion internal/commands/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/spf13/cobra"
"github.com/splunk/qbec/internal/model"
"github.com/splunk/qbec/internal/objsort"
"github.com/splunk/qbec/internal/pristine"
"github.com/splunk/qbec/internal/sio"
"github.com/splunk/qbec/internal/types"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
Expand Down Expand Up @@ -125,6 +126,12 @@ func cleanMeta(obj model.K8sLocalObject) *unstructured.Unstructured {
return un
}

func showPristine(obj model.K8sLocalObject) *unstructured.Unstructured {
p := pristine.QbecPristine{}
ret, _ := p.CreateFromPristine(obj)
return ret.ToUnstructured()
}

func doShow(args []string, config showCommandConfig) error {
if len(args) != 1 {
return newUsageError("exactly one environment required")
Expand Down Expand Up @@ -176,6 +183,9 @@ func doShow(args []string, config showCommandConfig) error {
var displayObjects []*unstructured.Unstructured
mapper := func(o model.K8sLocalObject) *unstructured.Unstructured { return o.ToUnstructured() }

if config.showPristine {
mapper = showPristine
}
if config.cleanEvalMode {
mapper = cleanMeta
}
Expand Down Expand Up @@ -213,17 +223,19 @@ func newShowCommand(cp configProvider) *cobra.Command {
filterFunc: addFilterParams(cmd, true),
}

var clean bool
var clean, pristine bool
cmd.Flags().StringVarP(&config.format, "format", "o", "yaml", "Output format. Supported values are: json, yaml")
cmd.Flags().BoolVarP(&config.namesOnly, "objects", "O", false, "Only print names of objects instead of their contents")
cmd.Flags().BoolVar(&config.sortAsApply, "sort-apply", false, "sort output in apply order (requires cluster access)")
cmd.Flags().BoolVar(&clean, "clean", false, "do not display qbec-generated labels and annotations")
cmd.Flags().BoolVar(&pristine, "show-pristine", false, "generate and display last-applied annotation")
cmd.Flags().BoolVarP(&config.showSecrets, "show-secrets", "S", false, "do not obfuscate secret values in the output")

cmd.RunE = func(c *cobra.Command, args []string) error {
config.config = cp()
config.formatSpecified = c.Flags().Changed("format")
config.config.cleanEvalMode = clean
config.config.showPristine = pristine
return wrapError(doShow(args, config))
}
return cmd
Expand Down
32 changes: 16 additions & 16 deletions internal/remote/pristine.go → internal/pristine/pristine.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
limitations under the License.
*/

package remote
package pristine

import (
"bytes"
Expand Down Expand Up @@ -72,18 +72,18 @@ func unzipData(s string) (map[string]interface{}, error) {
return data, nil
}

type pristineReader interface {
getPristine(annotations map[string]string, obj *unstructured.Unstructured) (pristine *unstructured.Unstructured, source string)
type PristineReader interface {
GetPristine(annotations map[string]string, obj *unstructured.Unstructured) (pristine *unstructured.Unstructured, source string)
}

type pristineReadWriter interface {
pristineReader
createFromPristine(obj model.K8sLocalObject) (model.K8sLocalObject, error)
type PristineReadWriter interface {
PristineReader
CreateFromPristine(obj model.K8sLocalObject) (model.K8sLocalObject, error)
}

type qbecPristine struct{}
type QbecPristine struct{}

func (k qbecPristine) getPristine(annotations map[string]string, _ *unstructured.Unstructured) (*unstructured.Unstructured, string) {
func (k QbecPristine) GetPristine(annotations map[string]string, _ *unstructured.Unstructured) (*unstructured.Unstructured, string) {
serialized := annotations[model.QbecNames.PristineAnnotation]
if serialized == "" {
return nil, ""
Expand All @@ -96,7 +96,7 @@ func (k qbecPristine) getPristine(annotations map[string]string, _ *unstructured
return &unstructured.Unstructured{Object: m}, "qbec annotation"
}

func (k qbecPristine) createFromPristine(pristine model.K8sLocalObject) (model.K8sLocalObject, error) {
func (k QbecPristine) CreateFromPristine(pristine model.K8sLocalObject) (model.K8sLocalObject, error) {
b, err := json.Marshal(pristine)
if err != nil {
return nil, errors.Wrap(err, "pristine JSON marshal")
Expand Down Expand Up @@ -125,9 +125,9 @@ func (k qbecPristine) createFromPristine(pristine model.K8sLocalObject) (model.K

const kubectlLastConfig = "kubectl.kubernetes.io/last-applied-configuration"

type kubectlPristine struct{}
type KubectlPristine struct{}

func (k kubectlPristine) getPristine(annotations map[string]string, _ *unstructured.Unstructured) (*unstructured.Unstructured, string) {
func (k KubectlPristine) GetPristine(annotations map[string]string, _ *unstructured.Unstructured) (*unstructured.Unstructured, string) {
serialized := annotations[kubectlLastConfig]
if serialized == "" {
return nil, ""
Expand All @@ -150,7 +150,7 @@ func (k kubectlPristine) getPristine(annotations map[string]string, _ *unstructu

type fallbackPristine struct{}

func (f fallbackPristine) getPristine(annotations map[string]string, orig *unstructured.Unstructured) (*unstructured.Unstructured, string) {
func (f fallbackPristine) GetPristine(annotations map[string]string, orig *unstructured.Unstructured) (*unstructured.Unstructured, string) {
delete(annotations, "deployment.kubernetes.io/revision")
orig.SetDeletionTimestamp(nil)
orig.SetCreationTimestamp(metav1.Time{})
Expand All @@ -163,8 +163,8 @@ func (f fallbackPristine) getPristine(annotations map[string]string, orig *unstr
return orig, "fallback - live object with some attributes removed"
}

func getPristineVersion(obj *unstructured.Unstructured, includeFallback bool) (*unstructured.Unstructured, string) {
pristineReaders := []pristineReader{qbecPristine{}, kubectlPristine{}}
func GetPristineVersion(obj *unstructured.Unstructured, includeFallback bool) (*unstructured.Unstructured, string) {
pristineReaders := []PristineReader{QbecPristine{}, KubectlPristine{}}
if includeFallback {
pristineReaders = append(pristineReaders, fallbackPristine{})
}
Expand All @@ -173,7 +173,7 @@ func getPristineVersion(obj *unstructured.Unstructured, includeFallback bool) (*
annotations = map[string]string{}
}
for _, p := range pristineReaders {
out, str := p.getPristine(annotations, obj)
out, str := p.GetPristine(annotations, obj)
if out != nil {
return out, str
}
Expand All @@ -185,5 +185,5 @@ func getPristineVersion(obj *unstructured.Unstructured, includeFallback bool) (*
// live object. If no annotations are found, it halfheartedly deletes known runtime information that is
// set on the server and returns the supplied object with those attributes removed.
func GetPristineVersionForDiff(obj *unstructured.Unstructured) (*unstructured.Unstructured, string) {
return getPristineVersion(obj, true)
return GetPristineVersion(obj, true)
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package remote
package pristine

import (
"encoding/base64"
Expand Down Expand Up @@ -174,7 +174,7 @@ func testPristineReader(t *testing.T, useFallback bool) {
if useFallback {
pristine, source = GetPristineVersionForDiff(obj)
} else {
pristine, source = getPristineVersion(obj, false)
pristine, source = GetPristineVersion(obj, false)
}
test.asserter(t, pristine, source)
})
Expand All @@ -191,9 +191,9 @@ func TestPristineReaderNoFallback(t *testing.T) {

func TestCreateFromPristine(t *testing.T) {
un := loadFile(t, "input.yaml")
p := qbecPristine{}
p := QbecPristine{}
obj := model.NewK8sLocalObject(un.Object, model.LocalAttrs{App: "app", Tag: "", Component: "comp1", Env: "dev"})
ret, err := p.createFromPristine(obj)
ret, err := p.CreateFromPristine(obj)
require.Nil(t, err)
a := assert.New(t)
eLabels := obj.ToUnstructured().GetLabels()
Expand Down
13 changes: 7 additions & 6 deletions internal/remote/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/jonboulle/clockwork"
"github.com/pkg/errors"
"github.com/splunk/qbec/internal/model"
"github.com/splunk/qbec/internal/pristine"
"github.com/splunk/qbec/internal/remote/k8smeta"
"github.com/splunk/qbec/internal/sio"
"github.com/splunk/qbec/internal/types"
Expand Down Expand Up @@ -78,9 +79,9 @@ type DeleteOptions struct {
}

type internalSyncOptions struct {
secretDryRun bool // dry-run phase for objects having secrets info
pristiner pristineReadWriter // pristine writer
pristineAnnotation string // pristine annotation to manipulate for secrets dry-run
secretDryRun bool // dry-run phase for objects having secrets info
pristiner pristine.PristineReadWriter // pristine writer
pristineAnnotation string // pristine annotation to manipulate for secrets dry-run
}

type resourceClient interface {
Expand Down Expand Up @@ -407,7 +408,7 @@ func (c *Client) ensureType(gvk schema.GroupVersionKind, opts SyncOptions) error
// It does not do anything in dry-run mode. It also does not create new objects if the caller has disabled the feature.
func (c *Client) Sync(original model.K8sLocalObject, opts SyncOptions) (_ *SyncResult, finalError error) {
// set up the pristine strategy.
var prw pristineReadWriter = qbecPristine{}
var prw pristine.PristineReadWriter = pristine.QbecPristine{}
sensitive := types.HasSensitiveInfo(original.ToUnstructured())

internal := internalSyncOptions{
Expand Down Expand Up @@ -476,7 +477,7 @@ func (c *Client) doSync(original model.K8sLocalObject, opts SyncOptions, interna
opts.DryRun = true // won't affect caller since passed by value
obj, _ = types.HideSensitiveLocalInfo(original)
} else {
o, err := internal.pristiner.createFromPristine(original)
o, err := internal.pristiner.CreateFromPristine(original)
if err != nil {
return nil, errors.Wrap(err, "create from pristine")
}
Expand Down Expand Up @@ -665,7 +666,7 @@ func (c *Client) maybeUpdate(obj model.K8sLocalObject, remObj *unstructured.Unst
p := patcher{
provider: c.resourceInterfaceWithDefaultNs,
cfgProvider: func(obj *unstructured.Unstructured) ([]byte, error) {
pristine, _ := getPristineVersion(obj, false)
pristine, _ := pristine.GetPristineVersion(obj, false)
if pristine == nil {
p := map[string]interface{}{
"kind": obj.GetKind(),
Expand Down