1/*
2Copyright 2018 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17// Package kunstruct provides unstructured from api machinery and factory for creating unstructured
18package kunstruct
19
20import (
21	"encoding/json"
22	"fmt"
23
24	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
26	"k8s.io/apimachinery/pkg/runtime"
27	"sigs.k8s.io/kustomize/pkg/gvk"
28	"sigs.k8s.io/kustomize/pkg/ifc"
29)
30
31var _ ifc.Kunstructured = &UnstructAdapter{}
32
33// UnstructAdapter wraps unstructured.Unstructured from
34// https://github.com/kubernetes/apimachinery/blob/master/
35//     pkg/apis/meta/v1/unstructured/unstructured.go
36// to isolate dependence on apimachinery.
37type UnstructAdapter struct {
38	unstructured.Unstructured
39}
40
41// NewKunstructuredFromObject returns a new instance of Kunstructured.
42func NewKunstructuredFromObject(obj runtime.Object) (ifc.Kunstructured, error) {
43	// Convert obj to a byte stream, then convert that to JSON (Unstructured).
44	marshaled, err := json.Marshal(obj)
45	if err != nil {
46		return &UnstructAdapter{}, err
47	}
48	var u unstructured.Unstructured
49	err = u.UnmarshalJSON(marshaled)
50	// creationTimestamp always 'null', remove it
51	u.SetCreationTimestamp(metav1.Time{})
52	return &UnstructAdapter{Unstructured: u}, err
53}
54
55// GetGvk returns the Gvk name of the object.
56func (fs *UnstructAdapter) GetGvk() gvk.Gvk {
57	x := fs.GroupVersionKind()
58	return gvk.Gvk{
59		Group:   x.Group,
60		Version: x.Version,
61		Kind:    x.Kind,
62	}
63}
64
65// Copy provides a copy behind an interface.
66func (fs *UnstructAdapter) Copy() ifc.Kunstructured {
67	return &UnstructAdapter{*fs.DeepCopy()}
68}
69
70// Map returns the unstructured content map.
71func (fs *UnstructAdapter) Map() map[string]interface{} {
72	return fs.Object
73}
74
75// SetMap overrides the unstructured content map.
76func (fs *UnstructAdapter) SetMap(m map[string]interface{}) {
77	fs.Object = m
78}
79
80// GetFieldValue returns value at the given fieldpath.
81func (fs *UnstructAdapter) GetFieldValue(path string) (string, error) {
82	fields, err := parseFields(path)
83	if err != nil {
84		return "", err
85	}
86	s, found, err := unstructured.NestedString(
87		fs.UnstructuredContent(), fields...)
88	if found || err != nil {
89		return s, err
90	}
91	return "", fmt.Errorf("no field named '%s'", path)
92}
93