mirror of
https://github.com/k3s-io/k3s.git
synced 2024-06-07 19:41:36 +00:00
271 lines
6.9 KiB
Go
271 lines
6.9 KiB
Go
// Copyright 2019 The Kubernetes Authors.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package resource
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"strings"
|
|
|
|
"sigs.k8s.io/kustomize/api/ifc"
|
|
"sigs.k8s.io/kustomize/api/internal/generators"
|
|
"sigs.k8s.io/kustomize/api/internal/kusterr"
|
|
"sigs.k8s.io/kustomize/api/konfig"
|
|
"sigs.k8s.io/kustomize/api/resid"
|
|
"sigs.k8s.io/kustomize/api/types"
|
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
|
)
|
|
|
|
// Factory makes instances of Resource.
|
|
type Factory struct {
|
|
hasher ifc.KustHasher
|
|
}
|
|
|
|
// NewFactory makes an instance of Factory.
|
|
func NewFactory(h ifc.KustHasher) *Factory {
|
|
return &Factory{hasher: h}
|
|
}
|
|
|
|
// Hasher returns an ifc.KustHasher
|
|
func (rf *Factory) Hasher() ifc.KustHasher {
|
|
return rf.hasher
|
|
}
|
|
|
|
// FromMap returns a new instance of Resource.
|
|
func (rf *Factory) FromMap(m map[string]interface{}) *Resource {
|
|
return rf.FromMapAndOption(m, nil)
|
|
}
|
|
|
|
// FromMapWithName returns a new instance with the given "original" name.
|
|
func (rf *Factory) FromMapWithName(n string, m map[string]interface{}) *Resource {
|
|
return rf.FromMapWithNamespaceAndName(resid.DefaultNamespace, n, m)
|
|
}
|
|
|
|
// FromMapWithNamespaceAndName returns a new instance with the given "original" namespace.
|
|
func (rf *Factory) FromMapWithNamespaceAndName(ns string, n string, m map[string]interface{}) *Resource {
|
|
r := rf.FromMapAndOption(m, nil)
|
|
return r.setPreviousId(ns, n, r.GetKind())
|
|
}
|
|
|
|
// FromMapAndOption returns a new instance of Resource with given options.
|
|
func (rf *Factory) FromMapAndOption(
|
|
m map[string]interface{}, args *types.GeneratorArgs) *Resource {
|
|
n, err := yaml.FromMap(m)
|
|
if err != nil {
|
|
// TODO: return err instead of log.
|
|
log.Fatal(err)
|
|
}
|
|
return rf.makeOne(n, types.NewGenArgs(args))
|
|
}
|
|
|
|
// makeOne returns a new instance of Resource.
|
|
func (rf *Factory) makeOne(rn *yaml.RNode, o *types.GenArgs) *Resource {
|
|
if rn == nil {
|
|
log.Fatal("RNode must not be null")
|
|
}
|
|
if o == nil {
|
|
o = types.NewGenArgs(nil)
|
|
}
|
|
return &Resource{node: rn, options: o}
|
|
}
|
|
|
|
// SliceFromPatches returns a slice of resources given a patch path
|
|
// slice from a kustomization file.
|
|
func (rf *Factory) SliceFromPatches(
|
|
ldr ifc.Loader, paths []types.PatchStrategicMerge) ([]*Resource, error) {
|
|
var result []*Resource
|
|
for _, path := range paths {
|
|
content, err := ldr.Load(string(path))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
res, err := rf.SliceFromBytes(content)
|
|
if err != nil {
|
|
return nil, kusterr.Handler(err, string(path))
|
|
}
|
|
result = append(result, res...)
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// FromBytes unmarshalls bytes into one Resource.
|
|
func (rf *Factory) FromBytes(in []byte) (*Resource, error) {
|
|
result, err := rf.SliceFromBytes(in)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(result) != 1 {
|
|
return nil, fmt.Errorf(
|
|
"expected 1 resource, found %d in %v", len(result), in)
|
|
}
|
|
return result[0], nil
|
|
}
|
|
|
|
// SliceFromBytes unmarshals bytes into a Resource slice.
|
|
func (rf *Factory) SliceFromBytes(in []byte) ([]*Resource, error) {
|
|
nodes, err := rf.RNodesFromBytes(in)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return rf.resourcesFromRNodes(nodes), nil
|
|
}
|
|
|
|
// ResourcesFromRNodes converts RNodes to Resources.
|
|
func (rf *Factory) ResourcesFromRNodes(
|
|
nodes []*yaml.RNode) (result []*Resource, err error) {
|
|
nodes, err = rf.dropBadNodes(nodes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return rf.resourcesFromRNodes(nodes), nil
|
|
}
|
|
|
|
// resourcesFromRNode assumes all nodes are good.
|
|
func (rf *Factory) resourcesFromRNodes(
|
|
nodes []*yaml.RNode) (result []*Resource) {
|
|
for _, n := range nodes {
|
|
result = append(result, rf.makeOne(n, nil))
|
|
}
|
|
return
|
|
}
|
|
|
|
func (rf *Factory) RNodesFromBytes(b []byte) (result []*yaml.RNode, err error) {
|
|
nodes, err := kio.FromBytes(b)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
nodes, err = rf.dropBadNodes(nodes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for len(nodes) > 0 {
|
|
n0 := nodes[0]
|
|
nodes = nodes[1:]
|
|
kind := n0.GetKind()
|
|
if !strings.HasSuffix(kind, "List") {
|
|
result = append(result, n0)
|
|
continue
|
|
}
|
|
// Convert a FooList into a slice of Foo.
|
|
var m map[string]interface{}
|
|
m, err = n0.Map()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
items, ok := m["items"]
|
|
if !ok {
|
|
// treat as an empty list
|
|
continue
|
|
}
|
|
slice, ok := items.([]interface{})
|
|
if !ok {
|
|
if items == nil {
|
|
// an empty list
|
|
continue
|
|
}
|
|
return nil, fmt.Errorf(
|
|
"expected array in %s/items, but found %T", kind, items)
|
|
}
|
|
innerNodes, err := rf.convertObjectSliceToNodeSlice(slice)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
nodes = append(nodes, innerNodes...)
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// convertObjectSlice converts a list of objects to a list of RNode.
|
|
func (rf *Factory) convertObjectSliceToNodeSlice(
|
|
objects []interface{}) (result []*yaml.RNode, err error) {
|
|
var bytes []byte
|
|
var nodes []*yaml.RNode
|
|
for _, obj := range objects {
|
|
bytes, err = json.Marshal(obj)
|
|
if err != nil {
|
|
return
|
|
}
|
|
nodes, err = kio.FromBytes(bytes)
|
|
if err != nil {
|
|
return
|
|
}
|
|
nodes, err = rf.dropBadNodes(nodes)
|
|
if err != nil {
|
|
return
|
|
}
|
|
result = append(result, nodes...)
|
|
}
|
|
return
|
|
}
|
|
|
|
// dropBadNodes may drop some nodes from its input argument.
|
|
func (rf *Factory) dropBadNodes(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
|
var result []*yaml.RNode
|
|
for _, n := range nodes {
|
|
ignore, err := rf.shouldIgnore(n)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !ignore {
|
|
result = append(result, n)
|
|
}
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// shouldIgnore returns true if there's some reason to ignore the node.
|
|
func (rf *Factory) shouldIgnore(n *yaml.RNode) (bool, error) {
|
|
if n.IsNilOrEmpty() {
|
|
return true, nil
|
|
}
|
|
md, err := n.GetValidatedMetadata()
|
|
if err != nil {
|
|
return true, err
|
|
}
|
|
_, ignore := md.ObjectMeta.Annotations[konfig.IgnoredByKustomizeAnnotation]
|
|
if ignore {
|
|
return true, nil
|
|
}
|
|
if foundNil, path := n.HasNilEntryInList(); foundNil {
|
|
return true, fmt.Errorf("empty item at %v in object %v", path, n)
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
// SliceFromBytesWithNames unmarshals bytes into a Resource slice with specified original
|
|
// name.
|
|
func (rf *Factory) SliceFromBytesWithNames(names []string, in []byte) ([]*Resource, error) {
|
|
result, err := rf.SliceFromBytes(in)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(names) != len(result) {
|
|
return nil, fmt.Errorf("number of names doesn't match number of resources")
|
|
}
|
|
for i, res := range result {
|
|
res.setPreviousId(resid.DefaultNamespace, names[i], res.GetKind())
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// MakeConfigMap makes an instance of Resource for ConfigMap
|
|
func (rf *Factory) MakeConfigMap(kvLdr ifc.KvLoader, args *types.ConfigMapArgs) (*Resource, error) {
|
|
rn, err := generators.MakeConfigMap(kvLdr, args)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return rf.makeOne(rn, types.NewGenArgs(&args.GeneratorArgs)), nil
|
|
}
|
|
|
|
// MakeSecret makes an instance of Resource for Secret
|
|
func (rf *Factory) MakeSecret(kvLdr ifc.KvLoader, args *types.SecretArgs) (*Resource, error) {
|
|
rn, err := generators.MakeSecret(kvLdr, args)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return rf.makeOne(rn, types.NewGenArgs(&args.GeneratorArgs)), nil
|
|
}
|