mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 20:53:33 +00:00
Use resource package, delete older code
This commit is contained in:
parent
d75a3d5021
commit
a1ee782df5
@ -20,7 +20,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/resource"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ Examples:
|
|||||||
checkErr(err)
|
checkErr(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = kubectl.NewRESTHelper(client, mapping).Create(namespace, true, data)
|
err = resource.NewHelper(client, mapping).Create(namespace, true, data)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
fmt.Fprintf(out, "%s\n", name)
|
fmt.Fprintf(out, "%s\n", name)
|
||||||
},
|
},
|
||||||
|
@ -23,7 +23,7 @@ import (
|
|||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/resource"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (f *Factory) NewCmdDelete(out io.Writer) *cobra.Command {
|
func (f *Factory) NewCmdDelete(out io.Writer) *cobra.Command {
|
||||||
@ -59,9 +59,9 @@ Examples:
|
|||||||
checkErr(err)
|
checkErr(err)
|
||||||
selector := GetFlagString(cmd, "selector")
|
selector := GetFlagString(cmd, "selector")
|
||||||
found := 0
|
found := 0
|
||||||
ResourcesFromArgsOrFile(cmd, args, filename, selector, f.Typer, f.Mapper, f.Client, schema).Visit(func(r *ResourceInfo) error {
|
ResourcesFromArgsOrFile(cmd, args, filename, selector, f.Typer, f.Mapper, f.Client, schema).Visit(func(r *resource.Info) error {
|
||||||
found++
|
found++
|
||||||
if err := kubectl.NewRESTHelper(r.Client, r.Mapping).Delete(r.Namespace, r.Name); err != nil {
|
if err := resource.NewHelper(r.Client, r.Mapping).Delete(r.Namespace, r.Name); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Fprintf(out, "%s\n", r.Name)
|
fmt.Fprintf(out, "%s\n", r.Name)
|
||||||
|
@ -21,7 +21,9 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/resource"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
@ -70,8 +72,13 @@ Examples:
|
|||||||
printer, err := kubectl.GetPrinter(outputFormat, templateFile, outputVersion, mapping.ObjectConvertor, defaultPrinter)
|
printer, err := kubectl.GetPrinter(outputFormat, templateFile, outputVersion, mapping.ObjectConvertor, defaultPrinter)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|
||||||
restHelper := kubectl.NewRESTHelper(client, mapping)
|
restHelper := resource.NewHelper(client, mapping)
|
||||||
obj, err := restHelper.Get(namespace, name, labelSelector)
|
var obj runtime.Object
|
||||||
|
if len(name) == 0 {
|
||||||
|
obj, err = restHelper.List(namespace, labelSelector)
|
||||||
|
} else {
|
||||||
|
obj, err = restHelper.Get(namespace, name)
|
||||||
|
}
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|
||||||
isWatch, isWatchOnly := GetFlagBool(cmd, "watch"), GetFlagBool(cmd, "watch-only")
|
isWatch, isWatchOnly := GetFlagBool(cmd, "watch"), GetFlagBool(cmd, "watch-only")
|
||||||
|
@ -18,122 +18,19 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/resource"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ResourceInfo contains temporary info to execute REST call
|
|
||||||
type ResourceInfo struct {
|
|
||||||
Client kubectl.RESTClient
|
|
||||||
Mapping *meta.RESTMapping
|
|
||||||
Namespace string
|
|
||||||
Name string
|
|
||||||
|
|
||||||
// Optional, this is the most recent value returned by the server if available
|
|
||||||
runtime.Object
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResourceVisitor lets clients walk the list of resources
|
|
||||||
type ResourceVisitor interface {
|
|
||||||
Visit(func(*ResourceInfo) error) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResourceVisitorList []ResourceVisitor
|
|
||||||
|
|
||||||
// Visit implements ResourceVisitor
|
|
||||||
func (l ResourceVisitorList) Visit(fn func(r *ResourceInfo) error) error {
|
|
||||||
for i := range l {
|
|
||||||
if err := l[i].Visit(fn); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewResourceInfo(client kubectl.RESTClient, mapping *meta.RESTMapping, namespace, name string) *ResourceInfo {
|
|
||||||
return &ResourceInfo{
|
|
||||||
Client: client,
|
|
||||||
Mapping: mapping,
|
|
||||||
Namespace: namespace,
|
|
||||||
Name: name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Visit implements ResourceVisitor
|
|
||||||
func (r *ResourceInfo) Visit(fn func(r *ResourceInfo) error) error {
|
|
||||||
return fn(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResourceSelector is a facade for all the resources fetched via label selector
|
|
||||||
type ResourceSelector struct {
|
|
||||||
Client kubectl.RESTClient
|
|
||||||
Mapping *meta.RESTMapping
|
|
||||||
Namespace string
|
|
||||||
Selector labels.Selector
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewResourceSelector creates a resource selector which hides details of getting items by their label selector.
|
|
||||||
func NewResourceSelector(client kubectl.RESTClient, mapping *meta.RESTMapping, namespace string, selector labels.Selector) *ResourceSelector {
|
|
||||||
return &ResourceSelector{
|
|
||||||
Client: client,
|
|
||||||
Mapping: mapping,
|
|
||||||
Namespace: namespace,
|
|
||||||
Selector: selector,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Visit implements ResourceVisitor
|
|
||||||
func (r *ResourceSelector) Visit(fn func(r *ResourceInfo) error) error {
|
|
||||||
list, err := kubectl.NewRESTHelper(r.Client, r.Mapping).List(r.Namespace, r.Selector)
|
|
||||||
if err != nil {
|
|
||||||
if errors.IsBadRequest(err) || errors.IsNotFound(err) {
|
|
||||||
glog.V(2).Infof("Unable to perform a label selector query on %s with labels %s: %v", r.Mapping.Resource, r.Selector, err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
items, err := runtime.ExtractList(list)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
accessor := meta.NewAccessor()
|
|
||||||
for i := range items {
|
|
||||||
name, err := accessor.Name(items[i])
|
|
||||||
if err != nil {
|
|
||||||
// items without names cannot be visited
|
|
||||||
glog.V(2).Infof("Found %s with labels %s, but can't access the item by name.", r.Mapping.Resource, r.Selector)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
item := &ResourceInfo{
|
|
||||||
Client: r.Client,
|
|
||||||
Mapping: r.Mapping,
|
|
||||||
Namespace: r.Namespace,
|
|
||||||
Name: name,
|
|
||||||
Object: items[i],
|
|
||||||
}
|
|
||||||
if err := fn(item); err != nil {
|
|
||||||
if errors.IsNotFound(err) {
|
|
||||||
glog.V(2).Infof("Found %s named %q, but can't be accessed now: %v", r.Mapping.Resource, name, err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
log.Printf("got error for resource %s: %v", r.Mapping.Resource, err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResourcesFromArgsOrFile computes a list of Resources by extracting info from filename or args. It will
|
// ResourcesFromArgsOrFile computes a list of Resources by extracting info from filename or args. It will
|
||||||
// handle label selectors provided.
|
// handle label selectors provided.
|
||||||
func ResourcesFromArgsOrFile(
|
func ResourcesFromArgsOrFile(
|
||||||
@ -144,7 +41,7 @@ func ResourcesFromArgsOrFile(
|
|||||||
mapper meta.RESTMapper,
|
mapper meta.RESTMapper,
|
||||||
clientBuilder func(cmd *cobra.Command, mapping *meta.RESTMapping) (kubectl.RESTClient, error),
|
clientBuilder func(cmd *cobra.Command, mapping *meta.RESTMapping) (kubectl.RESTClient, error),
|
||||||
schema validation.Schema,
|
schema validation.Schema,
|
||||||
) ResourceVisitor {
|
) resource.Visitor {
|
||||||
|
|
||||||
// handling filename & resource id
|
// handling filename & resource id
|
||||||
if len(selector) == 0 {
|
if len(selector) == 0 {
|
||||||
@ -152,34 +49,34 @@ func ResourcesFromArgsOrFile(
|
|||||||
client, err := clientBuilder(cmd, mapping)
|
client, err := clientBuilder(cmd, mapping)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|
||||||
return NewResourceInfo(client, mapping, namespace, name)
|
return resource.NewInfo(client, mapping, namespace, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
labelSelector, err := labels.ParseSelector(selector)
|
labelSelector, err := labels.ParseSelector(selector)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|
||||||
namespace := GetKubeNamespace(cmd)
|
namespace := GetKubeNamespace(cmd)
|
||||||
visitors := ResourceVisitorList{}
|
visitors := resource.VisitorList{}
|
||||||
|
|
||||||
if len(args) != 1 {
|
if len(args) != 1 {
|
||||||
usageError(cmd, "Must specify the type of resource")
|
usageError(cmd, "Must specify the type of resource")
|
||||||
}
|
}
|
||||||
types := SplitResourceArgument(args[0])
|
types := SplitResourceArgument(args[0])
|
||||||
for _, arg := range types {
|
for _, arg := range types {
|
||||||
resource := kubectl.ExpandResourceShortcut(arg)
|
resourceName := kubectl.ExpandResourceShortcut(arg)
|
||||||
if len(resource) == 0 {
|
if len(resourceName) == 0 {
|
||||||
usageError(cmd, "Unknown resource %s", resource)
|
usageError(cmd, "Unknown resource %s", resourceName)
|
||||||
}
|
}
|
||||||
version, kind, err := mapper.VersionAndKindForResource(resource)
|
version, kind, err := mapper.VersionAndKindForResource(resourceName)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|
||||||
mapping, err := mapper.RESTMapping(version, kind)
|
mapping, err := mapper.RESTMapping(kind, version)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|
||||||
client, err := clientBuilder(cmd, mapping)
|
client, err := clientBuilder(cmd, mapping)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|
||||||
visitors = append(visitors, NewResourceSelector(client, mapping, namespace, labelSelector))
|
visitors = append(visitors, resource.NewSelector(client, mapping, namespace, labelSelector))
|
||||||
}
|
}
|
||||||
return visitors
|
return visitors
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/resource"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -52,7 +52,7 @@ Examples:
|
|||||||
err = CompareNamespaceFromFile(cmd, namespace)
|
err = CompareNamespaceFromFile(cmd, namespace)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|
||||||
err = kubectl.NewRESTHelper(client, mapping).Update(namespace, name, true, data)
|
err = resource.NewHelper(client, mapping).Update(namespace, name, true, data)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
fmt.Fprintf(out, "%s\n", name)
|
fmt.Fprintf(out, "%s\n", name)
|
||||||
},
|
},
|
||||||
|
@ -1,146 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2014 Google Inc. All rights reserved.
|
|
||||||
|
|
||||||
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 kubectl
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
|
||||||
)
|
|
||||||
|
|
||||||
// RESTHelper provides methods for retrieving or mutating a RESTful
|
|
||||||
// resource.
|
|
||||||
type RESTHelper struct {
|
|
||||||
Resource string
|
|
||||||
// A RESTClient capable of mutating this resource
|
|
||||||
RESTClient RESTClient
|
|
||||||
// A codec for decoding and encoding objects of this resource type.
|
|
||||||
Codec runtime.Codec
|
|
||||||
// An interface for reading or writing the resource version of this
|
|
||||||
// type.
|
|
||||||
Versioner runtime.ResourceVersioner
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewRESTHelper creates a RESTHelper from a ResourceMapping
|
|
||||||
func NewRESTHelper(client RESTClient, mapping *meta.RESTMapping) *RESTHelper {
|
|
||||||
return &RESTHelper{
|
|
||||||
RESTClient: client,
|
|
||||||
Resource: mapping.Resource,
|
|
||||||
Codec: mapping.Codec,
|
|
||||||
Versioner: mapping.MetadataAccessor,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *RESTHelper) Get(namespace, name string, selector labels.Selector) (runtime.Object, error) {
|
|
||||||
return m.RESTClient.Get().Resource(m.Resource).Namespace(namespace).Name(name).SelectorParam("labels", selector).Do().Get()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *RESTHelper) List(namespace string, selector labels.Selector) (runtime.Object, error) {
|
|
||||||
return m.RESTClient.Get().Resource(m.Resource).Namespace(namespace).SelectorParam("labels", selector).Do().Get()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *RESTHelper) Watch(namespace, resourceVersion string, labelSelector, fieldSelector labels.Selector) (watch.Interface, error) {
|
|
||||||
return m.RESTClient.Get().
|
|
||||||
Prefix("watch").
|
|
||||||
Namespace(namespace).
|
|
||||||
Resource(m.Resource).
|
|
||||||
Param("resourceVersion", resourceVersion).
|
|
||||||
SelectorParam("labels", labelSelector).
|
|
||||||
SelectorParam("fields", fieldSelector).
|
|
||||||
Watch()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *RESTHelper) Delete(namespace, name string) error {
|
|
||||||
return m.RESTClient.Delete().Namespace(namespace).Resource(m.Resource).Name(name).Do().Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *RESTHelper) Create(namespace string, modify bool, data []byte) error {
|
|
||||||
if modify {
|
|
||||||
obj, err := m.Codec.Decode(data)
|
|
||||||
if err != nil {
|
|
||||||
// We don't know how to check a version on this object, but create it anyway
|
|
||||||
return createResource(m.RESTClient, m.Resource, namespace, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt to version the object based on client logic.
|
|
||||||
version, err := m.Versioner.ResourceVersion(obj)
|
|
||||||
if err != nil {
|
|
||||||
// We don't know how to clear the version on this object, so send it to the server as is
|
|
||||||
return createResource(m.RESTClient, m.Resource, namespace, data)
|
|
||||||
}
|
|
||||||
if version != "" {
|
|
||||||
if err := m.Versioner.SetResourceVersion(obj, ""); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
newData, err := m.Codec.Encode(obj)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
data = newData
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return createResource(m.RESTClient, m.Resource, namespace, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createResource(c RESTClient, resource, namespace string, data []byte) error {
|
|
||||||
return c.Post().Namespace(namespace).Resource(resource).Body(data).Do().Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *RESTHelper) Update(namespace, name string, overwrite bool, data []byte) error {
|
|
||||||
c := m.RESTClient
|
|
||||||
|
|
||||||
obj, err := m.Codec.Decode(data)
|
|
||||||
if err != nil {
|
|
||||||
// We don't know how to handle this object, but update it anyway
|
|
||||||
return updateResource(c, m.Resource, namespace, name, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt to version the object based on client logic.
|
|
||||||
version, err := m.Versioner.ResourceVersion(obj)
|
|
||||||
if err != nil {
|
|
||||||
// We don't know how to version this object, so send it to the server as is
|
|
||||||
return updateResource(c, m.Resource, namespace, name, data)
|
|
||||||
}
|
|
||||||
if version == "" && overwrite {
|
|
||||||
// Retrieve the current version of the object to overwrite the server object
|
|
||||||
serverObj, err := c.Get().Resource(m.Resource).Name(name).Do().Get()
|
|
||||||
if err != nil {
|
|
||||||
// The object does not exist, but we want it to be created
|
|
||||||
return updateResource(c, m.Resource, namespace, name, data)
|
|
||||||
}
|
|
||||||
serverVersion, err := m.Versioner.ResourceVersion(serverObj)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := m.Versioner.SetResourceVersion(obj, serverVersion); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
newData, err := m.Codec.Encode(obj)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
data = newData
|
|
||||||
}
|
|
||||||
|
|
||||||
return updateResource(c, m.Resource, namespace, name, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateResource(c RESTClient, resource, namespace, name string, data []byte) error {
|
|
||||||
return c.Put().Namespace(namespace).Resource(resource).Name(name).Body(data).Do().Error()
|
|
||||||
}
|
|
@ -1,393 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2014 Google Inc. All rights reserved.
|
|
||||||
|
|
||||||
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 kubectl
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
func objBody(obj runtime.Object) io.ReadCloser {
|
|
||||||
return ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(testapi.Codec(), obj))))
|
|
||||||
}
|
|
||||||
|
|
||||||
// splitPath returns the segments for a URL path.
|
|
||||||
func splitPath(path string) []string {
|
|
||||||
path = strings.Trim(path, "/")
|
|
||||||
if path == "" {
|
|
||||||
return []string{}
|
|
||||||
}
|
|
||||||
return strings.Split(path, "/")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRESTHelperDelete(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
Err bool
|
|
||||||
Req func(*http.Request) bool
|
|
||||||
Resp *http.Response
|
|
||||||
HttpErr error
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
HttpErr: errors.New("failure"),
|
|
||||||
Err: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Resp: &http.Response{
|
|
||||||
StatusCode: http.StatusNotFound,
|
|
||||||
Body: objBody(&api.Status{Status: api.StatusFailure}),
|
|
||||||
},
|
|
||||||
Err: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Resp: &http.Response{
|
|
||||||
StatusCode: http.StatusOK,
|
|
||||||
Body: objBody(&api.Status{Status: api.StatusSuccess}),
|
|
||||||
},
|
|
||||||
Req: func(req *http.Request) bool {
|
|
||||||
if req.Method != "DELETE" {
|
|
||||||
t.Errorf("unexpected method: %#v", req)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
parts := splitPath(req.URL.Path)
|
|
||||||
if parts[1] != "bar" {
|
|
||||||
t.Errorf("url doesn't contain namespace: %#v", req)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if parts[2] != "foo" {
|
|
||||||
t.Errorf("url doesn't contain name: %#v", req)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, test := range tests {
|
|
||||||
client := &client.FakeRESTClient{
|
|
||||||
Codec: testapi.Codec(),
|
|
||||||
Resp: test.Resp,
|
|
||||||
Err: test.HttpErr,
|
|
||||||
}
|
|
||||||
modifier := &RESTHelper{
|
|
||||||
RESTClient: client,
|
|
||||||
}
|
|
||||||
err := modifier.Delete("bar", "foo")
|
|
||||||
if (err != nil) != test.Err {
|
|
||||||
t.Errorf("unexpected error: %t %v", test.Err, err)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if test.Req != nil && !test.Req(client.Req) {
|
|
||||||
t.Errorf("unexpected request: %#v", client.Req)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRESTHelperCreate(t *testing.T) {
|
|
||||||
expectPost := func(req *http.Request) bool {
|
|
||||||
if req.Method != "POST" {
|
|
||||||
t.Errorf("unexpected method: %#v", req)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
parts := splitPath(req.URL.Path)
|
|
||||||
if parts[1] != "bar" {
|
|
||||||
t.Errorf("url doesn't contain namespace: %#v", req)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
tests := []struct {
|
|
||||||
Resp *http.Response
|
|
||||||
RespFunc client.HTTPClientFunc
|
|
||||||
HttpErr error
|
|
||||||
Modify bool
|
|
||||||
Object runtime.Object
|
|
||||||
|
|
||||||
ExpectObject runtime.Object
|
|
||||||
Err bool
|
|
||||||
Req func(*http.Request) bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
HttpErr: errors.New("failure"),
|
|
||||||
Err: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Resp: &http.Response{
|
|
||||||
StatusCode: http.StatusNotFound,
|
|
||||||
Body: objBody(&api.Status{Status: api.StatusFailure}),
|
|
||||||
},
|
|
||||||
Err: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Resp: &http.Response{
|
|
||||||
StatusCode: http.StatusOK,
|
|
||||||
Body: objBody(&api.Status{Status: api.StatusSuccess}),
|
|
||||||
},
|
|
||||||
Object: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}},
|
|
||||||
ExpectObject: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}},
|
|
||||||
Req: expectPost,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Modify: false,
|
|
||||||
Object: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "10"}},
|
|
||||||
ExpectObject: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "10"}},
|
|
||||||
Resp: &http.Response{StatusCode: http.StatusOK, Body: objBody(&api.Status{Status: api.StatusSuccess})},
|
|
||||||
Req: expectPost,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Modify: true,
|
|
||||||
Object: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "10"}},
|
|
||||||
ExpectObject: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}},
|
|
||||||
Resp: &http.Response{StatusCode: http.StatusOK, Body: objBody(&api.Status{Status: api.StatusSuccess})},
|
|
||||||
Req: expectPost,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for i, test := range tests {
|
|
||||||
client := &client.FakeRESTClient{
|
|
||||||
Codec: testapi.Codec(),
|
|
||||||
Resp: test.Resp,
|
|
||||||
Err: test.HttpErr,
|
|
||||||
}
|
|
||||||
if test.RespFunc != nil {
|
|
||||||
client.Client = test.RespFunc
|
|
||||||
}
|
|
||||||
modifier := &RESTHelper{
|
|
||||||
RESTClient: client,
|
|
||||||
Codec: testapi.Codec(),
|
|
||||||
Versioner: testapi.MetadataAccessor(),
|
|
||||||
}
|
|
||||||
data := []byte{}
|
|
||||||
if test.Object != nil {
|
|
||||||
data = []byte(runtime.EncodeOrDie(testapi.Codec(), test.Object))
|
|
||||||
}
|
|
||||||
err := modifier.Create("bar", test.Modify, data)
|
|
||||||
if (err != nil) != test.Err {
|
|
||||||
t.Errorf("%d: unexpected error: %t %v", i, test.Err, err)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if test.Req != nil && !test.Req(client.Req) {
|
|
||||||
t.Errorf("%d: unexpected request: %#v", i, client.Req)
|
|
||||||
}
|
|
||||||
body, err := ioutil.ReadAll(client.Req.Body)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("%d: unexpected error: %#v", i, err)
|
|
||||||
}
|
|
||||||
t.Logf("got body: %s", string(body))
|
|
||||||
expect := []byte{}
|
|
||||||
if test.ExpectObject != nil {
|
|
||||||
expect = []byte(runtime.EncodeOrDie(testapi.Codec(), test.ExpectObject))
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(expect, body) {
|
|
||||||
t.Errorf("%d: unexpected body: %s", i, string(body))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRESTHelperGet(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
Err bool
|
|
||||||
Req func(*http.Request) bool
|
|
||||||
Resp *http.Response
|
|
||||||
HttpErr error
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
HttpErr: errors.New("failure"),
|
|
||||||
Err: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Resp: &http.Response{
|
|
||||||
StatusCode: http.StatusNotFound,
|
|
||||||
Body: objBody(&api.Status{Status: api.StatusFailure}),
|
|
||||||
},
|
|
||||||
Err: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Resp: &http.Response{
|
|
||||||
StatusCode: http.StatusOK,
|
|
||||||
Body: objBody(&api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}}),
|
|
||||||
},
|
|
||||||
Req: func(req *http.Request) bool {
|
|
||||||
if req.Method != "GET" {
|
|
||||||
t.Errorf("unexpected method: %#v", req)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
parts := splitPath(req.URL.Path)
|
|
||||||
if parts[1] != "bar" {
|
|
||||||
t.Errorf("url doesn't contain namespace: %#v", req)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if parts[2] != "foo" {
|
|
||||||
t.Errorf("url doesn't contain name: %#v", req)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, test := range tests {
|
|
||||||
client := &client.FakeRESTClient{
|
|
||||||
Codec: testapi.Codec(),
|
|
||||||
Resp: test.Resp,
|
|
||||||
Err: test.HttpErr,
|
|
||||||
}
|
|
||||||
modifier := &RESTHelper{
|
|
||||||
RESTClient: client,
|
|
||||||
}
|
|
||||||
obj, err := modifier.Get("bar", "foo", labels.Everything())
|
|
||||||
if (err != nil) != test.Err {
|
|
||||||
t.Errorf("unexpected error: %t %v", test.Err, err)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if obj.(*api.Pod).Name != "foo" {
|
|
||||||
t.Errorf("unexpected object: %#v", obj)
|
|
||||||
}
|
|
||||||
if test.Req != nil && !test.Req(client.Req) {
|
|
||||||
t.Errorf("unexpected request: %#v", client.Req)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRESTHelperUpdate(t *testing.T) {
|
|
||||||
expectPut := func(req *http.Request) bool {
|
|
||||||
if req.Method != "PUT" {
|
|
||||||
t.Errorf("unexpected method: %#v", req)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
parts := splitPath(req.URL.Path)
|
|
||||||
if parts[1] != "bar" {
|
|
||||||
t.Errorf("url doesn't contain namespace: %#v", req.URL)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if parts[2] != "foo" {
|
|
||||||
t.Errorf("url doesn't contain name: %#v", req)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
tests := []struct {
|
|
||||||
Resp *http.Response
|
|
||||||
RespFunc client.HTTPClientFunc
|
|
||||||
HttpErr error
|
|
||||||
Overwrite bool
|
|
||||||
Object runtime.Object
|
|
||||||
|
|
||||||
ExpectObject runtime.Object
|
|
||||||
Err bool
|
|
||||||
Req func(*http.Request) bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
HttpErr: errors.New("failure"),
|
|
||||||
Err: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}},
|
|
||||||
Resp: &http.Response{
|
|
||||||
StatusCode: http.StatusNotFound,
|
|
||||||
Body: objBody(&api.Status{Status: api.StatusFailure}),
|
|
||||||
},
|
|
||||||
Err: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}},
|
|
||||||
ExpectObject: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}},
|
|
||||||
Resp: &http.Response{
|
|
||||||
StatusCode: http.StatusOK,
|
|
||||||
Body: objBody(&api.Status{Status: api.StatusSuccess}),
|
|
||||||
},
|
|
||||||
Req: expectPut,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}},
|
|
||||||
ExpectObject: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "10"}},
|
|
||||||
|
|
||||||
Overwrite: true,
|
|
||||||
RespFunc: func(req *http.Request) (*http.Response, error) {
|
|
||||||
if req.Method == "PUT" {
|
|
||||||
return &http.Response{StatusCode: http.StatusOK, Body: objBody(&api.Status{Status: api.StatusSuccess})}, nil
|
|
||||||
}
|
|
||||||
return &http.Response{StatusCode: http.StatusOK, Body: objBody(&api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "10"}})}, nil
|
|
||||||
},
|
|
||||||
Req: expectPut,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "10"}},
|
|
||||||
ExpectObject: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "10"}},
|
|
||||||
Resp: &http.Response{StatusCode: http.StatusOK, Body: objBody(&api.Status{Status: api.StatusSuccess})},
|
|
||||||
Req: expectPut,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for i, test := range tests {
|
|
||||||
client := &client.FakeRESTClient{
|
|
||||||
Codec: testapi.Codec(),
|
|
||||||
Resp: test.Resp,
|
|
||||||
Err: test.HttpErr,
|
|
||||||
}
|
|
||||||
if test.RespFunc != nil {
|
|
||||||
client.Client = test.RespFunc
|
|
||||||
}
|
|
||||||
modifier := &RESTHelper{
|
|
||||||
RESTClient: client,
|
|
||||||
Codec: testapi.Codec(),
|
|
||||||
Versioner: testapi.MetadataAccessor(),
|
|
||||||
}
|
|
||||||
data := []byte{}
|
|
||||||
if test.Object != nil {
|
|
||||||
data = []byte(runtime.EncodeOrDie(testapi.Codec(), test.Object))
|
|
||||||
}
|
|
||||||
err := modifier.Update("bar", "foo", test.Overwrite, data)
|
|
||||||
if (err != nil) != test.Err {
|
|
||||||
t.Errorf("%d: unexpected error: %t %v", i, test.Err, err)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if test.Req != nil && !test.Req(client.Req) {
|
|
||||||
t.Errorf("%d: unexpected request: %#v", i, client.Req)
|
|
||||||
}
|
|
||||||
body, err := ioutil.ReadAll(client.Req.Body)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("%d: unexpected error: %#v", i, err)
|
|
||||||
}
|
|
||||||
t.Logf("got body: %s", string(body))
|
|
||||||
expect := []byte{}
|
|
||||||
if test.ExpectObject != nil {
|
|
||||||
expect = []byte(runtime.EncodeOrDie(testapi.Codec(), test.ExpectObject))
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(expect, body) {
|
|
||||||
t.Errorf("%d: unexpected body: %s", i, string(body))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user