mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 14:37:00 +00:00
Merge pull request #3196 from smarterclayton/allow_create_to_span_resources
Allow create to handle multiple resources, remove createall
This commit is contained in:
commit
de2e298fa9
@ -4,5 +4,5 @@
|
|||||||
|
|
||||||
### Usage
|
### Usage
|
||||||
```
|
```
|
||||||
$ flags2yaml image=dockerfile/nginx | simplegen - | cluster/kubectl.sh createall -f -
|
$ flags2yaml image=dockerfile/nginx | simplegen - | cluster/kubectl.sh create -f -
|
||||||
```
|
```
|
||||||
|
@ -41,8 +41,8 @@ portSpec: 10001:6379
|
|||||||
```
|
```
|
||||||
Output:
|
Output:
|
||||||
```
|
```
|
||||||
$ simplegen redismaster.yaml | cluster/kubectl.sh createall -f -
|
$ simplegen redismaster.yaml | cluster/kubectl.sh create -f -
|
||||||
$ simplegen redisslave.yaml | cluster/kubectl.sh createall -f -
|
$ simplegen redisslave.yaml | cluster/kubectl.sh create -f -
|
||||||
$ cluster/kubectl.sh get services
|
$ cluster/kubectl.sh get services
|
||||||
NAME LABELS SELECTOR IP PORT
|
NAME LABELS SELECTOR IP PORT
|
||||||
kubernetes-ro component=apiserver,provider=kubernetes 10.0.0.2 80
|
kubernetes-ro component=apiserver,provider=kubernetes 10.0.0.2 80
|
||||||
|
@ -16,8 +16,8 @@ limitations under the License.
|
|||||||
|
|
||||||
// simplegen is a tool to generate simple services from a simple description
|
// simplegen is a tool to generate simple services from a simple description
|
||||||
//
|
//
|
||||||
// $ simplegen myservice.json | kubectl createall -f -
|
// $ simplegen myservice.json | kubectl create -f -
|
||||||
// $ simplegen myservice.yaml | kubectl createall -f -
|
// $ simplegen myservice.yaml | kubectl create -f -
|
||||||
//
|
//
|
||||||
// This is completely separate from kubectl at the moment, until we figure out
|
// This is completely separate from kubectl at the moment, until we figure out
|
||||||
// what the right integration approach is.
|
// what the right integration approach is.
|
||||||
|
@ -17,8 +17,8 @@ limitations under the License.
|
|||||||
// srvexpand is a tool to generate non-trivial but regular services
|
// srvexpand is a tool to generate non-trivial but regular services
|
||||||
// from a description free of most boilerplate
|
// from a description free of most boilerplate
|
||||||
//
|
//
|
||||||
// $ srvexpand myservice.json | kubectl createall -f -
|
// $ srvexpand myservice.json | kubectl create -f -
|
||||||
// $ srvexpand myservice.yaml | kubectl createall -f -
|
// $ srvexpand myservice.yaml | kubectl create -f -
|
||||||
//
|
//
|
||||||
// This is completely separate from kubectl at the moment, until we figure out
|
// This is completely separate from kubectl at the moment, until we figure out
|
||||||
// what the right integration approach is.
|
// what the right integration approach is.
|
||||||
|
@ -48,16 +48,15 @@ type Factory struct {
|
|||||||
clients *clientCache
|
clients *clientCache
|
||||||
flags *pflag.FlagSet
|
flags *pflag.FlagSet
|
||||||
|
|
||||||
Mapper meta.RESTMapper
|
// Returns interfaces for dealing with arbitrary runtime.Objects.
|
||||||
Typer runtime.ObjectTyper
|
Object func(cmd *cobra.Command) (meta.RESTMapper, runtime.ObjectTyper)
|
||||||
|
|
||||||
// Returns a client for accessing Kubernetes resources or an error.
|
// Returns a client for accessing Kubernetes resources or an error.
|
||||||
Client func(cmd *cobra.Command) (*client.Client, error)
|
Client func(cmd *cobra.Command) (*client.Client, error)
|
||||||
// Returns a client.Config for accessing the Kubernetes server.
|
// Returns a client.Config for accessing the Kubernetes server.
|
||||||
ClientConfig func(cmd *cobra.Command) (*client.Config, error)
|
ClientConfig func(cmd *cobra.Command) (*client.Config, error)
|
||||||
// Returns a RESTClient for working with the specified RESTMapping or an error. This is intended
|
// Returns a RESTClient for working with the specified RESTMapping or an error. This is intended
|
||||||
// for working with arbitrary resources and is not guaranteed to point to a Kubernetes APIServer.
|
// for working with arbitrary resources and is not guaranteed to point to a Kubernetes APIServer.
|
||||||
RESTClient func(cmd *cobra.Command, mapping *meta.RESTMapping) (kubectl.RESTClient, error)
|
RESTClient func(cmd *cobra.Command, mapping *meta.RESTMapping) (resource.RESTClient, error)
|
||||||
// Returns a Describer for displaying the specified RESTMapping type or an error.
|
// Returns a Describer for displaying the specified RESTMapping type or an error.
|
||||||
Describer func(cmd *cobra.Command, mapping *meta.RESTMapping) (kubectl.Describer, error)
|
Describer func(cmd *cobra.Command, mapping *meta.RESTMapping) (kubectl.Describer, error)
|
||||||
// Returns a Printer for formatting objects of the given type or an error.
|
// Returns a Printer for formatting objects of the given type or an error.
|
||||||
@ -81,16 +80,17 @@ func NewFactory() *Factory {
|
|||||||
clients: clients,
|
clients: clients,
|
||||||
flags: flags,
|
flags: flags,
|
||||||
|
|
||||||
Mapper: mapper,
|
Object: func(cmd *cobra.Command) (meta.RESTMapper, runtime.ObjectTyper) {
|
||||||
Typer: api.Scheme,
|
version := GetFlagString(cmd, "api-version")
|
||||||
|
return kubectl.OutputVersionMapper{mapper, version}, api.Scheme
|
||||||
|
},
|
||||||
Client: func(cmd *cobra.Command) (*client.Client, error) {
|
Client: func(cmd *cobra.Command) (*client.Client, error) {
|
||||||
return clients.ClientForVersion("")
|
return clients.ClientForVersion("")
|
||||||
},
|
},
|
||||||
ClientConfig: func(cmd *cobra.Command) (*client.Config, error) {
|
ClientConfig: func(cmd *cobra.Command) (*client.Config, error) {
|
||||||
return clients.ClientConfigForVersion("")
|
return clients.ClientConfigForVersion("")
|
||||||
},
|
},
|
||||||
RESTClient: func(cmd *cobra.Command, mapping *meta.RESTMapping) (kubectl.RESTClient, error) {
|
RESTClient: func(cmd *cobra.Command, mapping *meta.RESTMapping) (resource.RESTClient, error) {
|
||||||
client, err := clients.ClientForVersion(mapping.APIVersion)
|
client, err := clients.ClientForVersion(mapping.APIVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -165,7 +165,6 @@ Find more information at https://github.com/GoogleCloudPlatform/kubernetes.`,
|
|||||||
cmds.AddCommand(f.NewCmdGet(out))
|
cmds.AddCommand(f.NewCmdGet(out))
|
||||||
cmds.AddCommand(f.NewCmdDescribe(out))
|
cmds.AddCommand(f.NewCmdDescribe(out))
|
||||||
cmds.AddCommand(f.NewCmdCreate(out))
|
cmds.AddCommand(f.NewCmdCreate(out))
|
||||||
cmds.AddCommand(f.NewCmdCreateAll(out))
|
|
||||||
cmds.AddCommand(f.NewCmdUpdate(out))
|
cmds.AddCommand(f.NewCmdUpdate(out))
|
||||||
cmds.AddCommand(f.NewCmdDelete(out))
|
cmds.AddCommand(f.NewCmdDelete(out))
|
||||||
|
|
||||||
|
@ -25,8 +25,10 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||||
"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/kubectl"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl"
|
||||||
. "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd"
|
. "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/resource"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@ -90,19 +92,27 @@ func (t *testDescriber) Describe(namespace, name string) (output string, err err
|
|||||||
}
|
}
|
||||||
|
|
||||||
type testFactory struct {
|
type testFactory struct {
|
||||||
|
Mapper meta.RESTMapper
|
||||||
|
Typer runtime.ObjectTyper
|
||||||
Client kubectl.RESTClient
|
Client kubectl.RESTClient
|
||||||
Describer kubectl.Describer
|
Describer kubectl.Describer
|
||||||
Printer kubectl.ResourcePrinter
|
Printer kubectl.ResourcePrinter
|
||||||
|
Validator validation.Schema
|
||||||
Err error
|
Err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTestFactory() (*Factory, *testFactory, runtime.Codec) {
|
func NewTestFactory() (*Factory, *testFactory, runtime.Codec) {
|
||||||
scheme, mapper, codec := newExternalScheme()
|
scheme, mapper, codec := newExternalScheme()
|
||||||
t := &testFactory{}
|
t := &testFactory{
|
||||||
|
Validator: validation.NullSchema{},
|
||||||
|
Mapper: mapper,
|
||||||
|
Typer: scheme,
|
||||||
|
}
|
||||||
return &Factory{
|
return &Factory{
|
||||||
Mapper: mapper,
|
Object: func(*cobra.Command) (meta.RESTMapper, runtime.ObjectTyper) {
|
||||||
Typer: scheme,
|
return t.Mapper, t.Typer
|
||||||
RESTClient: func(*cobra.Command, *meta.RESTMapping) (kubectl.RESTClient, error) {
|
},
|
||||||
|
RESTClient: func(*cobra.Command, *meta.RESTMapping) (resource.RESTClient, error) {
|
||||||
return t.Client, t.Err
|
return t.Client, t.Err
|
||||||
},
|
},
|
||||||
Describer: func(*cobra.Command, *meta.RESTMapping) (kubectl.Describer, error) {
|
Describer: func(*cobra.Command, *meta.RESTMapping) (kubectl.Describer, error) {
|
||||||
@ -111,15 +121,21 @@ func NewTestFactory() (*Factory, *testFactory, runtime.Codec) {
|
|||||||
Printer: func(cmd *cobra.Command, mapping *meta.RESTMapping, noHeaders bool) (kubectl.ResourcePrinter, error) {
|
Printer: func(cmd *cobra.Command, mapping *meta.RESTMapping, noHeaders bool) (kubectl.ResourcePrinter, error) {
|
||||||
return t.Printer, t.Err
|
return t.Printer, t.Err
|
||||||
},
|
},
|
||||||
|
Validator: func(cmd *cobra.Command) (validation.Schema, error) {
|
||||||
|
return t.Validator, t.Err
|
||||||
|
},
|
||||||
}, t, codec
|
}, t, codec
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAPIFactory() (*Factory, *testFactory, runtime.Codec) {
|
func NewAPIFactory() (*Factory, *testFactory, runtime.Codec) {
|
||||||
t := &testFactory{}
|
t := &testFactory{
|
||||||
|
Validator: validation.NullSchema{},
|
||||||
|
}
|
||||||
return &Factory{
|
return &Factory{
|
||||||
Mapper: latest.RESTMapper,
|
Object: func(*cobra.Command) (meta.RESTMapper, runtime.ObjectTyper) {
|
||||||
Typer: api.Scheme,
|
return latest.RESTMapper, api.Scheme
|
||||||
RESTClient: func(*cobra.Command, *meta.RESTMapping) (kubectl.RESTClient, error) {
|
},
|
||||||
|
RESTClient: func(*cobra.Command, *meta.RESTMapping) (resource.RESTClient, error) {
|
||||||
return t.Client, t.Err
|
return t.Client, t.Err
|
||||||
},
|
},
|
||||||
Describer: func(*cobra.Command, *meta.RESTMapping) (kubectl.Describer, error) {
|
Describer: func(*cobra.Command, *meta.RESTMapping) (kubectl.Describer, error) {
|
||||||
@ -128,6 +144,9 @@ func NewAPIFactory() (*Factory, *testFactory, runtime.Codec) {
|
|||||||
Printer: func(cmd *cobra.Command, mapping *meta.RESTMapping, noHeaders bool) (kubectl.ResourcePrinter, error) {
|
Printer: func(cmd *cobra.Command, mapping *meta.RESTMapping, noHeaders bool) (kubectl.ResourcePrinter, error) {
|
||||||
return t.Printer, t.Err
|
return t.Printer, t.Err
|
||||||
},
|
},
|
||||||
|
Validator: func(cmd *cobra.Command) (validation.Schema, error) {
|
||||||
|
return t.Validator, t.Err
|
||||||
|
},
|
||||||
}, t, latest.Codec
|
}, t, latest.Codec
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,11 +20,16 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/resource"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/resource"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (f *Factory) NewCmdCreate(out io.Writer) *cobra.Command {
|
func (f *Factory) NewCmdCreate(out io.Writer) *cobra.Command {
|
||||||
|
flags := &struct {
|
||||||
|
Filenames util.StringList
|
||||||
|
}{}
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "create -f filename",
|
Use: "create -f filename",
|
||||||
Short: "Create a resource by filename or stdin",
|
Short: "Create a resource by filename or stdin",
|
||||||
@ -39,29 +44,35 @@ Examples:
|
|||||||
$ cat pod.json | kubectl create -f -
|
$ cat pod.json | kubectl create -f -
|
||||||
<create a pod based on the json passed into stdin>`,
|
<create a pod based on the json passed into stdin>`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
filename := GetFlagString(cmd, "filename")
|
|
||||||
if len(filename) == 0 {
|
|
||||||
usageError(cmd, "Must specify filename to create")
|
|
||||||
}
|
|
||||||
schema, err := f.Validator(cmd)
|
schema, err := f.Validator(cmd)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
mapping, namespace, name, data := ResourceFromFile(cmd, filename, f.Typer, f.Mapper, schema)
|
|
||||||
client, err := f.RESTClient(cmd, mapping)
|
|
||||||
checkErr(err)
|
|
||||||
|
|
||||||
// use the default namespace if not specified, or check for conflict with the file's namespace
|
mapper, typer := f.Object(cmd)
|
||||||
if len(namespace) == 0 {
|
r := resource.NewBuilder(mapper, typer, ClientMapperForCommand(cmd, f)).
|
||||||
namespace = GetKubeNamespace(cmd)
|
ContinueOnError().
|
||||||
} else {
|
NamespaceParam(GetKubeNamespace(cmd)).RequireNamespace().
|
||||||
err = CompareNamespaceFromFile(cmd, namespace)
|
FilenameParam(flags.Filenames...).
|
||||||
checkErr(err)
|
Flatten().
|
||||||
}
|
Do()
|
||||||
|
|
||||||
err = resource.NewHelper(client, mapping).Create(namespace, true, data)
|
err = r.Visit(func(info *resource.Info) error {
|
||||||
|
data, err := info.Mapping.Codec.Encode(info.Object)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := schema.ValidateBytes(data); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, data); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// TODO: if generation of names added to server side, change this to use the server's name
|
||||||
|
fmt.Fprintf(out, "%s\n", info.Name)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
fmt.Fprintf(out, "%s\n", name)
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cmd.Flags().StringP("filename", "f", "", "Filename or URL to file to use to create the resource")
|
cmd.Flags().VarP(&flags.Filenames, "filename", "f", "Filename, directory, or URL to file to use to create the resource")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
120
pkg/kubectl/cmd/create_test.go
Normal file
120
pkg/kubectl/cmd/create_test.go
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
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 cmd_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCreateObject(t *testing.T) {
|
||||||
|
pods, _ := testData()
|
||||||
|
|
||||||
|
f, tf, codec := NewAPIFactory()
|
||||||
|
tf.Printer = &testPrinter{}
|
||||||
|
tf.Client = &client.FakeRESTClient{
|
||||||
|
Codec: codec,
|
||||||
|
Client: client.HTTPClientFunc(func(req *http.Request) (*http.Response, error) {
|
||||||
|
switch p, m := req.URL.Path, req.Method; {
|
||||||
|
case p == "/ns/test/pods" && m == "POST":
|
||||||
|
return &http.Response{StatusCode: 201, Body: objBody(codec, &pods.Items[0])}, nil
|
||||||
|
default:
|
||||||
|
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
buf := bytes.NewBuffer([]byte{})
|
||||||
|
|
||||||
|
cmd := f.NewCmdCreate(buf)
|
||||||
|
cmd.Flags().String("namespace", "test", "")
|
||||||
|
cmd.Flags().Set("filename", "../../../examples/guestbook/redis-master.json")
|
||||||
|
cmd.Run(cmd, []string{})
|
||||||
|
|
||||||
|
// uses the name from the file, not the response
|
||||||
|
if buf.String() != "redis-master\n" {
|
||||||
|
t.Errorf("unexpected output: %s", buf.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateMultipleObject(t *testing.T) {
|
||||||
|
pods, svc := testData()
|
||||||
|
|
||||||
|
f, tf, codec := NewAPIFactory()
|
||||||
|
tf.Printer = &testPrinter{}
|
||||||
|
tf.Client = &client.FakeRESTClient{
|
||||||
|
Codec: codec,
|
||||||
|
Client: client.HTTPClientFunc(func(req *http.Request) (*http.Response, error) {
|
||||||
|
switch p, m := req.URL.Path, req.Method; {
|
||||||
|
case p == "/ns/test/pods" && m == "POST":
|
||||||
|
return &http.Response{StatusCode: 201, Body: objBody(codec, &pods.Items[0])}, nil
|
||||||
|
case p == "/ns/test/services" && m == "POST":
|
||||||
|
return &http.Response{StatusCode: 201, Body: objBody(codec, &svc.Items[0])}, nil
|
||||||
|
default:
|
||||||
|
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
buf := bytes.NewBuffer([]byte{})
|
||||||
|
|
||||||
|
cmd := f.NewCmdCreate(buf)
|
||||||
|
cmd.Flags().String("namespace", "test", "")
|
||||||
|
cmd.Flags().Set("filename", "../../../examples/guestbook/redis-master.json")
|
||||||
|
cmd.Flags().Set("filename", "../../../examples/guestbook/frontend-service.json")
|
||||||
|
cmd.Run(cmd, []string{})
|
||||||
|
|
||||||
|
if buf.String() != "redis-master\nfrontend\n" {
|
||||||
|
t.Errorf("unexpected output: %s", buf.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateDirectory(t *testing.T) {
|
||||||
|
pods, svc := testData()
|
||||||
|
|
||||||
|
f, tf, codec := NewAPIFactory()
|
||||||
|
tf.Printer = &testPrinter{}
|
||||||
|
tf.Client = &client.FakeRESTClient{
|
||||||
|
Codec: codec,
|
||||||
|
Client: client.HTTPClientFunc(func(req *http.Request) (*http.Response, error) {
|
||||||
|
switch p, m := req.URL.Path, req.Method; {
|
||||||
|
case p == "/ns/test/pods" && m == "POST":
|
||||||
|
return &http.Response{StatusCode: 201, Body: objBody(codec, &pods.Items[0])}, nil
|
||||||
|
case p == "/ns/test/services" && m == "POST":
|
||||||
|
return &http.Response{StatusCode: 201, Body: objBody(codec, &svc.Items[0])}, nil
|
||||||
|
case p == "/ns/test/replicationcontrollers" && m == "POST":
|
||||||
|
return &http.Response{StatusCode: 201, Body: objBody(codec, &svc.Items[0])}, nil
|
||||||
|
default:
|
||||||
|
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
buf := bytes.NewBuffer([]byte{})
|
||||||
|
|
||||||
|
cmd := f.NewCmdCreate(buf)
|
||||||
|
cmd.Flags().String("namespace", "test", "")
|
||||||
|
cmd.Flags().Set("filename", "../../../examples/guestbook")
|
||||||
|
cmd.Run(cmd, []string{})
|
||||||
|
|
||||||
|
if buf.String() != "frontendController\nfrontend\nredis-master\nredis-master\nredisSlaveController\nredisslave\n" {
|
||||||
|
t.Errorf("unexpected output: %s", buf.String())
|
||||||
|
}
|
||||||
|
}
|
@ -1,120 +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 cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/config"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
|
||||||
"github.com/ghodss/yaml"
|
|
||||||
"github.com/golang/glog"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DataToObjects converts the raw JSON data into API objects
|
|
||||||
func DataToObjects(m meta.RESTMapper, t runtime.ObjectTyper, data []byte) (result []runtime.Object, errors []error) {
|
|
||||||
configObj := []runtime.RawExtension{}
|
|
||||||
|
|
||||||
if err := yaml.Unmarshal(data, &configObj); err != nil {
|
|
||||||
errors = append(errors, fmt.Errorf("config unmarshal: %v", err))
|
|
||||||
return result, errors
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, in := range configObj {
|
|
||||||
version, kind, err := t.DataVersionAndKind(in.RawJSON)
|
|
||||||
if err != nil {
|
|
||||||
errors = append(errors, fmt.Errorf("item[%d] kind: %v", i, err))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
mapping, err := m.RESTMapping(kind, version)
|
|
||||||
if err != nil {
|
|
||||||
errors = append(errors, fmt.Errorf("item[%d] mapping: %v", i, err))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
obj, err := mapping.Codec.Decode(in.RawJSON)
|
|
||||||
if err != nil {
|
|
||||||
errors = append(errors, fmt.Errorf("item[%d] decode: %v", i, err))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
result = append(result, obj)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Factory) NewCmdCreateAll(out io.Writer) *cobra.Command {
|
|
||||||
cmd := &cobra.Command{
|
|
||||||
Use: "createall [-d directory] [-f filename]",
|
|
||||||
Short: "Create all resources specified in a directory, filename or stdin",
|
|
||||||
Long: `Create all resources contained in JSON file specified in a directory, filename or stdin
|
|
||||||
|
|
||||||
JSON and YAML formats are accepted.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
$ kubectl createall -d configs/
|
|
||||||
<creates all resources listed in JSON or YAML files, found recursively under the configs directory>
|
|
||||||
|
|
||||||
$ kubectl createall -f config.json
|
|
||||||
<creates all resources listed in config.json>
|
|
||||||
|
|
||||||
$ cat config.json | kubectl apply -f -
|
|
||||||
<creates all resources listed in config.json>`,
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
|
||||||
clientFunc := func(mapper *meta.RESTMapping) (config.RESTClientPoster, error) {
|
|
||||||
client, err := f.RESTClient(cmd, mapper)
|
|
||||||
checkErr(err)
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
filename := GetFlagString(cmd, "filename")
|
|
||||||
directory := GetFlagString(cmd, "directory")
|
|
||||||
if (len(filename) == 0 && len(directory) == 0) || (len(filename) != 0 && len(directory) != 0) {
|
|
||||||
usageError(cmd, "Must pass a directory or filename to update")
|
|
||||||
}
|
|
||||||
|
|
||||||
files := []string{}
|
|
||||||
if len(filename) != 0 {
|
|
||||||
files = append(files, filename)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
files = append(GetFilesFromDir(directory, ".json"), GetFilesFromDir(directory, ".yaml")...)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, filename := range files {
|
|
||||||
data, err := ReadConfigData(filename)
|
|
||||||
checkErr(err)
|
|
||||||
|
|
||||||
items, errs := DataToObjects(f.Mapper, f.Typer, data)
|
|
||||||
applyErrs := config.CreateObjects(f.Typer, f.Mapper, clientFunc, items)
|
|
||||||
|
|
||||||
errs = append(errs, applyErrs...)
|
|
||||||
if len(errs) > 0 {
|
|
||||||
for _, e := range errs {
|
|
||||||
glog.Error(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
cmd.Flags().StringP("directory", "d", "", "Directory of JSON or YAML files to use to update the resource")
|
|
||||||
cmd.Flags().StringP("filename", "f", "", "Filename or URL to file to use to update the resource")
|
|
||||||
return cmd
|
|
||||||
}
|
|
@ -59,7 +59,8 @@ 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.RESTClient, schema, true).Visit(func(r *resource.Info) error {
|
mapper, typer := f.Object(cmd)
|
||||||
|
ResourcesFromArgsOrFile(cmd, args, filename, selector, typer, mapper, f.RESTClient, schema, true).Visit(func(r *resource.Info) error {
|
||||||
found++
|
found++
|
||||||
if err := resource.NewHelper(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
|
||||||
|
@ -32,7 +32,8 @@ func (f *Factory) NewCmdDescribe(out io.Writer) *cobra.Command {
|
|||||||
This command joins many API calls together to form a detailed description of a
|
This command joins many API calls together to form a detailed description of a
|
||||||
given resource.`,
|
given resource.`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
mapping, namespace, name := ResourceFromArgs(cmd, args, f.Mapper)
|
mapper, _ := f.Object(cmd)
|
||||||
|
mapping, namespace, name := ResourceFromArgs(cmd, args, mapper)
|
||||||
|
|
||||||
describer, err := f.Describer(cmd, mapping)
|
describer, err := f.Describer(cmd, mapping)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
@ -74,11 +74,12 @@ Examples:
|
|||||||
// TODO: return an error instead of using glog.Fatal and checkErr
|
// TODO: return an error instead of using glog.Fatal and checkErr
|
||||||
func RunGet(f *Factory, out io.Writer, cmd *cobra.Command, args []string) {
|
func RunGet(f *Factory, out io.Writer, cmd *cobra.Command, args []string) {
|
||||||
selector := GetFlagString(cmd, "selector")
|
selector := GetFlagString(cmd, "selector")
|
||||||
|
mapper, typer := f.Object(cmd)
|
||||||
|
|
||||||
// handle watch separately since we cannot watch multiple resource types
|
// handle watch separately since we cannot watch multiple resource types
|
||||||
isWatch, isWatchOnly := GetFlagBool(cmd, "watch"), GetFlagBool(cmd, "watch-only")
|
isWatch, isWatchOnly := GetFlagBool(cmd, "watch"), GetFlagBool(cmd, "watch-only")
|
||||||
if isWatch || isWatchOnly {
|
if isWatch || isWatchOnly {
|
||||||
r := resource.NewBuilder(f.Mapper, f.Typer, ClientMapperForCommand(cmd, f)).
|
r := resource.NewBuilder(mapper, typer, ClientMapperForCommand(cmd, f)).
|
||||||
NamespaceParam(GetKubeNamespace(cmd)).DefaultNamespace().
|
NamespaceParam(GetKubeNamespace(cmd)).DefaultNamespace().
|
||||||
SelectorParam(selector).
|
SelectorParam(selector).
|
||||||
ResourceTypeOrNameArgs(args...).
|
ResourceTypeOrNameArgs(args...).
|
||||||
@ -117,7 +118,7 @@ func RunGet(f *Factory, out io.Writer, cmd *cobra.Command, args []string) {
|
|||||||
printer, generic, err := printerForCommand(cmd)
|
printer, generic, err := printerForCommand(cmd)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|
||||||
b := resource.NewBuilder(f.Mapper, f.Typer, ClientMapperForCommand(cmd, f)).
|
b := resource.NewBuilder(mapper, typer, ClientMapperForCommand(cmd, f)).
|
||||||
NamespaceParam(GetKubeNamespace(cmd)).DefaultNamespace().
|
NamespaceParam(GetKubeNamespace(cmd)).DefaultNamespace().
|
||||||
SelectorParam(selector).
|
SelectorParam(selector).
|
||||||
ResourceTypeOrNameArgs(args...).
|
ResourceTypeOrNameArgs(args...).
|
||||||
|
@ -90,8 +90,8 @@ func TestGetUnknownSchemaObject(t *testing.T) {
|
|||||||
// Verifies that schemas that are not in the master tree of Kubernetes can be retrieved via Get.
|
// Verifies that schemas that are not in the master tree of Kubernetes can be retrieved via Get.
|
||||||
func TestGetSchemaObject(t *testing.T) {
|
func TestGetSchemaObject(t *testing.T) {
|
||||||
f, tf, _ := NewTestFactory()
|
f, tf, _ := NewTestFactory()
|
||||||
f.Mapper = latest.RESTMapper
|
tf.Mapper = latest.RESTMapper
|
||||||
f.Typer = api.Scheme
|
tf.Typer = api.Scheme
|
||||||
codec := latest.Codec
|
codec := latest.Codec
|
||||||
tf.Printer = &testPrinter{}
|
tf.Printer = &testPrinter{}
|
||||||
tf.Client = &client.FakeRESTClient{
|
tf.Client = &client.FakeRESTClient{
|
||||||
|
@ -24,7 +24,6 @@ import (
|
|||||||
|
|
||||||
"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/resource"
|
"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"
|
||||||
@ -39,7 +38,7 @@ func ResourcesFromArgsOrFile(
|
|||||||
filename, selector string,
|
filename, selector string,
|
||||||
typer runtime.ObjectTyper,
|
typer runtime.ObjectTyper,
|
||||||
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) (resource.RESTClient, error),
|
||||||
schema validation.Schema,
|
schema validation.Schema,
|
||||||
requireNames bool,
|
requireNames bool,
|
||||||
) resource.Visitor {
|
) resource.Visitor {
|
||||||
|
@ -61,7 +61,8 @@ $ cat frontend-v2.json | kubectl rollingupdate frontend-v1 -f -
|
|||||||
oldName := args[0]
|
oldName := args[0]
|
||||||
schema, err := f.Validator(cmd)
|
schema, err := f.Validator(cmd)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
mapping, namespace, newName, data := ResourceFromFile(cmd, filename, f.Typer, f.Mapper, schema)
|
mapper, typer := f.Object(cmd)
|
||||||
|
mapping, namespace, newName, data := ResourceFromFile(cmd, filename, typer, mapper, schema)
|
||||||
if mapping.Kind != "ReplicationController" {
|
if mapping.Kind != "ReplicationController" {
|
||||||
usageError(cmd, "%s does not specify a valid ReplicationController", filename)
|
usageError(cmd, "%s does not specify a valid ReplicationController", filename)
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,8 @@ Examples:
|
|||||||
}
|
}
|
||||||
schema, err := f.Validator(cmd)
|
schema, err := f.Validator(cmd)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
mapping, namespace, name, data := ResourceFromFile(cmd, filename, f.Typer, f.Mapper, schema)
|
mapper, typer := f.Object(cmd)
|
||||||
|
mapping, namespace, name, data := ResourceFromFile(cmd, filename, typer, mapper, schema)
|
||||||
client, err := f.RESTClient(cmd, mapping)
|
client, err := f.RESTClient(cmd, mapping)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|
||||||
|
@ -112,6 +112,19 @@ func makeImageList(spec *api.PodSpec) string {
|
|||||||
return strings.Join(listOfImages(spec), ",")
|
return strings.Join(listOfImages(spec), ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OutputVersionMapper is a RESTMapper that will prefer mappings that
|
||||||
|
// correspond to a preferred output version (if feasible)
|
||||||
|
type OutputVersionMapper struct {
|
||||||
|
meta.RESTMapper
|
||||||
|
OutputVersion string
|
||||||
|
}
|
||||||
|
|
||||||
|
// RESTMapping implements meta.RESTMapper by prepending the output version to the preferred version list.
|
||||||
|
func (m OutputVersionMapper) RESTMapping(kind string, versions ...string) (*meta.RESTMapping, error) {
|
||||||
|
preferred := append([]string{m.OutputVersion}, versions...)
|
||||||
|
return m.RESTMapper.RESTMapping(kind, preferred...)
|
||||||
|
}
|
||||||
|
|
||||||
// ShortcutExpander is a RESTMapper that can be used for Kubernetes
|
// ShortcutExpander is a RESTMapper that can be used for Kubernetes
|
||||||
// resources.
|
// resources.
|
||||||
type ShortcutExpander struct {
|
type ShortcutExpander struct {
|
||||||
|
@ -262,6 +262,8 @@ func (b *Builder) ContinueOnError() *Builder {
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SingleResourceType will cause the builder to error if the user specifies more than a single type
|
||||||
|
// of resource.
|
||||||
func (b *Builder) SingleResourceType() *Builder {
|
func (b *Builder) SingleResourceType() *Builder {
|
||||||
b.singleResourceType = true
|
b.singleResourceType = true
|
||||||
return b
|
return b
|
||||||
|
Loading…
Reference in New Issue
Block a user