Update go dependencies

This commit is contained in:
Manuel Alejandro de Brito Fontes 2020-03-24 10:44:24 -03:00
parent a46126a034
commit 3eafaa35a1
1108 changed files with 32555 additions and 83490 deletions

View file

@ -17,6 +17,7 @@ limitations under the License.
package genericclioptions
import (
"errors"
"os"
"path/filepath"
"regexp"
@ -41,6 +42,7 @@ const (
flagContext = "context"
flagNamespace = "namespace"
flagAPIServer = "server"
flagTLSServerName = "tls-server-name"
flagInsecure = "insecure-skip-tls-verify"
flagCertFile = "client-certificate"
flagKeyFile = "client-key"
@ -54,7 +56,17 @@ const (
flagHTTPCacheDir = "cache-dir"
)
var defaultCacheDir = filepath.Join(homedir.HomeDir(), ".kube", "http-cache")
var (
defaultCacheDir = filepath.Join(homedir.HomeDir(), ".kube", "http-cache")
ErrEmptyConfig = errors.New(`Missing or incomplete configuration info. Please point to an existing, complete config file:
1. Via the command-line flag --kubeconfig
2. Via the KUBECONFIG environment variable
3. In your home directory as ~/.kube/config
To view or setup config directly use the 'config' command.`)
)
// RESTClientGetter is an interface that the ConfigFlags describe to provide an easier way to mock for commands
// and eliminate the direct coupling to a struct type. Users may wish to duplicate this type in their own packages
@ -84,6 +96,7 @@ type ConfigFlags struct {
Context *string
Namespace *string
APIServer *string
TLSServerName *string
Insecure *bool
CertFile *string
KeyFile *string
@ -108,7 +121,12 @@ type ConfigFlags struct {
// to a .kubeconfig file, loading rules, and config flag overrides.
// Expects the AddFlags method to have been called.
func (f *ConfigFlags) ToRESTConfig() (*rest.Config, error) {
return f.ToRawKubeConfigLoader().ClientConfig()
config, err := f.ToRawKubeConfigLoader().ClientConfig()
// replace client-go's ErrEmptyConfig error with our custom, more verbose version
if clientcmd.IsEmptyConfig(err) {
return nil, ErrEmptyConfig
}
return config, err
}
// ToRawKubeConfigLoader binds config flag values to config overrides
@ -160,6 +178,9 @@ func (f *ConfigFlags) toRawKubeConfigLoader() clientcmd.ClientConfig {
if f.APIServer != nil {
overrides.ClusterInfo.Server = *f.APIServer
}
if f.TLSServerName != nil {
overrides.ClusterInfo.TLSServerName = *f.TLSServerName
}
if f.CAFile != nil {
overrides.ClusterInfo.CertificateAuthority = *f.CAFile
}
@ -294,6 +315,9 @@ func (f *ConfigFlags) AddFlags(flags *pflag.FlagSet) {
if f.APIServer != nil {
flags.StringVarP(f.APIServer, flagAPIServer, "s", *f.APIServer, "The address and port of the Kubernetes API server")
}
if f.TLSServerName != nil {
flags.StringVar(f.TLSServerName, flagTLSServerName, *f.TLSServerName, "Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used")
}
if f.Insecure != nil {
flags.BoolVar(f.Insecure, flagInsecure, *f.Insecure, "If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure")
}
@ -329,6 +353,7 @@ func NewConfigFlags(usePersistentConfig bool) *ConfigFlags {
Context: stringptr(""),
Namespace: stringptr(""),
APIServer: stringptr(""),
TLSServerName: stringptr(""),
CertFile: stringptr(""),
KeyFile: stringptr(""),
CAFile: stringptr(""),

View file

@ -90,7 +90,14 @@ func SecretHash(sec *v1.Secret) (string, error) {
// Data, Kind, and Name are taken into account.
func encodeConfigMap(cm *v1.ConfigMap) (string, error) {
// json.Marshal sorts the keys in a stable order in the encoding
m := map[string]interface{}{"kind": "ConfigMap", "name": cm.Name, "data": cm.Data}
m := map[string]interface{}{
"kind": "ConfigMap",
"name": cm.Name,
"data": cm.Data,
}
if cm.Immutable != nil {
m["immutable"] = *cm.Immutable
}
if len(cm.BinaryData) > 0 {
m["binaryData"] = cm.BinaryData
}
@ -105,7 +112,16 @@ func encodeConfigMap(cm *v1.ConfigMap) (string, error) {
// Data, Kind, Name, and Type are taken into account.
func encodeSecret(sec *v1.Secret) (string, error) {
// json.Marshal sorts the keys in a stable order in the encoding
data, err := json.Marshal(map[string]interface{}{"kind": "Secret", "type": sec.Type, "name": sec.Name, "data": sec.Data})
m := map[string]interface{}{
"kind": "Secret",
"type": sec.Type,
"name": sec.Name,
"data": sec.Data,
}
if sec.Immutable != nil {
m["immutable"] = *sec.Immutable
}
data, err := json.Marshal(m)
if err != nil {
return "", err
}

View file

@ -26,7 +26,6 @@ import (
"github.com/liggitt/tabwriter"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/duration"
@ -36,7 +35,7 @@ import (
var _ ResourcePrinter = &HumanReadablePrinter{}
type printHandler struct {
columnDefinitions []metav1beta1.TableColumnDefinition
columnDefinitions []metav1.TableColumnDefinition
printFunc reflect.Value
}
@ -46,7 +45,7 @@ var (
printFunc: reflect.ValueOf(printStatus),
}
statusColumnDefinitions = []metav1beta1.TableColumnDefinition{
statusColumnDefinitions = []metav1.TableColumnDefinition{
{Name: "Status", Type: "string"},
{Name: "Reason", Type: "string"},
{Name: "Message", Type: "string"},
@ -57,7 +56,7 @@ var (
printFunc: reflect.ValueOf(printObjectMeta),
}
objectMetaColumnDefinitions = []metav1beta1.TableColumnDefinition{
objectMetaColumnDefinitions = []metav1.TableColumnDefinition{
{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
}
@ -73,7 +72,7 @@ var (
type HumanReadablePrinter struct {
options PrintOptions
lastType interface{}
lastColumns []metav1beta1.TableColumnDefinition
lastColumns []metav1.TableColumnDefinition
printedHeaders bool
}
@ -110,7 +109,7 @@ func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) er
// Parameter "obj" is a table from server; print it.
// display tables following the rules of options
if table, ok := obj.(*metav1beta1.Table); ok {
if table, ok := obj.(*metav1.Table); ok {
// Do not print headers if this table has no column definitions, or they are the same as the last ones we printed
localOptions := h.options
if h.printedHeaders && (len(table.ColumnDefinitions) == 0 || reflect.DeepEqual(table.ColumnDefinitions, h.lastColumns)) {
@ -136,8 +135,8 @@ func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) er
}
if len(eventType) > 0 {
if err := addColumns(beginning, table,
[]metav1beta1.TableColumnDefinition{{Name: "Event", Type: "string"}},
[]cellValueFunc{func(metav1beta1.TableRow) (interface{}, error) { return formatEventType(eventType), nil }},
[]metav1.TableColumnDefinition{{Name: "Event", Type: "string"}},
[]cellValueFunc{func(metav1.TableRow) (interface{}, error) { return formatEventType(eventType), nil }},
); err != nil {
return err
}
@ -171,7 +170,7 @@ func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) er
// printTable prints a table to the provided output respecting the filtering rules for options
// for wide columns and filtered rows. It filters out rows that are Completed. You should call
// decorateTable if you receive a table from a remote server before calling printTable.
func printTable(table *metav1beta1.Table, output io.Writer, options PrintOptions) error {
func printTable(table *metav1.Table, output io.Writer, options PrintOptions) error {
if !options.NoHeaders {
// avoid printing headers if we have no rows to display
if len(table.Rows) == 0 {
@ -218,7 +217,7 @@ func printTable(table *metav1beta1.Table, output io.Writer, options PrintOptions
return nil
}
type cellValueFunc func(metav1beta1.TableRow) (interface{}, error)
type cellValueFunc func(metav1.TableRow) (interface{}, error)
type columnAddPosition int
@ -227,7 +226,7 @@ const (
end columnAddPosition = 2
)
func addColumns(pos columnAddPosition, table *metav1beta1.Table, columns []metav1beta1.TableColumnDefinition, valueFuncs []cellValueFunc) error {
func addColumns(pos columnAddPosition, table *metav1.Table, columns []metav1.TableColumnDefinition, valueFuncs []cellValueFunc) error {
if len(columns) != len(valueFuncs) {
return fmt.Errorf("cannot prepend columns, unmatched value functions")
}
@ -268,7 +267,7 @@ func addColumns(pos columnAddPosition, table *metav1beta1.Table, columns []metav
}
// All cells successfully computed, now replace columns and rows
newColumns := make([]metav1beta1.TableColumnDefinition, 0, len(columns)+len(table.ColumnDefinitions))
newColumns := make([]metav1.TableColumnDefinition, 0, len(columns)+len(table.ColumnDefinitions))
switch pos {
case beginning:
newColumns = append(newColumns, columns...)
@ -291,7 +290,7 @@ func addColumns(pos columnAddPosition, table *metav1beta1.Table, columns []metav
// namespace column. It will fill empty columns with nil (if the object
// does not expose metadata). It returns an error if the table cannot
// be decorated.
func decorateTable(table *metav1beta1.Table, options PrintOptions) error {
func decorateTable(table *metav1.Table, options PrintOptions) error {
width := len(table.ColumnDefinitions) + len(options.ColumnLabels)
if options.WithNamespace {
width++
@ -313,22 +312,22 @@ func decorateTable(table *metav1beta1.Table, options PrintOptions) error {
}
if width != len(table.ColumnDefinitions) {
columns = make([]metav1beta1.TableColumnDefinition, 0, width)
columns = make([]metav1.TableColumnDefinition, 0, width)
if options.WithNamespace {
columns = append(columns, metav1beta1.TableColumnDefinition{
columns = append(columns, metav1.TableColumnDefinition{
Name: "Namespace",
Type: "string",
})
}
columns = append(columns, table.ColumnDefinitions...)
for _, label := range formatLabelHeaders(options.ColumnLabels) {
columns = append(columns, metav1beta1.TableColumnDefinition{
columns = append(columns, metav1.TableColumnDefinition{
Name: label,
Type: "string",
})
}
if options.ShowLabels {
columns = append(columns, metav1beta1.TableColumnDefinition{
columns = append(columns, metav1.TableColumnDefinition{
Name: "Labels",
Type: "string",
})
@ -417,7 +416,7 @@ func printRowsForHandlerEntry(output io.Writer, handler *printHandler, eventType
}
if results[1].IsNil() {
rows := results[0].Interface().([]metav1beta1.TableRow)
rows := results[0].Interface().([]metav1.TableRow)
printRows(output, eventType, rows, options)
return nil
}
@ -439,7 +438,7 @@ func formatEventType(eventType string) string {
}
// printRows writes the provided rows to output.
func printRows(output io.Writer, eventType string, rows []metav1beta1.TableRow, options PrintOptions) {
func printRows(output io.Writer, eventType string, rows []metav1.TableRow, options PrintOptions) {
for _, row := range rows {
if len(eventType) > 0 {
fmt.Fprint(output, formatEventType(eventType))
@ -522,20 +521,20 @@ func appendLabelCells(values []interface{}, itemLabels map[string]string, opts P
return values
}
func printStatus(obj runtime.Object, options PrintOptions) ([]metav1beta1.TableRow, error) {
func printStatus(obj runtime.Object, options PrintOptions) ([]metav1.TableRow, error) {
status, ok := obj.(*metav1.Status)
if !ok {
return nil, fmt.Errorf("expected *v1.Status, got %T", obj)
}
return []metav1beta1.TableRow{{
return []metav1.TableRow{{
Object: runtime.RawExtension{Object: obj},
Cells: []interface{}{status.Status, status.Reason, status.Message},
}}, nil
}
func printObjectMeta(obj runtime.Object, options PrintOptions) ([]metav1beta1.TableRow, error) {
func printObjectMeta(obj runtime.Object, options PrintOptions) ([]metav1.TableRow, error) {
if meta.IsListType(obj) {
rows := make([]metav1beta1.TableRow, 0, 16)
rows := make([]metav1.TableRow, 0, 16)
err := meta.EachListItem(obj, func(obj runtime.Object) error {
nestedRows, err := printObjectMeta(obj, options)
if err != nil {
@ -550,12 +549,12 @@ func printObjectMeta(obj runtime.Object, options PrintOptions) ([]metav1beta1.Ta
return rows, nil
}
rows := make([]metav1beta1.TableRow, 0, 1)
rows := make([]metav1.TableRow, 0, 1)
m, err := meta.Accessor(obj)
if err != nil {
return nil, err
}
row := metav1beta1.TableRow{
row := metav1.TableRow{
Object: runtime.RawExtension{Object: obj},
}
row.Cells = append(row.Cells, m.GetName(), translateTimestampSince(m.GetCreationTimestamp()))

110
vendor/k8s.io/cli-runtime/pkg/resource/crd_finder.go generated vendored Normal file
View file

@ -0,0 +1,110 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package resource
import (
"context"
"fmt"
"reflect"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"
)
// CRDGetter is a function that can download the list of GVK for all
// CRDs.
type CRDGetter func() ([]schema.GroupKind, error)
func CRDFromDynamic(client dynamic.Interface) CRDGetter {
return func() ([]schema.GroupKind, error) {
list, err := client.Resource(schema.GroupVersionResource{
Group: "apiextensions.k8s.io",
Version: "v1beta1",
Resource: "customresourcedefinitions",
}).List(context.TODO(), metav1.ListOptions{})
if err != nil {
return nil, fmt.Errorf("failed to list CRDs: %v", err)
}
if list == nil {
return nil, nil
}
gks := []schema.GroupKind{}
// We need to parse the list to get the gvk, I guess that's fine.
for _, crd := range (*list).Items {
// Look for group, version, and kind
group, _, _ := unstructured.NestedString(crd.Object, "spec", "group")
kind, _, _ := unstructured.NestedString(crd.Object, "spec", "names", "kind")
gks = append(gks, schema.GroupKind{
Group: group,
Kind: kind,
})
}
return gks, nil
}
}
// CRDFinder keeps a cache of known CRDs and finds a given GVK in the
// list.
type CRDFinder interface {
HasCRD(gvk schema.GroupKind) (bool, error)
}
func NewCRDFinder(getter CRDGetter) CRDFinder {
return &crdFinder{
getter: getter,
}
}
type crdFinder struct {
getter CRDGetter
cache *[]schema.GroupKind
}
func (f *crdFinder) cacheCRDs() error {
if f.cache != nil {
return nil
}
list, err := f.getter()
if err != nil {
return err
}
f.cache = &list
return nil
}
func (f *crdFinder) findCRD(gvk schema.GroupKind) bool {
for _, crd := range *f.cache {
if reflect.DeepEqual(gvk, crd) {
return true
}
}
return false
}
func (f *crdFinder) HasCRD(gvk schema.GroupKind) (bool, error) {
if err := f.cacheCRDs(); err != nil {
return false, err
}
return f.findCRD(gvk), nil
}

View file

@ -0,0 +1,121 @@
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package resource
import (
"errors"
"fmt"
openapi_v2 "github.com/googleapis/gnostic/OpenAPIv2"
yaml "gopkg.in/yaml.v2"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/discovery"
"k8s.io/client-go/dynamic"
)
// VerifyDryRun returns nil if a resource group-version-kind supports
// server-side dry-run. Otherwise, an error is returned.
func VerifyDryRun(gvk schema.GroupVersionKind, dynamicClient dynamic.Interface, discoveryClient discovery.DiscoveryInterface) error {
verifier := NewDryRunVerifier(dynamicClient, discoveryClient)
return verifier.HasSupport(gvk)
}
func NewDryRunVerifier(dynamicClient dynamic.Interface, discoveryClient discovery.DiscoveryInterface) *DryRunVerifier {
return &DryRunVerifier{
finder: NewCRDFinder(CRDFromDynamic(dynamicClient)),
openAPIGetter: discoveryClient,
}
}
func hasGVKExtension(extensions []*openapi_v2.NamedAny, gvk schema.GroupVersionKind) bool {
for _, extension := range extensions {
if extension.GetValue().GetYaml() == "" ||
extension.GetName() != "x-kubernetes-group-version-kind" {
continue
}
var value map[string]string
err := yaml.Unmarshal([]byte(extension.GetValue().GetYaml()), &value)
if err != nil {
continue
}
if value["group"] == gvk.Group && value["kind"] == gvk.Kind && value["version"] == gvk.Version {
return true
}
return false
}
return false
}
// DryRunVerifier verifies if a given group-version-kind supports DryRun
// against the current server. Sending dryRun requests to apiserver that
// don't support it will result in objects being unwillingly persisted.
//
// It reads the OpenAPI to see if the given GVK supports dryRun. If the
// GVK can not be found, we assume that CRDs will have the same level of
// support as "namespaces", and non-CRDs will not be supported. We
// delay the check for CRDs as much as possible though, since it
// requires an extra round-trip to the server.
type DryRunVerifier struct {
finder CRDFinder
openAPIGetter discovery.OpenAPISchemaInterface
}
// HasSupport verifies if the given gvk supports DryRun. An error is
// returned if it doesn't.
func (v *DryRunVerifier) HasSupport(gvk schema.GroupVersionKind) error {
oapi, err := v.openAPIGetter.OpenAPISchema()
if err != nil {
return fmt.Errorf("failed to download openapi: %v", err)
}
supports, err := supportsDryRun(oapi, gvk)
if err != nil {
// We assume that we couldn't find the type, then check for namespace:
supports, _ = supportsDryRun(oapi, schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Namespace"})
// If namespace supports dryRun, then we will support dryRun for CRDs only.
if supports {
supports, err = v.finder.HasCRD(gvk.GroupKind())
if err != nil {
return fmt.Errorf("failed to check CRD: %v", err)
}
}
}
if !supports {
return fmt.Errorf("%v doesn't support dry-run", gvk)
}
return nil
}
// supportsDryRun is a method that let's us look in the OpenAPI if the
// specific group-version-kind supports the dryRun query parameter for
// the PATCH end-point.
func supportsDryRun(doc *openapi_v2.Document, gvk schema.GroupVersionKind) (bool, error) {
for _, path := range doc.GetPaths().GetPath() {
// Is this describing the gvk we're looking for?
if !hasGVKExtension(path.GetValue().GetPatch().GetVendorExtension(), gvk) {
continue
}
for _, param := range path.GetValue().GetPatch().GetParameters() {
if param.GetParameter().GetNonBodyParameter().GetQueryParameterSubSchema().GetName() == "dryRun" {
return true, nil
}
}
return false, nil
}
return false, errors.New("couldn't find GVK in openapi")
}

View file

@ -17,6 +17,7 @@ limitations under the License.
package resource
import (
"context"
"strconv"
"k8s.io/apimachinery/pkg/api/meta"
@ -38,6 +39,13 @@ type Helper struct {
RESTClient RESTClient
// True if the resource type is scoped to namespaces
NamespaceScoped bool
// If true, then use server-side dry-run to not persist changes to storage
// for verbs and resources that support server-side dry-run.
//
// Note this should only be used against an apiserver with dry-run enabled,
// and on resources that support dry-run. If the apiserver or the resource
// does not support dry-run, then the change will be persisted to storage.
ServerDryRun bool
}
// NewHelper creates a Helper from a ResourceMapping
@ -49,6 +57,13 @@ func NewHelper(client RESTClient, mapping *meta.RESTMapping) *Helper {
}
}
// DryRun, if true, will use server-side dry-run to not persist changes to storage.
// Otherwise, changes will be persisted to storage.
func (m *Helper) DryRun(dryRun bool) *Helper {
m.ServerDryRun = dryRun
return m
}
func (m *Helper) Get(namespace, name string, export bool) (runtime.Object, error) {
req := m.RESTClient.Get().
NamespaceIfScoped(namespace, m.NamespaceScoped).
@ -58,7 +73,7 @@ func (m *Helper) Get(namespace, name string, export bool) (runtime.Object, error
// TODO: I should be part of GetOptions
req.Param("export", strconv.FormatBool(export))
}
return req.Do().Get()
return req.Do(context.TODO()).Get()
}
func (m *Helper) List(namespace, apiVersion string, export bool, options *metav1.ListOptions) (runtime.Object, error) {
@ -70,7 +85,7 @@ func (m *Helper) List(namespace, apiVersion string, export bool, options *metav1
// TODO: I should be part of ListOptions
req.Param("export", strconv.FormatBool(export))
}
return req.Do().Get()
return req.Do(context.TODO()).Get()
}
func (m *Helper) Watch(namespace, apiVersion string, options *metav1.ListOptions) (watch.Interface, error) {
@ -79,7 +94,7 @@ func (m *Helper) Watch(namespace, apiVersion string, options *metav1.ListOptions
NamespaceIfScoped(namespace, m.NamespaceScoped).
Resource(m.Resource).
VersionedParams(options, metav1.ParameterCodec).
Watch()
Watch(context.TODO())
}
func (m *Helper) WatchSingle(namespace, name, resourceVersion string) (watch.Interface, error) {
@ -91,7 +106,7 @@ func (m *Helper) WatchSingle(namespace, name, resourceVersion string) (watch.Int
Watch: true,
FieldSelector: fields.OneTermEqualSelector("metadata.name", name).String(),
}, metav1.ParameterCodec).
Watch()
Watch(context.TODO())
}
func (m *Helper) Delete(namespace, name string) (runtime.Object, error) {
@ -99,19 +114,33 @@ func (m *Helper) Delete(namespace, name string) (runtime.Object, error) {
}
func (m *Helper) DeleteWithOptions(namespace, name string, options *metav1.DeleteOptions) (runtime.Object, error) {
if options == nil {
options = &metav1.DeleteOptions{}
}
if m.ServerDryRun {
options.DryRun = []string{metav1.DryRunAll}
}
return m.RESTClient.Delete().
NamespaceIfScoped(namespace, m.NamespaceScoped).
Resource(m.Resource).
Name(name).
Body(options).
Do().
Do(context.TODO()).
Get()
}
func (m *Helper) Create(namespace string, modify bool, obj runtime.Object, options *metav1.CreateOptions) (runtime.Object, error) {
func (m *Helper) Create(namespace string, modify bool, obj runtime.Object) (runtime.Object, error) {
return m.CreateWithOptions(namespace, modify, obj, nil)
}
func (m *Helper) CreateWithOptions(namespace string, modify bool, obj runtime.Object, options *metav1.CreateOptions) (runtime.Object, error) {
if options == nil {
options = &metav1.CreateOptions{}
}
if m.ServerDryRun {
options.DryRun = []string{metav1.DryRunAll}
}
if modify {
// Attempt to version the object based on client logic.
version, err := metadataAccessor.ResourceVersion(obj)
@ -135,38 +164,45 @@ func (m *Helper) createResource(c RESTClient, resource, namespace string, obj ru
Resource(resource).
VersionedParams(options, metav1.ParameterCodec).
Body(obj).
Do().
Do(context.TODO()).
Get()
}
func (m *Helper) Patch(namespace, name string, pt types.PatchType, data []byte, options *metav1.PatchOptions) (runtime.Object, error) {
if options == nil {
options = &metav1.PatchOptions{}
}
if m.ServerDryRun {
options.DryRun = []string{metav1.DryRunAll}
}
return m.RESTClient.Patch(pt).
NamespaceIfScoped(namespace, m.NamespaceScoped).
Resource(m.Resource).
Name(name).
VersionedParams(options, metav1.ParameterCodec).
Body(data).
Do().
Do(context.TODO()).
Get()
}
func (m *Helper) Replace(namespace, name string, overwrite bool, obj runtime.Object) (runtime.Object, error) {
c := m.RESTClient
var options = &metav1.UpdateOptions{}
if m.ServerDryRun {
options.DryRun = []string{metav1.DryRunAll}
}
// Attempt to version the object based on client logic.
version, err := metadataAccessor.ResourceVersion(obj)
if err != nil {
// We don't know how to version this object, so send it to the server as is
return m.replaceResource(c, m.Resource, namespace, name, obj)
return m.replaceResource(c, m.Resource, namespace, name, obj, options)
}
if version == "" && overwrite {
// Retrieve the current version of the object to overwrite the server object
serverObj, err := c.Get().NamespaceIfScoped(namespace, m.NamespaceScoped).Resource(m.Resource).Name(name).Do().Get()
serverObj, err := c.Get().NamespaceIfScoped(namespace, m.NamespaceScoped).Resource(m.Resource).Name(name).Do(context.TODO()).Get()
if err != nil {
// The object does not exist, but we want it to be created
return m.replaceResource(c, m.Resource, namespace, name, obj)
return m.replaceResource(c, m.Resource, namespace, name, obj, options)
}
serverVersion, err := metadataAccessor.ResourceVersion(serverObj)
if err != nil {
@ -177,9 +213,16 @@ func (m *Helper) Replace(namespace, name string, overwrite bool, obj runtime.Obj
}
}
return m.replaceResource(c, m.Resource, namespace, name, obj)
return m.replaceResource(c, m.Resource, namespace, name, obj, options)
}
func (m *Helper) replaceResource(c RESTClient, resource, namespace, name string, obj runtime.Object) (runtime.Object, error) {
return c.Put().NamespaceIfScoped(namespace, m.NamespaceScoped).Resource(resource).Name(name).Body(obj).Do().Get()
func (m *Helper) replaceResource(c RESTClient, resource, namespace, name string, obj runtime.Object, options *metav1.UpdateOptions) (runtime.Object, error) {
return c.Put().
NamespaceIfScoped(namespace, m.NamespaceScoped).
Resource(resource).
Name(name).
VersionedParams(options, metav1.ParameterCodec).
Body(obj).
Do(context.TODO()).
Get()
}

View file

@ -18,6 +18,7 @@ package resource
import (
"bytes"
"context"
"fmt"
"io"
"net/http"
@ -30,6 +31,8 @@ import (
"golang.org/x/text/encoding/unicode"
"golang.org/x/text/transform"
"sigs.k8s.io/kustomize/pkg/fs"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -40,7 +43,6 @@ import (
"k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/cli-runtime/pkg/kustomize"
"sigs.k8s.io/kustomize/pkg/fs"
)
const (
@ -100,7 +102,7 @@ func (i *Info) Get() (err error) {
obj, err := NewHelper(i.Client, i.Mapping).Get(i.Namespace, i.Name, i.Export)
if err != nil {
if errors.IsNotFound(err) && len(i.Namespace) > 0 && i.Namespace != metav1.NamespaceDefault && i.Namespace != metav1.NamespaceAll {
err2 := i.Client.Get().AbsPath("api", "v1", "namespaces", i.Namespace).Do().Error()
err2 := i.Client.Get().AbsPath("api", "v1", "namespaces", i.Namespace).Do(context.TODO()).Error()
if err2 != nil && errors.IsNotFound(err2) {
return err2
}
@ -158,7 +160,7 @@ func (i *Info) ObjectName() string {
// String returns the general purpose string representation
func (i *Info) String() string {
basicInfo := fmt.Sprintf("Name: %q, Namespace: %q\nObject: %+q", i.Name, i.Namespace, i.Object)
basicInfo := fmt.Sprintf("Name: %q, Namespace: %q", i.Name, i.Namespace)
if i.Mapping != nil {
mappingInfo := fmt.Sprintf("Resource: %q, GroupVersionKind: %q", i.Mapping.Resource.String(),
i.Mapping.GroupVersionKind.String())
@ -695,7 +697,7 @@ func RetrieveLazy(info *Info, err error) error {
// CreateAndRefresh creates an object from input info and refreshes info with that object
func CreateAndRefresh(info *Info) error {
obj, err := NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object, nil)
obj, err := NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)
if err != nil {
return err
}