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
a510285d
Unverified
Commit
a510285d
authored
Aug 22, 2018
by
juanvallejo
Committed by
Maciej Szulik
Aug 28, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add support for --cluster --context --user flags
parent
985406c9
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
165 additions
and
51 deletions
+165
-51
kubectl-ns.go
staging/src/k8s.io/sample-cli-plugin/cmd/kubectl-ns.go
+16
-0
ns.go
staging/src/k8s.io/sample-cli-plugin/pkg/cmd/ns.go
+149
-51
No files found.
staging/src/k8s.io/sample-cli-plugin/cmd/kubectl-ns.go
View file @
a510285d
/*
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
main
package
main
import
(
import
(
...
...
staging/src/k8s.io/sample-cli-plugin/pkg/cmd/ns.go
View file @
a510285d
/*
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
cmd
package
cmd
import
(
import
(
...
@@ -13,21 +29,33 @@ import (
...
@@ -13,21 +29,33 @@ import (
)
)
var
(
var
(
namespace
_e
xample
=
`
namespace
E
xample
=
`
# view the current namespace in your KUBECONFIG
# view the current namespace in your KUBECONFIG
%[1]s ns
%[1]s ns
# view all of the namespaces in use by contexts in your KUBECONFIG
# view all of the namespaces in use by contexts in your KUBECONFIG
%[1] ns --list
%[1]
s
ns --list
# switch your current-context to one that contains the desired namespace
# switch your current-context to one that contains the desired namespace
%[1]s ns foo
%[1]s ns foo
`
`
errNoContext
=
fmt
.
Errorf
(
"no context is currently set, use %q to select a new one"
,
"kubectl config use-context <context>"
)
)
)
// NamespaceOptions provides information required to update
// the current context on a user's KUBECONFIG
type
NamespaceOptions
struct
{
type
NamespaceOptions
struct
{
configFlags
*
genericclioptions
.
ConfigFlags
configFlags
*
genericclioptions
.
ConfigFlags
resultingContext
*
api
.
Context
resultingContextName
string
userSpecifiedCluster
string
userSpecifiedContext
string
userSpecifiedAuthInfo
string
userSpecifiedNamespace
string
rawConfig
api
.
Config
rawConfig
api
.
Config
listNamespaces
bool
listNamespaces
bool
args
[]
string
args
[]
string
...
@@ -35,6 +63,7 @@ type NamespaceOptions struct {
...
@@ -35,6 +63,7 @@ type NamespaceOptions struct {
genericclioptions
.
IOStreams
genericclioptions
.
IOStreams
}
}
// NewNamespaceOptions provides an instance of NamespaceOptions with default values
func
NewNamespaceOptions
(
streams
genericclioptions
.
IOStreams
)
*
NamespaceOptions
{
func
NewNamespaceOptions
(
streams
genericclioptions
.
IOStreams
)
*
NamespaceOptions
{
return
&
NamespaceOptions
{
return
&
NamespaceOptions
{
configFlags
:
genericclioptions
.
NewConfigFlags
(),
configFlags
:
genericclioptions
.
NewConfigFlags
(),
...
@@ -43,16 +72,17 @@ func NewNamespaceOptions(streams genericclioptions.IOStreams) *NamespaceOptions
...
@@ -43,16 +72,17 @@ func NewNamespaceOptions(streams genericclioptions.IOStreams) *NamespaceOptions
}
}
}
}
// NewCmdNamespace provides a cobra command wrapping NamespaceOptions
func
NewCmdNamespace
(
streams
genericclioptions
.
IOStreams
)
*
cobra
.
Command
{
func
NewCmdNamespace
(
streams
genericclioptions
.
IOStreams
)
*
cobra
.
Command
{
o
:=
NewNamespaceOptions
(
streams
)
o
:=
NewNamespaceOptions
(
streams
)
cmd
:=
&
cobra
.
Command
{
cmd
:=
&
cobra
.
Command
{
Use
:
"ns [new-namespace] [flags]"
,
Use
:
"ns [new-namespace] [flags]"
,
Short
:
"View or set the current namespace"
,
Short
:
"View or set the current namespace"
,
Example
:
namespace_example
,
Example
:
fmt
.
Sprintf
(
namespaceExample
,
"kubectl"
)
,
SilenceUsage
:
true
,
SilenceUsage
:
true
,
RunE
:
func
(
c
*
cobra
.
Command
,
args
[]
string
)
error
{
RunE
:
func
(
c
*
cobra
.
Command
,
args
[]
string
)
error
{
if
err
:=
o
.
Complete
(
args
);
err
!=
nil
{
if
err
:=
o
.
Complete
(
c
,
args
);
err
!=
nil
{
return
err
return
err
}
}
if
err
:=
o
.
Validate
();
err
!=
nil
{
if
err
:=
o
.
Validate
();
err
!=
nil
{
...
@@ -72,20 +102,103 @@ func NewCmdNamespace(streams genericclioptions.IOStreams) *cobra.Command {
...
@@ -72,20 +102,103 @@ func NewCmdNamespace(streams genericclioptions.IOStreams) *cobra.Command {
return
cmd
return
cmd
}
}
func
(
o
*
NamespaceOptions
)
Complete
(
args
[]
string
)
error
{
// Complete sets all information required for updating the current context
func
(
o
*
NamespaceOptions
)
Complete
(
cmd
*
cobra
.
Command
,
args
[]
string
)
error
{
o
.
args
=
args
var
err
error
var
err
error
o
.
rawConfig
,
err
=
o
.
configFlags
.
ToRawKubeConfigLoader
()
.
RawConfig
()
o
.
rawConfig
,
err
=
o
.
configFlags
.
ToRawKubeConfigLoader
()
.
RawConfig
()
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
o
.
args
=
args
o
.
userSpecifiedNamespace
,
err
=
cmd
.
Flags
()
.
GetString
(
"namespace"
)
if
err
!=
nil
{
return
err
}
if
len
(
args
)
>
0
{
if
len
(
o
.
userSpecifiedNamespace
)
>
0
{
return
fmt
.
Errorf
(
"cannot specify both a --namespace value and a new namespace argument"
)
}
o
.
userSpecifiedNamespace
=
args
[
0
]
}
// if no namespace argument or flag value was specified, then there
// is no need to generate a resulting context
if
len
(
o
.
userSpecifiedNamespace
)
==
0
{
return
nil
}
o
.
userSpecifiedContext
,
err
=
cmd
.
Flags
()
.
GetString
(
"context"
)
if
err
!=
nil
{
return
err
}
o
.
userSpecifiedCluster
,
err
=
cmd
.
Flags
()
.
GetString
(
"cluster"
)
if
err
!=
nil
{
return
err
}
o
.
userSpecifiedAuthInfo
,
err
=
cmd
.
Flags
()
.
GetString
(
"user"
)
if
err
!=
nil
{
return
err
}
currentContext
,
exists
:=
o
.
rawConfig
.
Contexts
[
o
.
rawConfig
.
CurrentContext
]
if
!
exists
{
return
errNoContext
}
o
.
resultingContext
=
api
.
NewContext
()
o
.
resultingContext
.
Cluster
=
currentContext
.
Cluster
o
.
resultingContext
.
AuthInfo
=
currentContext
.
AuthInfo
// if a target context is explicitly provided by the user,
// use that as our reference for the final, resulting context
if
len
(
o
.
userSpecifiedContext
)
>
0
{
o
.
resultingContextName
=
o
.
userSpecifiedContext
if
userCtx
,
exists
:=
o
.
rawConfig
.
Contexts
[
o
.
userSpecifiedContext
];
exists
{
o
.
resultingContext
=
userCtx
.
DeepCopy
()
}
}
// override context info with user provided values
o
.
resultingContext
.
Namespace
=
o
.
userSpecifiedNamespace
if
len
(
o
.
userSpecifiedCluster
)
>
0
{
o
.
resultingContext
.
Cluster
=
o
.
userSpecifiedCluster
}
if
len
(
o
.
userSpecifiedAuthInfo
)
>
0
{
o
.
resultingContext
.
AuthInfo
=
o
.
userSpecifiedAuthInfo
}
// generate a unique context name based on its new values if
// user did not explicitly request a context by name
if
len
(
o
.
userSpecifiedContext
)
==
0
{
o
.
resultingContextName
=
generateContextName
(
o
.
resultingContext
)
}
return
nil
return
nil
}
}
func
generateContextName
(
fromContext
*
api
.
Context
)
string
{
name
:=
fromContext
.
Namespace
if
len
(
fromContext
.
Cluster
)
>
0
{
name
=
fmt
.
Sprintf
(
"%s/%s"
,
name
,
fromContext
.
Cluster
)
}
if
len
(
fromContext
.
AuthInfo
)
>
0
{
cleanAuthInfo
:=
strings
.
Split
(
fromContext
.
AuthInfo
,
"/"
)[
0
]
name
=
fmt
.
Sprintf
(
"%s/%s"
,
name
,
cleanAuthInfo
)
}
return
name
}
// Validate ensures that all required arguments and flag values are provided
func
(
o
*
NamespaceOptions
)
Validate
()
error
{
func
(
o
*
NamespaceOptions
)
Validate
()
error
{
if
len
(
o
.
rawConfig
.
CurrentContext
)
==
0
{
if
len
(
o
.
rawConfig
.
CurrentContext
)
==
0
{
return
fmt
.
Errorf
(
"no context is currently set in your configuration"
)
return
errNoContext
}
}
if
len
(
o
.
args
)
>
1
{
if
len
(
o
.
args
)
>
1
{
return
fmt
.
Errorf
(
"either one or no arguments are allowed"
)
return
fmt
.
Errorf
(
"either one or no arguments are allowed"
)
...
@@ -94,9 +207,11 @@ func (o *NamespaceOptions) Validate() error {
...
@@ -94,9 +207,11 @@ func (o *NamespaceOptions) Validate() error {
return
nil
return
nil
}
}
// Run lists all available namespaces on a user's KUBECONFIG or updates the
// current context based on a provided namespace.
func
(
o
*
NamespaceOptions
)
Run
()
error
{
func
(
o
*
NamespaceOptions
)
Run
()
error
{
if
len
(
o
.
args
)
>
0
&&
len
(
o
.
args
[
0
])
>
0
{
if
len
(
o
.
userSpecifiedNamespace
)
>
0
&&
o
.
resultingContext
!=
nil
{
return
o
.
setNamespace
(
o
.
args
[
0
]
)
return
o
.
setNamespace
(
o
.
resultingContext
,
o
.
resultingContextName
)
}
}
namespaces
:=
map
[
string
]
bool
{}
namespaces
:=
map
[
string
]
bool
{}
...
@@ -134,58 +249,41 @@ func (o *NamespaceOptions) Run() error {
...
@@ -134,58 +249,41 @@ func (o *NamespaceOptions) Run() error {
return
nil
return
nil
}
}
func
(
o
*
NamespaceOptions
)
setNamespace
(
newNamespace
string
)
error
{
func
isContextEqual
(
ctxA
,
ctxB
*
api
.
Context
)
bool
{
if
len
(
newNamespace
)
==
0
{
if
ctxA
==
nil
||
ctxB
==
nil
{
return
f
mt
.
Errorf
(
"a non-empty namespace must be provided"
)
return
f
alse
}
}
if
ctxA
.
Cluster
!=
ctxB
.
Cluster
{
existingCtx
,
ok
:=
o
.
rawConfig
.
Contexts
[
o
.
rawConfig
.
CurrentContext
]
return
false
if
!
ok
{
return
fmt
.
Errorf
(
"unable to gather information about the current context"
)
}
}
if
ctxA
.
Namespace
!=
ctxB
.
Namespace
{
if
existingCtx
.
Namespace
==
newNamespace
{
return
false
fmt
.
Fprintf
(
o
.
Out
,
"already using namespace %q
\n
"
,
newNamespace
)
return
nil
}
}
if
ctxA
.
AuthInfo
!=
ctxB
.
AuthInfo
{
// determine if a context exists for the new namespace
return
false
existingCtxName
:=
""
for
name
,
c
:=
range
o
.
rawConfig
.
Contexts
{
if
c
.
Namespace
!=
newNamespace
||
c
.
Cluster
!=
existingCtx
.
Cluster
||
c
.
AuthInfo
!=
existingCtx
.
AuthInfo
{
continue
}
existingCtxName
=
name
break
}
}
if
len
(
existingCtxName
)
==
0
{
return
true
newCtx
:=
api
.
NewContext
()
}
newCtx
.
AuthInfo
=
existingCtx
.
AuthInfo
newCtx
.
Cluster
=
existingCtx
.
Cluster
newCtx
.
Namespace
=
newNamespace
newCtxName
:=
newNamespace
if
len
(
existingCtx
.
Cluster
)
>
0
{
newCtxName
=
fmt
.
Sprintf
(
"%s/%s"
,
newCtxName
,
existingCtx
.
Cluster
)
}
if
len
(
existingCtx
.
AuthInfo
)
>
0
{
cleanAuthInfo
:=
strings
.
Split
(
existingCtx
.
AuthInfo
,
"/"
)[
0
]
newCtxName
=
fmt
.
Sprintf
(
"%s/%s"
,
newCtxName
,
cleanAuthInfo
)
}
o
.
rawConfig
.
Contexts
[
newCtxName
]
=
newCtx
// setNamespace receives a "desired" context state and determines if a similar context
existingCtxName
=
newCtxName
// is already present in a user's KUBECONFIG. If one is not, then a new context is added
// to the user's config under the provided destination name.
// The current context field is updated to point to the new context.
func
(
o
*
NamespaceOptions
)
setNamespace
(
fromContext
*
api
.
Context
,
withContextName
string
)
error
{
if
len
(
fromContext
.
Namespace
)
==
0
{
return
fmt
.
Errorf
(
"a non-empty namespace must be provided"
)
}
}
configAccess
:=
clientcmd
.
NewDefaultPathOptions
()
configAccess
:=
clientcmd
.
NewDefaultPathOptions
()
o
.
rawConfig
.
CurrentContext
=
existingCtxName
if
err
:=
clientcmd
.
ModifyConfig
(
configAccess
,
o
.
rawConfig
,
true
);
err
!=
nil
{
// determine if we have already saved this context to the user's KUBECONFIG before
return
err
// if so, simply switch the current context to the existing one.
if
existingResultingCtx
,
exists
:=
o
.
rawConfig
.
Contexts
[
withContextName
];
!
exists
||
!
isContextEqual
(
fromContext
,
existingResultingCtx
)
{
o
.
rawConfig
.
Contexts
[
withContextName
]
=
fromContext
}
}
o
.
rawConfig
.
CurrentContext
=
withContextName
fmt
.
Fprintf
(
o
.
Out
,
"namespace changed to %q
\n
"
,
new
Namespace
)
fmt
.
Fprintf
(
o
.
Out
,
"namespace changed to %q
\n
"
,
fromContext
.
Namespace
)
return
nil
return
clientcmd
.
ModifyConfig
(
configAccess
,
o
.
rawConfig
,
true
)
}
}
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