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
61673c4b
Commit
61673c4b
authored
Nov 02, 2016
by
deads2k
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
make kubectl get generic with respect to objects
parent
7fe9bd4c
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
309 additions
and
203 deletions
+309
-203
help.go
pkg/api/meta/help.go
+16
-0
help_test.go
pkg/api/meta/help_test.go
+21
-0
BUILD
pkg/kubectl/cmd/BUILD
+0
-2
delete_test.go
pkg/kubectl/cmd/delete_test.go
+2
-6
get.go
pkg/kubectl/cmd/get.go
+43
-40
get_test.go
pkg/kubectl/cmd/get_test.go
+0
-0
fake.go
pkg/kubectl/cmd/testing/fake.go
+9
-2
BUILD
pkg/kubectl/cmd/util/BUILD
+0
-2
factory.go
pkg/kubectl/cmd/util/factory.go
+1
-67
helpers.go
pkg/kubectl/cmd/util/helpers.go
+0
-44
custom_column_printer.go
pkg/kubectl/custom_column_printer.go
+10
-1
kubectl.go
pkg/kubectl/kubectl.go
+0
-22
resource_printer.go
pkg/kubectl/resource_printer.go
+118
-7
sorting_printer.go
pkg/kubectl/sorting_printer.go
+82
-3
kubectl.go
test/e2e/kubectl.go
+6
-6
test_owners.csv
test/test_owners.csv
+1
-1
No files found.
pkg/api/meta/help.go
View file @
61673c4b
...
...
@@ -26,6 +26,14 @@ import (
// IsListType returns true if the provided Object has a slice called Items
func
IsListType
(
obj
runtime
.
Object
)
bool
{
// if we're a runtime.Unstructured, check to see if we have an `items` key
// This is a list type for recognition, but other Items type methods will fail on it
// and give you errors.
if
unstructured
,
ok
:=
obj
.
(
*
runtime
.
Unstructured
);
ok
{
_
,
ok
:=
unstructured
.
Object
[
"items"
]
return
ok
}
_
,
err
:=
GetItemsPtr
(
obj
)
return
err
==
nil
}
...
...
@@ -39,6 +47,7 @@ func GetItemsPtr(list runtime.Object) (interface{}, error) {
if
err
!=
nil
{
return
nil
,
err
}
items
:=
v
.
FieldByName
(
"Items"
)
if
!
items
.
IsValid
()
{
return
nil
,
fmt
.
Errorf
(
"no Items field in %#v"
,
list
)
...
...
@@ -117,6 +126,13 @@ func SetList(list runtime.Object, objects []runtime.Object) error {
slice
:=
reflect
.
MakeSlice
(
items
.
Type
(),
len
(
objects
),
len
(
objects
))
for
i
:=
range
objects
{
dest
:=
slice
.
Index
(
i
)
// check to see if you're directly assignable
if
reflect
.
TypeOf
(
objects
[
i
])
.
AssignableTo
(
dest
.
Type
())
{
dest
.
Set
(
reflect
.
ValueOf
(
objects
[
i
]))
continue
}
src
,
err
:=
conversion
.
EnforcePtr
(
objects
[
i
])
if
err
!=
nil
{
return
err
...
...
pkg/api/meta/help_test.go
View file @
61673c4b
...
...
@@ -229,6 +229,27 @@ func TestSetListToRuntimeObjectArray(t *testing.T) {
}
}
func
TestSetListToMatchingType
(
t
*
testing
.
T
)
{
pl
:=
&
runtime
.
UnstructuredList
{}
list
:=
[]
runtime
.
Object
{
&
runtime
.
Unstructured
{
Object
:
map
[
string
]
interface
{}{
"foo"
:
1
}},
&
runtime
.
Unstructured
{
Object
:
map
[
string
]
interface
{}{
"foo"
:
2
}},
&
runtime
.
Unstructured
{
Object
:
map
[
string
]
interface
{}{
"foo"
:
3
}},
}
err
:=
meta
.
SetList
(
pl
,
list
)
if
err
!=
nil
{
t
.
Fatalf
(
"Unexpected error %v"
,
err
)
}
if
e
,
a
:=
len
(
list
),
len
(
pl
.
Items
);
e
!=
a
{
t
.
Fatalf
(
"Expected %v, got %v"
,
e
,
a
)
}
for
i
:=
range
list
{
if
e
,
a
:=
list
[
i
],
pl
.
Items
[
i
];
e
!=
a
{
t
.
Fatalf
(
"%d: unmatched: %s"
,
i
,
diff
.
ObjectDiff
(
e
,
a
))
}
}
}
func
TestSetExtractListRoundTrip
(
t
*
testing
.
T
)
{
fuzzer
:=
fuzz
.
New
()
.
NilChance
(
0
)
.
NumElements
(
1
,
5
)
for
i
:=
0
;
i
<
5
;
i
++
{
...
...
pkg/kubectl/cmd/BUILD
View file @
61673c4b
...
...
@@ -182,11 +182,9 @@ go_test(
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/resource:go_default_library",
"//pkg/runtime:go_default_library",
"//pkg/runtime/serializer:go_default_library",
"//pkg/runtime/serializer/json:go_default_library",
"//pkg/runtime/serializer/streaming:go_default_library",
"//pkg/types:go_default_library",
"//pkg/util/diff:go_default_library",
"//pkg/util/intstr:go_default_library",
"//pkg/util/strings:go_default_library",
"//pkg/util/term:go_default_library",
...
...
pkg/kubectl/cmd/delete_test.go
View file @
61673c4b
...
...
@@ -28,16 +28,12 @@ import (
"k8s.io/kubernetes/pkg/apimachinery/registered"
"k8s.io/kubernetes/pkg/client/restclient"
"k8s.io/kubernetes/pkg/client/restclient/fake"
"k8s.io/kubernetes/pkg/client/typed/dynamic"
cmdtesting
"k8s.io/kubernetes/pkg/kubectl/cmd/testing"
"k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/runtime/serializer"
)
var
unstructuredSerializer
=
serializer
.
NegotiatedSerializerWrapper
(
runtime
.
SerializerInfo
{
MediaType
:
"application/json"
,
EncodesAsText
:
true
,
Serializer
:
runtime
.
UnstructuredJSONScheme
})
var
unstructuredSerializer
=
dynamic
.
ContentConfig
()
.
NegotiatedSerializer
func
TestDeleteObjectByTuple
(
t
*
testing
.
T
)
{
_
,
_
,
rc
:=
testData
()
...
...
pkg/kubectl/cmd/get.go
View file @
61673c4b
...
...
@@ -149,7 +149,10 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
selector
:=
cmdutil
.
GetFlagString
(
cmd
,
"selector"
)
allNamespaces
:=
cmdutil
.
GetFlagBool
(
cmd
,
"all-namespaces"
)
showKind
:=
cmdutil
.
GetFlagBool
(
cmd
,
"show-kind"
)
mapper
,
typer
:=
f
.
Object
()
mapper
,
typer
,
err
:=
f
.
UnstructuredObject
()
if
err
!=
nil
{
return
err
}
printAll
:=
false
filterFuncs
:=
f
.
DefaultResourceFilterFunc
()
filterOpts
:=
f
.
DefaultResourceFilterOptions
(
cmd
,
allNamespaces
)
...
...
@@ -196,7 +199,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
// handle watch separately since we cannot watch multiple resource types
isWatch
,
isWatchOnly
:=
cmdutil
.
GetFlagBool
(
cmd
,
"watch"
),
cmdutil
.
GetFlagBool
(
cmd
,
"watch-only"
)
if
isWatch
||
isWatchOnly
{
r
:=
resource
.
NewBuilder
(
mapper
,
typer
,
resource
.
ClientMapperFunc
(
f
.
ClientForMapping
),
f
.
Decoder
(
true
)
)
.
r
:=
resource
.
NewBuilder
(
mapper
,
typer
,
resource
.
ClientMapperFunc
(
f
.
UnstructuredClientForMapping
),
runtime
.
UnstructuredJSONScheme
)
.
NamespaceParam
(
cmdNamespace
)
.
DefaultNamespace
()
.
AllNamespaces
(
allNamespaces
)
.
FilenameParam
(
enforceNamespace
,
&
options
.
FilenameOptions
)
.
SelectorParam
(
selector
)
.
...
...
@@ -281,7 +284,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
return
nil
}
r
:=
resource
.
NewBuilder
(
mapper
,
typer
,
resource
.
ClientMapperFunc
(
f
.
ClientForMapping
),
f
.
Decoder
(
true
)
)
.
r
:=
resource
.
NewBuilder
(
mapper
,
typer
,
resource
.
ClientMapperFunc
(
f
.
UnstructuredClientForMapping
),
runtime
.
UnstructuredJSONScheme
)
.
NamespaceParam
(
cmdNamespace
)
.
DefaultNamespace
()
.
AllNamespaces
(
allNamespaces
)
.
FilenameParam
(
enforceNamespace
,
&
options
.
FilenameOptions
)
.
SelectorParam
(
selector
)
.
...
...
@@ -302,18 +305,10 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
}
if
generic
{
clientConfig
,
err
:=
f
.
ClientConfig
()
if
err
!=
nil
{
return
err
}
// the outermost object will be converted to the output-version, but inner
// objects can use their mappings
version
,
err
:=
cmdutil
.
OutputVersion
(
cmd
,
clientConfig
.
GroupVersion
)
if
err
!=
nil
{
return
err
}
// we flattened the data from the builder, so we have individual items, but now we'd like to either:
// 1. if there is more than one item, combine them all into a single list
// 2. if there is a single item and that item is a list, leave it as its specific list
// 3. if there is a single item and it is not a a list, leave it as a single item
var
errs
[]
error
singular
:=
false
infos
,
err
:=
r
.
IntoSingular
(
&
singular
)
.
Infos
()
...
...
@@ -332,9 +327,22 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
res
=
infos
[
0
]
.
ResourceMapping
()
.
Resource
}
obj
,
err
:=
resource
.
AsVersionedObject
(
infos
,
!
singular
,
version
,
f
.
JSONEncoder
())
if
err
!=
nil
{
return
err
var
obj
runtime
.
Object
if
singular
{
obj
=
infos
[
0
]
.
Object
}
else
{
// we have more than one item, so coerce all items into a list
list
:=
&
runtime
.
UnstructuredList
{
Object
:
map
[
string
]
interface
{}{
"kind"
:
"List"
,
"apiVersion"
:
"v1"
,
"metadata"
:
map
[
string
]
interface
{}{},
},
}
for
_
,
info
:=
range
infos
{
list
.
Items
=
append
(
list
.
Items
,
info
.
Object
.
(
*
runtime
.
Unstructured
))
}
obj
=
list
}
isList
:=
meta
.
IsListType
(
obj
)
...
...
@@ -343,11 +351,24 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
if
err
!=
nil
{
return
err
}
filteredObj
,
err
:=
cmdutil
.
ObjectListToVersionedObject
(
items
,
version
)
if
err
!=
nil
{
return
err
// take the filtered items and create a new list for display
list
:=
&
runtime
.
UnstructuredList
{
Object
:
map
[
string
]
interface
{}{
"kind"
:
"List"
,
"apiVersion"
:
"v1"
,
"metadata"
:
map
[
string
]
interface
{}{},
},
}
if
listMeta
,
err
:=
meta
.
ListAccessor
(
obj
);
err
==
nil
{
list
.
Object
[
"selfLink"
]
=
listMeta
.
GetSelfLink
()
list
.
Object
[
"resourceVersion"
]
=
listMeta
.
GetResourceVersion
()
}
if
err
:=
printer
.
PrintObj
(
filteredObj
,
out
);
err
!=
nil
{
for
_
,
item
:=
range
items
{
list
.
Items
=
append
(
list
.
Items
,
item
.
(
*
runtime
.
Unstructured
))
}
if
err
:=
printer
.
PrintObj
(
list
,
out
);
err
!=
nil
{
errs
=
append
(
errs
,
err
)
}
...
...
@@ -390,24 +411,6 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
}
var
sorter
*
kubectl
.
RuntimeSort
if
len
(
sorting
)
>
0
&&
len
(
objs
)
>
1
{
clientConfig
,
err
:=
f
.
ClientConfig
()
if
err
!=
nil
{
return
err
}
version
,
err
:=
cmdutil
.
OutputVersion
(
cmd
,
clientConfig
.
GroupVersion
)
if
err
!=
nil
{
return
err
}
for
ix
:=
range
infos
{
objs
[
ix
],
err
=
infos
[
ix
]
.
Mapping
.
ConvertToVersion
(
infos
[
ix
]
.
Object
,
version
)
if
err
!=
nil
{
allErrs
=
append
(
allErrs
,
err
)
continue
}
}
// TODO: questionable
if
sorter
,
err
=
kubectl
.
SortObjects
(
f
.
Decoder
(
true
),
objs
,
sorting
);
err
!=
nil
{
return
err
...
...
pkg/kubectl/cmd/get_test.go
View file @
61673c4b
This diff is collapsed.
Click to expand it.
pkg/kubectl/cmd/testing/fake.go
View file @
61673c4b
...
...
@@ -182,7 +182,11 @@ func (f *FakeFactory) Object() (meta.RESTMapper, runtime.ObjectTyper) {
}
func
(
f
*
FakeFactory
)
UnstructuredObject
()
(
meta
.
RESTMapper
,
runtime
.
ObjectTyper
,
error
)
{
return
nil
,
nil
,
nil
groupResources
:=
testDynamicResources
()
mapper
:=
discovery
.
NewRESTMapper
(
groupResources
,
meta
.
InterfacesForUnstructured
)
typer
:=
discovery
.
NewUnstructuredObjectTyper
(
groupResources
)
return
cmdutil
.
NewShortcutExpander
(
mapper
,
nil
),
typer
,
nil
}
func
(
f
*
FakeFactory
)
Decoder
(
bool
)
runtime
.
Decoder
{
...
...
@@ -379,7 +383,7 @@ func (f *fakeMixedFactory) ClientForMapping(m *meta.RESTMapping) (resource.RESTC
}
func
NewMixedFactory
(
apiClient
resource
.
RESTClient
)
(
cmdutil
.
Factory
,
*
TestFactory
,
runtime
.
Codec
)
{
f
,
t
,
c
,
_
:=
New
Test
Factory
()
f
,
t
,
c
,
_
:=
New
API
Factory
()
return
&
fakeMixedFactory
{
Factory
:
f
,
tf
:
t
,
...
...
@@ -545,6 +549,9 @@ func testDynamicResources() []*discovery.APIGroupResources {
{
Name
:
"pods"
,
Namespaced
:
true
,
Kind
:
"Pod"
},
{
Name
:
"services"
,
Namespaced
:
true
,
Kind
:
"Service"
},
{
Name
:
"replicationcontrollers"
,
Namespaced
:
true
,
Kind
:
"ReplicationController"
},
{
Name
:
"componentstatuses"
,
Namespaced
:
false
,
Kind
:
"ComponentStatus"
},
{
Name
:
"nodes"
,
Namespaced
:
false
,
Kind
:
"Node"
},
{
Name
:
"type"
,
Namespaced
:
false
,
Kind
:
"Type"
},
},
},
},
...
...
pkg/kubectl/cmd/util/BUILD
View file @
61673c4b
...
...
@@ -29,12 +29,10 @@ go_library(
"//pkg/api/service:go_default_library",
"//pkg/api/unversioned:go_default_library",
"//pkg/api/validation:go_default_library",
"//pkg/apimachinery:go_default_library",
"//pkg/apimachinery/registered:go_default_library",
"//pkg/apis/apps:go_default_library",
"//pkg/apis/batch:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/apis/extensions/v1beta1:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
"//pkg/client/restclient:go_default_library",
...
...
pkg/kubectl/cmd/util/factory.go
View file @
61673c4b
...
...
@@ -33,23 +33,19 @@ import (
"time"
"github.com/emicklei/go-restful/swagger"
"github.com/golang/glog"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"k8s.io/kubernetes/federation/apis/federation"
"k8s.io/kubernetes/pkg/api"
apierrors
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/service"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/validation"
"k8s.io/kubernetes/pkg/apimachinery"
"k8s.io/kubernetes/pkg/apimachinery/registered"
"k8s.io/kubernetes/pkg/apis/apps"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/apis/extensions"
extensionsv1beta1
"k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
coreclient
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
"k8s.io/kubernetes/pkg/client/restclient"
...
...
@@ -339,21 +335,10 @@ func (f *factory) Object() (meta.RESTMapper, runtime.ObjectTyper) {
mapper
:=
registered
.
RESTMapper
()
discoveryClient
,
err
:=
discovery
.
NewDiscoveryClientForConfig
(
cfg
)
if
err
==
nil
{
// register third party resources with the api machinery groups. This probably should be done, but
// its consistent with old code, so we'll start with it.
if
err
:=
registerThirdPartyResources
(
discoveryClient
);
err
!=
nil
{
glog
.
V
(
1
)
.
Infof
(
"Unable to register third party resources: %v"
,
err
)
}
// ThirdPartyResourceData is special. It's not discoverable, but needed for thirdparty resource listing
// TODO eliminate this once we're truly generic.
thirdPartyResourceDataMapper
:=
meta
.
NewDefaultRESTMapper
([]
unversioned
.
GroupVersion
{
extensionsv1beta1
.
SchemeGroupVersion
},
registered
.
InterfacesFor
)
thirdPartyResourceDataMapper
.
Add
(
extensionsv1beta1
.
SchemeGroupVersion
.
WithKind
(
"ThirdPartyResourceData"
),
meta
.
RESTScopeNamespace
)
mapper
=
meta
.
FirstHitRESTMapper
{
MultiRESTMapper
:
meta
.
MultiRESTMapper
{
discovery
.
NewDeferredDiscoveryRESTMapper
(
discoveryClient
,
registered
.
InterfacesFor
),
thirdPartyResourceDataMapper
,
// needed for TPR printing
registered
.
RESTMapper
(),
// hardcoded fall back
registered
.
RESTMapper
(),
// hardcoded fall back
},
}
}
...
...
@@ -1331,54 +1316,3 @@ func (f *factory) SuggestedPodTemplateResources() []unversioned.GroupResource {
{
Resource
:
"replicaset"
},
}
}
// registerThirdPartyResources inspects the discovery endpoint to find thirdpartyresources in the discovery doc
// and then registers them with the apimachinery code. I think this is done so that scheme/codec stuff works,
// but I really don't know. Feels like this code should go away once kubectl is completely generic for generic
// CRUD
func
registerThirdPartyResources
(
discoveryClient
discovery
.
DiscoveryInterface
)
error
{
var
versions
[]
unversioned
.
GroupVersion
var
gvks
[]
unversioned
.
GroupVersionKind
var
err
error
retries
:=
3
for
i
:=
0
;
i
<
retries
;
i
++
{
versions
,
gvks
,
err
=
GetThirdPartyGroupVersions
(
discoveryClient
)
// Retry if we got a NotFound error, because user may delete
// a thirdparty group when the GetThirdPartyGroupVersions is
// running.
if
err
==
nil
||
!
apierrors
.
IsNotFound
(
err
)
{
break
}
}
if
err
!=
nil
{
return
err
}
groupsMap
:=
map
[
string
][]
unversioned
.
GroupVersion
{}
for
_
,
version
:=
range
versions
{
groupsMap
[
version
.
Group
]
=
append
(
groupsMap
[
version
.
Group
],
version
)
}
for
group
,
versionList
:=
range
groupsMap
{
preferredExternalVersion
:=
versionList
[
0
]
thirdPartyMapper
,
err
:=
kubectl
.
NewThirdPartyResourceMapper
(
versionList
,
getGroupVersionKinds
(
gvks
,
group
))
if
err
!=
nil
{
return
err
}
accessor
:=
meta
.
NewAccessor
()
groupMeta
:=
apimachinery
.
GroupMeta
{
GroupVersion
:
preferredExternalVersion
,
GroupVersions
:
versionList
,
RESTMapper
:
thirdPartyMapper
,
SelfLinker
:
runtime
.
SelfLinker
(
accessor
),
InterfacesFor
:
makeInterfacesFor
(
versionList
),
}
if
err
:=
registered
.
RegisterGroup
(
groupMeta
);
err
!=
nil
{
return
err
}
registered
.
AddThirdPartyAPIGroupVersions
(
versionList
...
)
}
return
nil
}
pkg/kubectl/cmd/util/helpers.go
View file @
61673c4b
...
...
@@ -34,7 +34,6 @@ import (
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apimachinery/registered"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/client/typed/discovery"
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/resource"
...
...
@@ -551,49 +550,6 @@ func ShouldRecord(cmd *cobra.Command, info *resource.Info) bool {
return
GetRecordFlag
(
cmd
)
||
(
ContainsChangeCause
(
info
)
&&
!
cmd
.
Flags
()
.
Changed
(
"record"
))
}
// GetThirdPartyGroupVersions returns the thirdparty "group/versions"s and
// resources supported by the server. A user may delete a thirdparty resource
// when this function is running, so this function may return a "NotFound" error
// due to the race.
func
GetThirdPartyGroupVersions
(
discovery
discovery
.
DiscoveryInterface
)
([]
unversioned
.
GroupVersion
,
[]
unversioned
.
GroupVersionKind
,
error
)
{
result
:=
[]
unversioned
.
GroupVersion
{}
gvks
:=
[]
unversioned
.
GroupVersionKind
{}
groupList
,
err
:=
discovery
.
ServerGroups
()
if
err
!=
nil
{
// On forbidden or not found, just return empty lists.
if
kerrors
.
IsForbidden
(
err
)
||
kerrors
.
IsNotFound
(
err
)
{
return
result
,
gvks
,
nil
}
return
nil
,
nil
,
err
}
for
ix
:=
range
groupList
.
Groups
{
group
:=
&
groupList
.
Groups
[
ix
]
for
jx
:=
range
group
.
Versions
{
gv
,
err2
:=
unversioned
.
ParseGroupVersion
(
group
.
Versions
[
jx
]
.
GroupVersion
)
if
err2
!=
nil
{
return
nil
,
nil
,
err
}
// Skip GroupVersionKinds that have been statically registered.
if
registered
.
IsRegisteredVersion
(
gv
)
{
continue
}
result
=
append
(
result
,
gv
)
resourceList
,
err
:=
discovery
.
ServerResourcesForGroupVersion
(
group
.
Versions
[
jx
]
.
GroupVersion
)
if
err
!=
nil
{
return
nil
,
nil
,
err
}
for
kx
:=
range
resourceList
.
APIResources
{
gvks
=
append
(
gvks
,
gv
.
WithKind
(
resourceList
.
APIResources
[
kx
]
.
Kind
))
}
}
}
return
result
,
gvks
,
nil
}
func
AddInclude3rdPartyFlags
(
cmd
*
cobra
.
Command
)
{
cmd
.
Flags
()
.
Bool
(
"include-extended-apis"
,
true
,
"If true, include definitions of new APIs via calls to the API server. [default true]"
)
cmd
.
Flags
()
.
MarkDeprecated
(
"include-extended-apis"
,
"No longer required."
)
...
...
pkg/kubectl/custom_column_printer.go
View file @
61673c4b
...
...
@@ -206,9 +206,18 @@ func (s *CustomColumnsPrinter) printOneObject(obj runtime.Object, parsers []*jso
}
}
}
for
ix
:=
range
parsers
{
parser
:=
parsers
[
ix
]
values
,
err
:=
parser
.
FindResults
(
reflect
.
ValueOf
(
obj
)
.
Elem
()
.
Interface
())
var
values
[][]
reflect
.
Value
var
err
error
if
unstructured
,
ok
:=
obj
.
(
*
runtime
.
Unstructured
);
ok
{
values
,
err
=
parser
.
FindResults
(
unstructured
.
Object
)
}
else
{
values
,
err
=
parser
.
FindResults
(
reflect
.
ValueOf
(
obj
)
.
Elem
()
.
Interface
())
}
if
err
!=
nil
{
return
err
}
...
...
pkg/kubectl/kubectl.go
View file @
61673c4b
...
...
@@ -48,28 +48,6 @@ func makeImageList(spec *api.PodSpec) string {
return
strings
.
Join
(
listOfImages
(
spec
),
","
)
}
func
NewThirdPartyResourceMapper
(
gvs
[]
unversioned
.
GroupVersion
,
gvks
[]
unversioned
.
GroupVersionKind
)
(
meta
.
RESTMapper
,
error
)
{
mapper
:=
meta
.
NewDefaultRESTMapper
(
gvs
,
func
(
gv
unversioned
.
GroupVersion
)
(
*
meta
.
VersionInterfaces
,
error
)
{
for
ix
:=
range
gvs
{
if
gvs
[
ix
]
.
Group
==
gv
.
Group
&&
gvs
[
ix
]
.
Version
==
gv
.
Version
{
return
&
meta
.
VersionInterfaces
{
ObjectConvertor
:
api
.
Scheme
,
MetadataAccessor
:
meta
.
NewAccessor
(),
},
nil
}
}
groupVersions
:=
make
([]
string
,
0
,
len
(
gvs
))
for
ix
:=
range
gvs
{
groupVersions
=
append
(
groupVersions
,
gvs
[
ix
]
.
String
())
}
return
nil
,
fmt
.
Errorf
(
"unsupported storage version: %s (valid: %s)"
,
gv
.
String
(),
strings
.
Join
(
groupVersions
,
", "
))
})
for
ix
:=
range
gvks
{
mapper
.
Add
(
gvks
[
ix
],
meta
.
RESTScopeNamespace
)
}
return
mapper
,
nil
}
// OutputVersionMapper is a RESTMapper that will prefer mappings that
// correspond to a preferred output version (if feasible)
type
OutputVersionMapper
struct
{
...
...
pkg/kubectl/resource_printer.go
View file @
61673c4b
...
...
@@ -241,8 +241,6 @@ func (p *NamePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
return
nil
}
// TODO: this is wrong, runtime.Unknown and runtime.Unstructured are not handled properly here.
name
:=
"<unknown>"
if
acc
,
err
:=
meta
.
Accessor
(
obj
);
err
==
nil
{
if
n
:=
acc
.
GetName
();
len
(
n
)
>
0
{
...
...
@@ -250,12 +248,22 @@ func (p *NamePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
}
}
if
gvks
,
_
,
err
:=
p
.
Typer
.
ObjectKinds
(
obj
);
err
==
nil
{
if
kind
:=
obj
.
GetObjectKind
()
.
GroupVersionKind
();
len
(
kind
.
Kind
)
==
0
{
// this is the old code. It's unnecessary on decoded external objects, but on internal objects
// you may have to do it. Tests are definitely calling it with internals and I'm not sure who else
// is
if
gvks
,
_
,
err
:=
p
.
Typer
.
ObjectKinds
(
obj
);
err
==
nil
{
// TODO: this is wrong, it assumes that meta knows about all Kinds - should take a RESTMapper
_
,
resource
:=
meta
.
KindToResource
(
gvks
[
0
])
fmt
.
Fprintf
(
w
,
"%s/%s
\n
"
,
resource
.
Resource
,
name
)
}
else
{
fmt
.
Fprintf
(
w
,
"<unknown>/%s
\n
"
,
name
)
}
}
else
{
// TODO: this is wrong, it assumes that meta knows about all Kinds - should take a RESTMapper
_
,
resource
:=
meta
.
KindToResource
(
gvks
[
0
]
)
_
,
resource
:=
meta
.
KindToResource
(
kind
)
fmt
.
Fprintf
(
w
,
"%s/%s
\n
"
,
resource
.
Resource
,
name
)
}
else
{
fmt
.
Fprintf
(
w
,
"<unknown>/%s
\n
"
,
name
)
}
return
nil
...
...
@@ -2251,6 +2259,18 @@ func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) er
w
=
GetNewTabWriter
(
output
)
defer
w
.
Flush
()
}
// check if the object is unstructured. If so, let's attempt to convert it to a type we can understand before
// trying to print, since the printers are keyed by type. This is extremely expensive.
switch
obj
.
(
type
)
{
case
*
runtime
.
Unstructured
,
*
runtime
.
Unknown
:
if
objBytes
,
err
:=
runtime
.
Encode
(
api
.
Codecs
.
LegacyCodec
(),
obj
);
err
==
nil
{
if
decodedObj
,
err
:=
runtime
.
Decode
(
api
.
Codecs
.
UniversalDecoder
(),
objBytes
);
err
==
nil
{
obj
=
decodedObj
}
}
}
t
:=
reflect
.
TypeOf
(
obj
)
if
handler
:=
h
.
handlerMap
[
t
];
handler
!=
nil
{
if
!
h
.
options
.
NoHeaders
&&
t
!=
h
.
lastType
{
...
...
@@ -2271,9 +2291,78 @@ func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) er
}
return
resultValue
.
Interface
()
.
(
error
)
}
// we don't recognize this type, but we can still attempt to print some reasonable information about.
unstructured
,
ok
:=
obj
.
(
*
runtime
.
Unstructured
)
if
!
ok
{
return
fmt
.
Errorf
(
"error: unknown type %#v"
,
obj
)
}
if
_
,
err
:=
meta
.
Accessor
(
obj
);
err
==
nil
{
if
!
h
.
options
.
NoHeaders
&&
t
!=
h
.
lastType
{
headers
:=
[]
string
{
"NAME"
,
"KIND"
}
headers
=
append
(
headers
,
formatLabelHeaders
(
h
.
options
.
ColumnLabels
)
...
)
// LABELS is always the last column.
headers
=
append
(
headers
,
formatShowLabelsHeader
(
h
.
options
.
ShowLabels
,
t
)
...
)
if
h
.
options
.
WithNamespace
{
headers
=
append
(
withNamespacePrefixColumns
,
headers
...
)
}
h
.
printHeader
(
headers
,
w
)
h
.
lastType
=
t
}
// if the error isn't nil, report the "I don't recognize this" error
if
err
:=
printUnstructured
(
unstructured
,
w
,
h
.
options
);
err
!=
nil
{
return
err
}
return
nil
}
// we failed all reasonable printing efforts, report failure
return
fmt
.
Errorf
(
"error: unknown type %#v"
,
obj
)
}
func
printUnstructured
(
unstructured
*
runtime
.
Unstructured
,
w
io
.
Writer
,
options
PrintOptions
)
error
{
metadata
,
err
:=
meta
.
Accessor
(
unstructured
)
if
err
!=
nil
{
return
err
}
if
options
.
WithNamespace
{
if
_
,
err
:=
fmt
.
Fprintf
(
w
,
"%s
\t
"
,
metadata
.
GetNamespace
());
err
!=
nil
{
return
err
}
}
kind
:=
"<missing>"
if
objKind
,
ok
:=
unstructured
.
Object
[
"kind"
];
ok
{
if
str
,
ok
:=
objKind
.
(
string
);
ok
{
kind
=
str
}
}
if
objAPIVersion
,
ok
:=
unstructured
.
Object
[
"apiVersion"
];
ok
{
if
str
,
ok
:=
objAPIVersion
.
(
string
);
ok
{
version
,
err
:=
unversioned
.
ParseGroupVersion
(
str
)
if
err
!=
nil
{
return
err
}
kind
=
kind
+
"."
+
version
.
Version
+
"."
+
version
.
Group
}
}
name
:=
formatResourceName
(
options
.
Kind
,
metadata
.
GetName
(),
options
.
WithKind
)
if
_
,
err
:=
fmt
.
Fprintf
(
w
,
"%s
\t
%s"
,
name
,
kind
);
err
!=
nil
{
return
err
}
if
_
,
err
:=
fmt
.
Fprint
(
w
,
AppendLabels
(
metadata
.
GetLabels
(),
options
.
ColumnLabels
));
err
!=
nil
{
return
err
}
if
_
,
err
:=
fmt
.
Fprint
(
w
,
AppendAllLabels
(
options
.
ShowLabels
,
metadata
.
GetLabels
()));
err
!=
nil
{
return
err
}
return
nil
}
// TemplatePrinter is an implementation of ResourcePrinter which formats data with a Go Template.
type
TemplatePrinter
struct
{
rawTemplate
string
...
...
@@ -2299,10 +2388,18 @@ func (p *TemplatePrinter) AfterPrint(w io.Writer, res string) error {
// PrintObj formats the obj with the Go Template.
func
(
p
*
TemplatePrinter
)
PrintObj
(
obj
runtime
.
Object
,
w
io
.
Writer
)
error
{
data
,
err
:=
json
.
Marshal
(
obj
)
var
data
[]
byte
var
err
error
if
unstructured
,
ok
:=
obj
.
(
*
runtime
.
Unstructured
);
ok
{
data
,
err
=
json
.
Marshal
(
unstructured
.
Object
)
}
else
{
data
,
err
=
json
.
Marshal
(
obj
)
}
if
err
!=
nil
{
return
err
}
out
:=
map
[
string
]
interface
{}{}
if
err
:=
json
.
Unmarshal
(
data
,
&
out
);
err
!=
nil
{
return
err
...
...
@@ -2462,6 +2559,20 @@ func (j *JSONPathPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
}
}
if
unknown
,
ok
:=
obj
.
(
*
runtime
.
Unknown
);
ok
{
data
,
err
:=
json
.
Marshal
(
unknown
)
if
err
!=
nil
{
return
err
}
queryObj
=
map
[
string
]
interface
{}{}
if
err
:=
json
.
Unmarshal
(
data
,
&
queryObj
);
err
!=
nil
{
return
err
}
}
if
unstructured
,
ok
:=
obj
.
(
*
runtime
.
Unstructured
);
ok
{
queryObj
=
unstructured
.
Object
}
if
err
:=
j
.
JSONPath
.
Execute
(
w
,
queryObj
);
err
!=
nil
{
fmt
.
Fprintf
(
w
,
"Error executing template: %v. Printing more information for debugging the template:
\n
"
,
err
)
fmt
.
Fprintf
(
w
,
"
\t
template was:
\n\t\t
%v
\n
"
,
j
.
rawTemplate
)
...
...
pkg/kubectl/sorting_printer.go
View file @
61673c4b
...
...
@@ -109,7 +109,13 @@ func SortObjects(decoder runtime.Decoder, objs []runtime.Object, fieldInput stri
}
}
values
,
err
:=
parser
.
FindResults
(
reflect
.
ValueOf
(
objs
[
0
])
.
Elem
()
.
Interface
())
var
values
[][]
reflect
.
Value
if
unstructured
,
ok
:=
objs
[
0
]
.
(
*
runtime
.
Unstructured
);
ok
{
values
,
err
=
parser
.
FindResults
(
unstructured
.
Object
)
}
else
{
values
,
err
=
parser
.
FindResults
(
reflect
.
ValueOf
(
objs
[
0
])
.
Elem
()
.
Interface
())
}
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -182,6 +188,66 @@ func isLess(i, j reflect.Value) (bool, error) {
}
}
return
true
,
nil
case
reflect
.
Interface
:
switch
itype
:=
i
.
Interface
()
.
(
type
)
{
case
uint8
:
if
jtype
,
ok
:=
j
.
Interface
()
.
(
uint8
);
ok
{
return
itype
<
jtype
,
nil
}
case
uint16
:
if
jtype
,
ok
:=
j
.
Interface
()
.
(
uint16
);
ok
{
return
itype
<
jtype
,
nil
}
case
uint32
:
if
jtype
,
ok
:=
j
.
Interface
()
.
(
uint32
);
ok
{
return
itype
<
jtype
,
nil
}
case
uint64
:
if
jtype
,
ok
:=
j
.
Interface
()
.
(
uint64
);
ok
{
return
itype
<
jtype
,
nil
}
case
int8
:
if
jtype
,
ok
:=
j
.
Interface
()
.
(
int8
);
ok
{
return
itype
<
jtype
,
nil
}
case
int16
:
if
jtype
,
ok
:=
j
.
Interface
()
.
(
int16
);
ok
{
return
itype
<
jtype
,
nil
}
case
int32
:
if
jtype
,
ok
:=
j
.
Interface
()
.
(
int32
);
ok
{
return
itype
<
jtype
,
nil
}
case
int64
:
if
jtype
,
ok
:=
j
.
Interface
()
.
(
int64
);
ok
{
return
itype
<
jtype
,
nil
}
case
uint
:
if
jtype
,
ok
:=
j
.
Interface
()
.
(
uint
);
ok
{
return
itype
<
jtype
,
nil
}
case
int
:
if
jtype
,
ok
:=
j
.
Interface
()
.
(
int
);
ok
{
return
itype
<
jtype
,
nil
}
case
float32
:
if
jtype
,
ok
:=
j
.
Interface
()
.
(
float32
);
ok
{
return
itype
<
jtype
,
nil
}
case
float64
:
if
jtype
,
ok
:=
j
.
Interface
()
.
(
float64
);
ok
{
return
itype
<
jtype
,
nil
}
case
string
:
if
jtype
,
ok
:=
j
.
Interface
()
.
(
string
);
ok
{
return
itype
<
jtype
,
nil
}
default
:
return
false
,
fmt
.
Errorf
(
"unsortable type: %T"
,
itype
)
}
return
false
,
fmt
.
Errorf
(
"unsortable interface: %v"
,
i
.
Kind
())
default
:
return
false
,
fmt
.
Errorf
(
"unsortable type: %v"
,
i
.
Kind
())
}
...
...
@@ -194,11 +260,24 @@ func (r *RuntimeSort) Less(i, j int) bool {
parser
:=
jsonpath
.
New
(
"sorting"
)
parser
.
Parse
(
r
.
field
)
iValues
,
err
:=
parser
.
FindResults
(
reflect
.
ValueOf
(
iObj
)
.
Elem
()
.
Interface
())
var
iValues
[][]
reflect
.
Value
var
jValues
[][]
reflect
.
Value
var
err
error
if
unstructured
,
ok
:=
iObj
.
(
*
runtime
.
Unstructured
);
ok
{
iValues
,
err
=
parser
.
FindResults
(
unstructured
.
Object
)
}
else
{
iValues
,
err
=
parser
.
FindResults
(
reflect
.
ValueOf
(
iObj
)
.
Elem
()
.
Interface
())
}
if
err
!=
nil
{
glog
.
Fatalf
(
"Failed to get i values for %#v using %s (%#v)"
,
iObj
,
r
.
field
,
err
)
}
jValues
,
err
:=
parser
.
FindResults
(
reflect
.
ValueOf
(
jObj
)
.
Elem
()
.
Interface
())
if
unstructured
,
ok
:=
jObj
.
(
*
runtime
.
Unstructured
);
ok
{
jValues
,
err
=
parser
.
FindResults
(
unstructured
.
Object
)
}
else
{
jValues
,
err
=
parser
.
FindResults
(
reflect
.
ValueOf
(
jObj
)
.
Elem
()
.
Interface
())
}
if
err
!=
nil
{
glog
.
Fatalf
(
"Failed to get j values for %#v using %s (%v)"
,
jObj
,
r
.
field
,
err
)
}
...
...
test/e2e/kubectl.go
View file @
61673c4b
...
...
@@ -551,25 +551,25 @@ var _ = framework.KubeDescribe("Kubectl client", func() {
By
(
"checking the result"
)
forEachReplicationController
(
c
,
ns
,
"app"
,
"redis"
,
validateReplicationControllerConfiguration
)
})
It
(
"should reuse
nodeP
ort when apply to an existing SVC"
,
func
()
{
It
(
"should reuse
p
ort when apply to an existing SVC"
,
func
()
{
serviceJson
:=
readTestFileOrDie
(
redisServiceFilename
)
nsFlag
:=
fmt
.
Sprintf
(
"--namespace=%v"
,
ns
)
By
(
"creating Redis SVC"
)
framework
.
RunKubectlOrDieInput
(
string
(
serviceJson
[
:
]),
"create"
,
"-f"
,
"-"
,
nsFlag
)
By
(
"getting the original
nodeP
ort"
)
originalNodePort
:=
framework
.
RunKubectlOrDie
(
"get"
,
"service"
,
"redis-master"
,
nsFlag
,
"-o"
,
"jsonpath={.spec.ports[0].
nodeP
ort}"
)
By
(
"getting the original
p
ort"
)
originalNodePort
:=
framework
.
RunKubectlOrDie
(
"get"
,
"service"
,
"redis-master"
,
nsFlag
,
"-o"
,
"jsonpath={.spec.ports[0].
p
ort}"
)
By
(
"applying the same configuration"
)
framework
.
RunKubectlOrDieInput
(
string
(
serviceJson
[
:
]),
"apply"
,
"-f"
,
"-"
,
nsFlag
)
By
(
"getting the
nodeP
ort after applying configuration"
)
currentNodePort
:=
framework
.
RunKubectlOrDie
(
"get"
,
"service"
,
"redis-master"
,
nsFlag
,
"-o"
,
"jsonpath={.spec.ports[0].
nodeP
ort}"
)
By
(
"getting the
p
ort after applying configuration"
)
currentNodePort
:=
framework
.
RunKubectlOrDie
(
"get"
,
"service"
,
"redis-master"
,
nsFlag
,
"-o"
,
"jsonpath={.spec.ports[0].
p
ort}"
)
By
(
"checking the result"
)
if
originalNodePort
!=
currentNodePort
{
framework
.
Failf
(
"
nodeP
ort should keep the same"
)
framework
.
Failf
(
"
p
ort should keep the same"
)
}
})
})
...
...
test/test_owners.csv
View file @
61673c4b
...
...
@@ -181,7 +181,7 @@ Kubectl alpha client Kubectl run ScheduledJob should create a ScheduledJob,karga
Kubectl client Guestbook application should create and stop a working application,pwittrock,0
Kubectl client Kubectl api-versions should check if v1 is in available api versions,pwittrock,0
Kubectl client Kubectl apply should apply a new configuration to an existing RC,pwittrock,0
Kubectl client Kubectl apply should reuse
nodePort when apply to an existing SVC,pwittroc
k,0
Kubectl client Kubectl apply should reuse
port when apply to an existing SVC,deads2
k,0
Kubectl client Kubectl cluster-info should check if Kubernetes master services is included in cluster-info,pwittrock,0
Kubectl client Kubectl create quota should create a quota with scopes,jdef,1
Kubectl client Kubectl create quota should create a quota without scopes,xiang90,1
...
...
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