Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
37f35d93
Commit
37f35d93
authored
Nov 04, 2015
by
Janet Kuo
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Make kubectl apply create resources if not found
parent
c095e35f
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
81 additions
and
5 deletions
+81
-5
kubectl-apply.1
docs/man/man1/kubectl-apply.1
+1
-0
kubectl_apply.md
docs/user-guide/kubectl/kubectl_apply.md
+2
-1
test-cmd.sh
hack/test-cmd.sh
+12
-0
apply.go
pkg/kubectl/cmd/apply.go
+17
-1
apply_test.go
pkg/kubectl/cmd/apply_test.go
+38
-0
create.go
pkg/kubectl/cmd/create.go
+11
-3
No files found.
docs/man/man1/kubectl-apply.1
View file @
37f35d93
...
@@ -14,6 +14,7 @@ kubectl apply \- Apply a configuration to a resource by filename or stdin
...
@@ -14,6 +14,7 @@ kubectl apply \- Apply a configuration to a resource by filename or stdin
.SH DESCRIPTION
.SH DESCRIPTION
.PP
.PP
Apply a configuration to a resource by filename or stdin.
Apply a configuration to a resource by filename or stdin.
The resource will be created if it doesn't exist yet.
.PP
.PP
JSON and YAML formats are accepted.
JSON and YAML formats are accepted.
...
...
docs/user-guide/kubectl/kubectl_apply.md
View file @
37f35d93
...
@@ -39,6 +39,7 @@ Apply a configuration to a resource by filename or stdin
...
@@ -39,6 +39,7 @@ Apply a configuration to a resource by filename or stdin
Apply a configuration to a resource by filename or stdin.
Apply a configuration to a resource by filename or stdin.
The resource will be created if it doesn't exist yet.
JSON and YAML formats are accepted.
JSON and YAML formats are accepted.
...
@@ -97,7 +98,7 @@ $ cat pod.json | kubectl apply -f -
...
@@ -97,7 +98,7 @@ $ cat pod.json | kubectl apply -f -
*
[
kubectl
](
kubectl.md
)
- kubectl controls the Kubernetes cluster manager
*
[
kubectl
](
kubectl.md
)
- kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra
at 2015-10-01 05:36:57.66914652 +0000 UTC
###### Auto generated by spf13/cobra
on 4-Nov-2015
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
[

]()
[

]()
...
...
hack/test-cmd.sh
View file @
37f35d93
...
@@ -635,6 +635,18 @@ runTests() {
...
@@ -635,6 +635,18 @@ runTests() {
# Clean up
# Clean up
kubectl delete rc,hpa frontend
kubectl delete rc,hpa frontend
## kubectl apply should create the resource that doesn't exist yet
# Pre-Condition: no POD is running
kube::test::get_object_assert pods
"{{range.items}}{{
$id_field
}}:{{end}}"
''
# Command: apply a pod "test-pod" (doesn't exist) should create this pod
kubectl apply
-f
hack/testdata/pod.yaml
"
${
kube_flags
[@]
}
"
# Post-Condition: pod "test-pod" is running
kube::test::get_object_assert
'pods test-pod'
"{{
${
labels_field
}
.name}}"
'test-pod-label'
# Post-Condition: pod "test-pod" has configuration annotation
[[
"
$(
kubectl get pods test-pod
-o
yaml
"
${
kube_flags
[@]
}
"
|
grep
kubectl.kubernetes.io/last-applied-configuration
)
"
]]
# Clean up
kubectl delete pods test-pod
"
${
kube_flags
[@]
}
"
##############
##############
# Namespaces #
# Namespaces #
##############
##############
...
...
pkg/kubectl/cmd/apply.go
View file @
37f35d93
...
@@ -23,6 +23,7 @@ import (
...
@@ -23,6 +23,7 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl"
cmdutil
"k8s.io/kubernetes/pkg/kubectl/cmd/util"
cmdutil
"k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/kubectl/resource"
...
@@ -37,6 +38,7 @@ type ApplyOptions struct {
...
@@ -37,6 +38,7 @@ type ApplyOptions struct {
const
(
const
(
apply_long
=
`Apply a configuration to a resource by filename or stdin.
apply_long
=
`Apply a configuration to a resource by filename or stdin.
The resource will be created if it doesn't exist yet.
JSON and YAML formats are accepted.`
JSON and YAML formats are accepted.`
apply_example
=
`# Apply the configuration in pod.json to a pod.
apply_example
=
`# Apply the configuration in pod.json to a pod.
...
@@ -119,7 +121,21 @@ func RunApply(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *Ap
...
@@ -119,7 +121,21 @@ func RunApply(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *Ap
}
}
if
err
:=
info
.
Get
();
err
!=
nil
{
if
err
:=
info
.
Get
();
err
!=
nil
{
return
cmdutil
.
AddSourceToErr
(
fmt
.
Sprintf
(
"retrieving current configuration of:
\n
%v
\n
from server for:"
,
info
),
info
.
Source
,
err
)
if
!
errors
.
IsNotFound
(
err
)
{
return
cmdutil
.
AddSourceToErr
(
fmt
.
Sprintf
(
"retrieving current configuration of:
\n
%v
\n
from server for:"
,
info
),
info
.
Source
,
err
)
}
// Create the resource if it doesn't exist
// First, update the annotation used by kubectl apply
if
err
:=
kubectl
.
CreateApplyAnnotation
(
info
);
err
!=
nil
{
return
cmdutil
.
AddSourceToErr
(
"creating"
,
info
.
Source
,
err
)
}
// Then create the resource and skip the three-way merge
if
err
:=
createAndRefresh
(
info
);
err
!=
nil
{
return
cmdutil
.
AddSourceToErr
(
"creating"
,
info
.
Source
,
err
)
}
count
++
cmdutil
.
PrintSuccess
(
mapper
,
shortOutput
,
out
,
info
.
Mapping
.
Resource
,
info
.
Name
,
"created"
)
return
nil
}
}
// Serialize the current configuration of the object from the server.
// Serialize the current configuration of the object from the server.
...
...
pkg/kubectl/cmd/apply_test.go
View file @
37f35d93
...
@@ -28,6 +28,7 @@ import (
...
@@ -28,6 +28,7 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/client/unversioned/fake"
"k8s.io/kubernetes/pkg/client/unversioned/fake"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl"
cmdutil
"k8s.io/kubernetes/pkg/kubectl/cmd/util"
cmdutil
"k8s.io/kubernetes/pkg/kubectl/cmd/util"
...
@@ -207,6 +208,43 @@ func TestApplyObject(t *testing.T) {
...
@@ -207,6 +208,43 @@ func TestApplyObject(t *testing.T) {
}
}
}
}
func
TestApplyNonExistObject
(
t
*
testing
.
T
)
{
nameRC
,
currentRC
:=
readAndAnnotateReplicationController
(
t
,
filenameRC
)
pathRC
:=
"/namespaces/test/replicationcontrollers"
pathNameRC
:=
pathRC
+
"/"
+
nameRC
f
,
tf
,
codec
:=
NewAPIFactory
()
tf
.
Printer
=
&
testPrinter
{}
tf
.
Client
=
&
fake
.
RESTClient
{
Codec
:
codec
,
Client
:
fake
.
HTTPClientFunc
(
func
(
req
*
http
.
Request
)
(
*
http
.
Response
,
error
)
{
switch
p
,
m
:=
req
.
URL
.
Path
,
req
.
Method
;
{
case
p
==
pathNameRC
&&
m
==
"GET"
:
return
&
http
.
Response
{
StatusCode
:
404
},
errors
.
NewNotFound
(
"ReplicationController"
,
""
)
case
p
==
pathRC
&&
m
==
"POST"
:
bodyRC
:=
ioutil
.
NopCloser
(
bytes
.
NewReader
(
currentRC
))
return
&
http
.
Response
{
StatusCode
:
201
,
Body
:
bodyRC
},
nil
default
:
t
.
Fatalf
(
"unexpected request: %#v
\n
%#v"
,
req
.
URL
,
req
)
return
nil
,
nil
}
}),
}
tf
.
Namespace
=
"test"
buf
:=
bytes
.
NewBuffer
([]
byte
{})
cmd
:=
NewCmdApply
(
f
,
buf
)
cmd
.
Flags
()
.
Set
(
"filename"
,
filenameRC
)
cmd
.
Flags
()
.
Set
(
"output"
,
"name"
)
cmd
.
Run
(
cmd
,
[]
string
{})
// uses the name from the file, not the response
expectRC
:=
"replicationcontroller/"
+
nameRC
+
"
\n
"
if
buf
.
String
()
!=
expectRC
{
t
.
Errorf
(
"unexpected output: %s
\n
expected: %s"
,
buf
.
String
(),
expectRC
)
}
}
func
TestApplyMultipleObject
(
t
*
testing
.
T
)
{
func
TestApplyMultipleObject
(
t
*
testing
.
T
)
{
nameRC
,
currentRC
:=
readAndAnnotateReplicationController
(
t
,
filenameRC
)
nameRC
,
currentRC
:=
readAndAnnotateReplicationController
(
t
,
filenameRC
)
pathRC
:=
"/namespaces/test/replicationcontrollers/"
+
nameRC
pathRC
:=
"/namespaces/test/replicationcontrollers/"
+
nameRC
...
...
pkg/kubectl/cmd/create.go
View file @
37f35d93
...
@@ -111,13 +111,11 @@ func RunCreate(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *C
...
@@ -111,13 +111,11 @@ func RunCreate(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *C
return
cmdutil
.
AddSourceToErr
(
"creating"
,
info
.
Source
,
err
)
return
cmdutil
.
AddSourceToErr
(
"creating"
,
info
.
Source
,
err
)
}
}
obj
,
err
:=
resource
.
NewHelper
(
info
.
Client
,
info
.
Mapping
)
.
Create
(
info
.
Namespace
,
true
,
info
.
Object
)
if
err
:=
createAndRefresh
(
info
);
err
!=
nil
{
if
err
!=
nil
{
return
cmdutil
.
AddSourceToErr
(
"creating"
,
info
.
Source
,
err
)
return
cmdutil
.
AddSourceToErr
(
"creating"
,
info
.
Source
,
err
)
}
}
count
++
count
++
info
.
Refresh
(
obj
,
true
)
shortOutput
:=
cmdutil
.
GetFlagString
(
cmd
,
"output"
)
==
"name"
shortOutput
:=
cmdutil
.
GetFlagString
(
cmd
,
"output"
)
==
"name"
if
!
shortOutput
{
if
!
shortOutput
{
printObjectSpecificMessage
(
info
.
Object
,
out
)
printObjectSpecificMessage
(
info
.
Object
,
out
)
...
@@ -164,3 +162,13 @@ func makePortsString(ports []api.ServicePort, useNodePort bool) string {
...
@@ -164,3 +162,13 @@ func makePortsString(ports []api.ServicePort, useNodePort bool) string {
}
}
return
strings
.
Join
(
pieces
,
","
)
return
strings
.
Join
(
pieces
,
","
)
}
}
// createAndRefresh creates an object from input info and refreshes info with that object
func
createAndRefresh
(
info
*
resource
.
Info
)
error
{
obj
,
err
:=
resource
.
NewHelper
(
info
.
Client
,
info
.
Mapping
)
.
Create
(
info
.
Namespace
,
true
,
info
.
Object
)
if
err
!=
nil
{
return
err
}
info
.
Refresh
(
obj
,
true
)
return
nil
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment