k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/cmd/kubeadm/app/util/marshal.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package util 18 19 import ( 20 "bufio" 21 "bytes" 22 "io" 23 24 "github.com/pkg/errors" 25 26 "k8s.io/apimachinery/pkg/runtime" 27 "k8s.io/apimachinery/pkg/runtime/schema" 28 "k8s.io/apimachinery/pkg/runtime/serializer" 29 yamlserializer "k8s.io/apimachinery/pkg/runtime/serializer/yaml" 30 errorsutil "k8s.io/apimachinery/pkg/util/errors" 31 utilyaml "k8s.io/apimachinery/pkg/util/yaml" 32 clientsetscheme "k8s.io/client-go/kubernetes/scheme" 33 34 kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" 35 "k8s.io/kubernetes/cmd/kubeadm/app/constants" 36 ) 37 38 // MarshalToYaml marshals an object into yaml. 39 func MarshalToYaml(obj runtime.Object, gv schema.GroupVersion) ([]byte, error) { 40 return MarshalToYamlForCodecs(obj, gv, clientsetscheme.Codecs) 41 } 42 43 // MarshalToYamlForCodecs marshals an object into yaml using the specified codec 44 // TODO: Is specifying the gv really needed here? 45 // TODO: Can we support json out of the box easily here? 46 func MarshalToYamlForCodecs(obj runtime.Object, gv schema.GroupVersion, codecs serializer.CodecFactory) ([]byte, error) { 47 const mediaType = runtime.ContentTypeYAML 48 info, ok := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), mediaType) 49 if !ok { 50 return []byte{}, errors.Errorf("unsupported media type %q", mediaType) 51 } 52 53 encoder := codecs.EncoderForVersion(info.Serializer, gv) 54 return runtime.Encode(encoder, obj) 55 } 56 57 // UniversalUnmarshal unmarshals YAML or JSON into a runtime.Object using the universal deserializer. 58 func UniversalUnmarshal(buffer []byte) (runtime.Object, error) { 59 codecs := clientsetscheme.Codecs 60 decoder := codecs.UniversalDeserializer() 61 obj, _, err := decoder.Decode(buffer, nil, nil) 62 if err != nil { 63 return nil, errors.Wrapf(err, "failed to decode %s into runtime.Object", buffer) 64 } 65 return obj, nil 66 } 67 68 // SplitYAMLDocuments reads the YAML bytes per-document, unmarshals the TypeMeta information from each document 69 // and returns a map between the GroupVersionKind of the document and the document bytes 70 func SplitYAMLDocuments(yamlBytes []byte) (kubeadmapi.DocumentMap, error) { 71 gvkmap := kubeadmapi.DocumentMap{} 72 knownKinds := map[string]bool{} 73 errs := []error{} 74 buf := bytes.NewBuffer(yamlBytes) 75 reader := utilyaml.NewYAMLReader(bufio.NewReader(buf)) 76 for { 77 // Read one YAML document at a time, until io.EOF is returned 78 b, err := reader.Read() 79 if err == io.EOF { 80 break 81 } else if err != nil { 82 return nil, err 83 } 84 if len(b) == 0 { 85 break 86 } 87 // Deserialize the TypeMeta information of this byte slice 88 gvk, err := yamlserializer.DefaultMetaFactory.Interpret(b) 89 if err != nil { 90 return nil, err 91 } 92 if len(gvk.Group) == 0 || len(gvk.Version) == 0 || len(gvk.Kind) == 0 { 93 return nil, errors.Errorf("invalid configuration for GroupVersionKind %+v: kind and apiVersion is mandatory information that must be specified", gvk) 94 } 95 96 // Check whether the kind has been registered before. If it has, throw an error 97 if known := knownKinds[gvk.Kind]; known { 98 errs = append(errs, errors.Errorf("invalid configuration: kind %q is specified twice in YAML file", gvk.Kind)) 99 continue 100 } 101 knownKinds[gvk.Kind] = true 102 103 // Save the mapping between the gvk and the bytes that object consists of 104 gvkmap[*gvk] = b 105 } 106 if err := errorsutil.NewAggregate(errs); err != nil { 107 return nil, err 108 } 109 return gvkmap, nil 110 } 111 112 // GroupVersionKindsFromBytes parses the bytes and returns a gvk slice 113 func GroupVersionKindsFromBytes(b []byte) ([]schema.GroupVersionKind, error) { 114 gvkmap, err := SplitYAMLDocuments(b) 115 if err != nil { 116 return nil, err 117 } 118 gvks := []schema.GroupVersionKind{} 119 for gvk := range gvkmap { 120 gvks = append(gvks, gvk) 121 } 122 return gvks, nil 123 } 124 125 // GroupVersionKindsHasKind returns whether the following gvk slice contains the kind given as a parameter 126 func GroupVersionKindsHasKind(gvks []schema.GroupVersionKind, kind string) bool { 127 for _, gvk := range gvks { 128 if gvk.Kind == kind { 129 return true 130 } 131 } 132 return false 133 } 134 135 // GroupVersionKindsHasClusterConfiguration returns whether the following gvk slice contains a ClusterConfiguration object 136 func GroupVersionKindsHasClusterConfiguration(gvks ...schema.GroupVersionKind) bool { 137 return GroupVersionKindsHasKind(gvks, constants.ClusterConfigurationKind) 138 } 139 140 // GroupVersionKindsHasInitConfiguration returns whether the following gvk slice contains a InitConfiguration object 141 func GroupVersionKindsHasInitConfiguration(gvks ...schema.GroupVersionKind) bool { 142 return GroupVersionKindsHasKind(gvks, constants.InitConfigurationKind) 143 } 144 145 // GroupVersionKindsHasJoinConfiguration returns whether the following gvk slice contains a JoinConfiguration object 146 func GroupVersionKindsHasJoinConfiguration(gvks ...schema.GroupVersionKind) bool { 147 return GroupVersionKindsHasKind(gvks, constants.JoinConfigurationKind) 148 } 149 150 // GroupVersionKindsHasResetConfiguration returns whether the following gvk slice contains a ResetConfiguration object 151 func GroupVersionKindsHasResetConfiguration(gvks ...schema.GroupVersionKind) bool { 152 return GroupVersionKindsHasKind(gvks, constants.ResetConfigurationKind) 153 } 154 155 // GroupVersionKindsHasUpgradeConfiguration returns whether the following gvk slice contains a UpgradeConfiguration object 156 func GroupVersionKindsHasUpgradeConfiguration(gvks ...schema.GroupVersionKind) bool { 157 return GroupVersionKindsHasKind(gvks, constants.UpgradeConfigurationKind) 158 }