add canonical full and short names for objects commands

mine
Gustavo Paiva 2019-09-20 11:27:13 -03:00
parent b87c6bc0b7
commit 3c83c37d03
5 changed files with 376 additions and 345 deletions

View File

@ -26,12 +26,12 @@ type RestMapper struct {
Connection Connection
} }
// Find a mapping given a resource name. // Find a mapping given a resource kind.
func (*RestMapper) Find(res string) (*meta.RESTMapping, error) { func (*RestMapper) Find(kind string) (*meta.RESTMapping, error) {
if m, ok := resMap[res]; ok { if m, ok := kindToMapper[kind]; ok {
return m, nil return m, nil
} }
return nil, fmt.Errorf("no mapping for resource %s", res) return nil, fmt.Errorf("no mapping for kind %s", kind)
} }
// ToRESTMapper map resources to kind, and map kind and version to interfaces for manipulating K8s objects. // ToRESTMapper map resources to kind, and map kind and version to interfaces for manipulating K8s objects.
@ -116,18 +116,18 @@ func (*RestMapper) Name() meta.RESTScopeName {
return meta.RESTScopeNameNamespace return meta.RESTScopeNameNamespace
} }
var resMap = map[string]*meta.RESTMapping{ var kindToMapper = map[string]*meta.RESTMapping{
"ConfigMaps": { "ConfigMap": {
Resource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "configmap"}, Resource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "configmap"},
GroupVersionKind: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ConfigMap"}, GroupVersionKind: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ConfigMap"},
Scope: RestMapping, Scope: RestMapping,
}, },
"Pods": { "Pod": {
Resource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pod"}, Resource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pod"},
GroupVersionKind: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"}, GroupVersionKind: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"},
Scope: RestMapping, Scope: RestMapping,
}, },
"Services": { "Service": {
Resource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "service"}, Resource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "service"},
GroupVersionKind: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Service"}, GroupVersionKind: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Service"},
Scope: RestMapping, Scope: RestMapping,
@ -137,81 +137,81 @@ var resMap = map[string]*meta.RESTMapping{
GroupVersionKind: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Endpoints"}, GroupVersionKind: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Endpoints"},
Scope: RestMapping, Scope: RestMapping,
}, },
"Namespaces": { "Namespace": {
Resource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "namespace"}, Resource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "namespace"},
GroupVersionKind: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Namespace"}, GroupVersionKind: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Namespace"},
Scope: RestMapping, Scope: RestMapping,
}, },
"Nodes": { "Node": {
Resource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "node"}, Resource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "node"},
GroupVersionKind: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Node"}, GroupVersionKind: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Node"},
Scope: RestMapping, Scope: RestMapping,
}, },
"PersistentVolumes": { "PersistentVolume": {
Resource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "persistentvolume"}, Resource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "persistentvolume"},
GroupVersionKind: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "PersistentVolume"}, GroupVersionKind: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "PersistentVolume"},
Scope: RestMapping, Scope: RestMapping,
}, },
"PersistentVolumeClaims": { "PersistentVolumeClaim": {
Resource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "persistentvolumeclaim"}, Resource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "persistentvolumeclaim"},
GroupVersionKind: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "PersistentVolumeClaim"}, GroupVersionKind: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "PersistentVolumeClaim"},
Scope: RestMapping, Scope: RestMapping,
}, },
"ReplicationControllers": { "ReplicationController": {
Resource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "replicationcontroller"}, Resource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "replicationcontroller"},
GroupVersionKind: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ReplicationController"}, GroupVersionKind: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ReplicationController"},
Scope: RestMapping, Scope: RestMapping,
}, },
"Secrets": { "Secret": {
Resource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "secret"}, Resource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "secret"},
GroupVersionKind: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Secret"}, GroupVersionKind: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Secret"},
Scope: RestMapping, Scope: RestMapping,
}, },
"StorageClasses": { "StorageClasse": {
Resource: schema.GroupVersionResource{Group: "storage.k8s.io", Version: "v1", Resource: "storageclass"}, Resource: schema.GroupVersionResource{Group: "storage.k8s.io", Version: "v1", Resource: "storageclass"},
GroupVersionKind: schema.GroupVersionKind{Group: "storage.k8s.io", Version: "v1", Kind: "StorageClass"}, GroupVersionKind: schema.GroupVersionKind{Group: "storage.k8s.io", Version: "v1", Kind: "StorageClass"},
Scope: RestMapping, Scope: RestMapping,
}, },
"ServiceAccounts": { "ServiceAccount": {
Resource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "serviceaccount"}, Resource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "serviceaccount"},
GroupVersionKind: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ServiceAccount"}, GroupVersionKind: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ServiceAccount"},
Scope: RestMapping, Scope: RestMapping,
}, },
"Deployments": { "Deployment": {
Resource: schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployment"}, Resource: schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployment"},
GroupVersionKind: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}, GroupVersionKind: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
Scope: RestMapping, Scope: RestMapping,
}, },
"ReplicaSets": { "ReplicaSet": {
Resource: schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "replicaset"}, Resource: schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "replicaset"},
GroupVersionKind: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "ReplicaSet"}, GroupVersionKind: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "ReplicaSet"},
Scope: RestMapping, Scope: RestMapping,
}, },
"StatefulSets": { "StatefulSet": {
Resource: schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "statefulsets"}, Resource: schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "statefulsets"},
GroupVersionKind: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "StatefulSet"}, GroupVersionKind: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "StatefulSet"},
Scope: RestMapping, Scope: RestMapping,
}, },
"HorizontalPodAutoscalers": { "HorizontalPodAutoscaler": {
Resource: schema.GroupVersionResource{Group: "autoscaling", Version: "v1", Resource: "horizontalpodautoscaler"}, Resource: schema.GroupVersionResource{Group: "autoscaling", Version: "v1", Resource: "horizontalpodautoscaler"},
GroupVersionKind: schema.GroupVersionKind{Group: "autoscaling", Version: "v1", Kind: "HorizontalPodAutoscaler"}, GroupVersionKind: schema.GroupVersionKind{Group: "autoscaling", Version: "v1", Kind: "HorizontalPodAutoscaler"},
Scope: RestMapping, Scope: RestMapping,
}, },
"Jobs": { "Job": {
Resource: schema.GroupVersionResource{Group: "batch", Version: "v1", Resource: "job"}, Resource: schema.GroupVersionResource{Group: "batch", Version: "v1", Resource: "job"},
GroupVersionKind: schema.GroupVersionKind{Group: "batch", Version: "v1", Kind: "Job"}, GroupVersionKind: schema.GroupVersionKind{Group: "batch", Version: "v1", Kind: "Job"},
Scope: RestMapping, Scope: RestMapping,
}, },
"CronJobs": { "CronJob": {
Resource: schema.GroupVersionResource{Group: "batch", Version: "v1", Resource: "cronjob"}, Resource: schema.GroupVersionResource{Group: "batch", Version: "v1", Resource: "cronjob"},
GroupVersionKind: schema.GroupVersionKind{Group: "batch", Version: "v1", Kind: "CronJob"}, GroupVersionKind: schema.GroupVersionKind{Group: "batch", Version: "v1", Kind: "CronJob"},
Scope: RestMapping, Scope: RestMapping,
}, },
"DaemonSets": { "DaemonSet": {
Resource: schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "daemonset"}, Resource: schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "daemonset"},
GroupVersionKind: schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "DaemonSet"}, GroupVersionKind: schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "DaemonSet"},
Scope: RestMapping, Scope: RestMapping,
@ -222,45 +222,45 @@ var resMap = map[string]*meta.RESTMapping{
Scope: RestMapping, Scope: RestMapping,
}, },
"ClusterRoles": { "ClusterRole": {
Resource: schema.GroupVersionResource{Group: "rbac.authorization.k8s.io", Version: "v1", Resource: "clusterrole"}, Resource: schema.GroupVersionResource{Group: "rbac.authorization.k8s.io", Version: "v1", Resource: "clusterrole"},
GroupVersionKind: schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "ClusterRole"}, GroupVersionKind: schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "ClusterRole"},
Scope: RestMapping, Scope: RestMapping,
}, },
"ClusterRoleBindings": { "ClusterRoleBinding": {
Resource: schema.GroupVersionResource{Group: "rbac.authorization.k8s.io", Version: "v1", Resource: "clusterrolebinding"}, Resource: schema.GroupVersionResource{Group: "rbac.authorization.k8s.io", Version: "v1", Resource: "clusterrolebinding"},
GroupVersionKind: schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "ClusterRoleBinding"}, GroupVersionKind: schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "ClusterRoleBinding"},
Scope: RestMapping, Scope: RestMapping,
}, },
"Roles": { "Role": {
Resource: schema.GroupVersionResource{Group: "rbac.authorization.k8s.io", Version: "v1", Resource: "role"}, Resource: schema.GroupVersionResource{Group: "rbac.authorization.k8s.io", Version: "v1", Resource: "role"},
GroupVersionKind: schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "Role"}, GroupVersionKind: schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "Role"},
Scope: RestMapping, Scope: RestMapping,
}, },
"RoleBindings": { "RoleBinding": {
Resource: schema.GroupVersionResource{Group: "rbac.authorization.k8s.io", Version: "v1", Resource: "rolebinding"}, Resource: schema.GroupVersionResource{Group: "rbac.authorization.k8s.io", Version: "v1", Resource: "rolebinding"},
GroupVersionKind: schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "RoleBinding"}, GroupVersionKind: schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "RoleBinding"},
Scope: RestMapping, Scope: RestMapping,
}, },
"CustomResourceDefinitions": { "CustomResourceDefinition": {
Resource: schema.GroupVersionResource{Group: "apiextensions.k8s.io", Version: "v1beta1", Resource: "customresourcedefinitions"}, Resource: schema.GroupVersionResource{Group: "apiextensions.k8s.io", Version: "v1beta1", Resource: "customresourcedefinitions"},
GroupVersionKind: schema.GroupVersionKind{Group: "apiextensions.k8s.io", Version: "v1beta1", Kind: "CustomResourceDefinition"}, GroupVersionKind: schema.GroupVersionKind{Group: "apiextensions.k8s.io", Version: "v1beta1", Kind: "CustomResourceDefinition"},
Scope: RestMapping, Scope: RestMapping,
}, },
"NetworkPolicies": { "NetworkPolicy": {
Resource: schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "networkpolicies"}, Resource: schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "networkpolicies"},
GroupVersionKind: schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "NetworkPolicy"}, GroupVersionKind: schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "NetworkPolicy"},
Scope: RestMapping, Scope: RestMapping,
}, },
"Events": { "Event": {
Resource: schema.GroupVersionResource{Group: "events.k8s.io", Version: "v1beta1", Resource: "events"}, Resource: schema.GroupVersionResource{Group: "events.k8s.io", Version: "v1beta1", Resource: "events"},
GroupVersionKind: schema.GroupVersionKind{Group: "events.k8s.io", Version: "v1beta1", Kind: "Event"}, GroupVersionKind: schema.GroupVersionKind{Group: "events.k8s.io", Version: "v1beta1", Kind: "Event"},
Scope: RestMapping, Scope: RestMapping,
}, },
"PodDisruptionBudgets": { "PodDisruptionBudget": {
Resource: schema.GroupVersionResource{Group: "policy", Version: "v1beta1", Resource: "poddisruptionbudgets"}, Resource: schema.GroupVersionResource{Group: "policy", Version: "v1beta1", Resource: "poddisruptionbudgets"},
GroupVersionKind: schema.GroupVersionKind{Group: "policy", Version: "v1beta1", Kind: "PodDisruptionBudget"}, GroupVersionKind: schema.GroupVersionKind{Group: "policy", Version: "v1beta1", Kind: "PodDisruptionBudget"},
Scope: RestMapping, Scope: RestMapping,

View File

@ -107,7 +107,7 @@ func (v *aliasView) runCmd(evt *tcell.EventKey) *tcell.EventKey {
} }
func (v *aliasView) hydrate() resource.TableData { func (v *aliasView) hydrate() resource.TableData {
cmds := make(map[string]resCmd, 40) cmds := make(map[string]*resCmd, 40)
aliasCmds(v.app.Conn(), cmds) aliasCmds(v.app.Conn(), cmds)
data := resource.TableData{ data := resource.TableData{
@ -119,7 +119,7 @@ func (v *aliasView) hydrate() resource.TableData {
for k := range cmds { for k := range cmds {
fields := resource.Row{ fields := resource.Row{
ui.Pad(k, 30), ui.Pad(k, 30),
ui.Pad(cmds[k].title, 30), ui.Pad(cmds[k].kind, 30),
ui.Pad(cmds[k].api, 30), ui.Pad(cmds[k].api, 30),
} }
data.Rows[k] = &resource.RowEvent{ data.Rows[k] = &resource.RowEvent{

View File

@ -13,6 +13,6 @@ func TestAliasView(t *testing.T) {
v.Init(nil, "") v.Init(nil, "")
assert.Equal(t, 3, len(td.Header)) assert.Equal(t, 3, len(td.Header))
assert.Equal(t, 33, len(td.Rows)) assert.Equal(t, 41, len(td.Rows))
assert.Equal(t, "Aliases", v.getTitle()) assert.Equal(t, "Aliases", v.getTitle())
} }

View File

@ -71,7 +71,7 @@ func (c *command) isStdCmd(cmd string) bool {
} }
func (c *command) isAliasCmd(cmd string) bool { func (c *command) isAliasCmd(cmd string) bool {
cmds := make(map[string]resCmd, 30) cmds := make(map[string]*resCmd, 30)
resourceViews(c.app.Conn(), cmds) resourceViews(c.app.Conn(), cmds)
res, ok := cmds[cmd] res, ok := cmds[cmd]
if !ok { if !ok {
@ -83,7 +83,7 @@ func (c *command) isAliasCmd(cmd string) bool {
r = res.listFn(c.app.Conn(), resource.DefaultNamespace) r = res.listFn(c.app.Conn(), resource.DefaultNamespace)
} }
v := res.viewFn(res.title, c.app, r) v := res.viewFn(res.kind, c.app, r)
if res.colorerFn != nil { if res.colorerFn != nil {
v.setColorerFn(res.colorerFn) v.setColorerFn(res.colorerFn)
} }
@ -94,8 +94,7 @@ func (c *command) isAliasCmd(cmd string) bool {
v.setDecorateFn(res.decorateFn) v.setDecorateFn(res.decorateFn)
} }
const fmat = "Viewing resource %s..." c.app.Flash().Infof("Viewing resource %s...", res.kind)
c.app.Flash().Infof(fmat, res.title)
log.Debug().Msgf("Running command %s", cmd) log.Debug().Msgf("Running command %s", cmd)
c.exec(cmd, v) c.exec(cmd, v)
@ -103,7 +102,7 @@ func (c *command) isAliasCmd(cmd string) bool {
} }
func (c *command) isCRDCmd(cmd string) bool { func (c *command) isCRDCmd(cmd string) bool {
crds := map[string]resCmd{} crds := map[string]*resCmd{}
allCRDs(c.app.Conn(), crds) allCRDs(c.app.Conn(), crds)
res, ok := crds[cmd] res, ok := crds[cmd]
if !ok { if !ok {
@ -115,7 +114,7 @@ func (c *command) isCRDCmd(cmd string) bool {
name = res.singular name = res.singular
} }
v := newResourceView( v := newResourceView(
res.title, res.kind,
c.app, c.app,
resource.NewCustomList(c.app.Conn(), "", res.api, res.version, name), resource.NewCustomList(c.app.Conn(), "", res.api, res.version, name),
) )

View File

@ -26,23 +26,49 @@ type (
resCmd struct { resCmd struct {
crdCmd crdCmd
title string kind string
viewFn viewFn viewFn viewFn
listFn listFn listFn listFn
enterFn enterFn enterFn enterFn
colorerFn ui.ColorerFunc colorerFn ui.ColorerFunc
decorateFn decorateFn decorateFn decorateFn
} }
AliasConfig struct {
Aliases map[string]string `yaml:"aliases"`
}
) )
func aliasCmds(c k8s.Connection, m map[string]resCmd) { var DefaultAliasConfig = AliasConfig{
Aliases: map[string]string{
"Deployment": "dp",
"Secret": "sec",
"Jobs": "jo",
"ClusterRoles": "cr",
"ClusterRoleBindings": "crb",
"RoleBindings": "rb",
"Roles": "ro",
"NetworkPolicies": "np",
"Contexts": "ctx",
"Users": "usr",
"Groups": "grp",
"PortForward": "pf",
"Benchmark": "be",
"ScreenDumps": "sd",
},
}
func aliasCmds(c k8s.Connection, m map[string]*resCmd) {
resourceViews(c, m) resourceViews(c, m)
if c != nil { if c != nil {
allCRDs(c, m) allCRDs(c, m)
} }
} }
func allCRDs(c k8s.Connection, m map[string]resCmd) { func allCRDs(c k8s.Connection, m map[string]*resCmd) {
crds, _ := resource.NewCustomResourceDefinitionList(c, resource.AllNamespaces). crds, _ := resource.NewCustomResourceDefinitionList(c, resource.AllNamespaces).
Resource(). Resource().
List(resource.AllNamespaces) List(resource.AllNamespaces)
@ -59,7 +85,7 @@ func allCRDs(c k8s.Connection, m map[string]resCmd) {
} }
res := resCmd{ res := resCmd{
title: grp.Kind, kind: grp.Kind,
crdCmd: crdCmd{ crdCmd: crdCmd{
api: grp.Group, api: grp.Group,
version: grp.Version, version: grp.Version,
@ -67,17 +93,17 @@ func allCRDs(c k8s.Connection, m map[string]resCmd) {
} }
if p, ok := ff["plural"].(string); ok { if p, ok := ff["plural"].(string); ok {
res.plural = p res.plural = p
m[p] = res m[p] = &res
} }
if s, ok := ff["singular"].(string); ok { if s, ok := ff["singular"].(string); ok {
res.singular = s res.singular = s
m[s] = res m[s] = &res
} }
if aa, ok := ff["aliases"].([]interface{}); ok { if aa, ok := ff["aliases"].([]interface{}); ok {
for _, a := range aa { for _, a := range aa {
m[a.(string)] = res m[a.(string)] = &res
} }
} }
} }
@ -122,372 +148,378 @@ func showSAPolicy(app *appView, _, _, selection string) {
app.inject(newPolicyView(app, mapFuSubject("ServiceAccount"), n)) app.inject(newPolicyView(app, mapFuSubject("ServiceAccount"), n))
} }
func resourceViews(c k8s.Connection, m map[string]resCmd) { func collect(commandList ...[]*resCmd) (accum []*resCmd) {
primRes(m) for _, commands := range commandList {
coreRes(m) accum = append(accum, commands...)
stateRes(m) }
rbacRes(m) return
apiExtRes(m) }
batchRes(m)
appsRes(m) func resourceViews(c k8s.Connection, cmdMap map[string]*resCmd) {
extRes(m) commands := collect(
v1beta1Res(m) primRes(), coreRes(), stateRes(), rbacRes(), apiExtRes(),
custRes(m) batchRes(), appsRes(), extRes(), v1beta1Res(), custRes(),
)
if c != nil { if c != nil {
hpaRes(c, m) commands = append(commands, hpaRes(c)...)
}
for _, rsc := range commands {
cmdMap[strings.ToLower(rsc.kind)] = rsc
}
// Add default aliases
// TODO: read aliases from a config file.
for rsc, alias := range DefaultAliasConfig.Aliases {
if cmd, ok := cmdMap[strings.ToLower(rsc)]; ok {
addAlias(cmdMap, cmd, alias)
}
}
if c != nil {
discoverAliasesFromServer(c, cmdMap)
} }
} }
func stateRes(m map[string]resCmd) { func addAlias(cmdMap map[string]*resCmd, cmd *resCmd, alias string) {
m["cm"] = resCmd{ if alias == "" {
title: "ConfigMaps", return
crdCmd: crdCmd{
api: "",
},
viewFn: newResourceView,
listFn: resource.NewConfigMapList,
} }
m["pv"] = resCmd{
title: "PersistentVolumes", alias = strings.ToLower(alias)
crdCmd: crdCmd{ if _, ok := cmdMap[alias]; !ok {
api: "", cmdMap[alias] = cmd
},
viewFn: newResourceView,
listFn: resource.NewPersistentVolumeList,
colorerFn: pvColorer,
}
m["pvc"] = resCmd{
title: "PersistentVolumeClaims",
crdCmd: crdCmd{
api: "",
},
viewFn: newResourceView,
listFn: resource.NewPersistentVolumeClaimList,
colorerFn: pvcColorer,
}
m["sec"] = resCmd{
title: "Secrets",
crdCmd: crdCmd{
api: "",
},
viewFn: newSecretView,
listFn: resource.NewSecretList,
}
m["sc"] = resCmd{
title: "StorageClasses",
crdCmd: crdCmd{
api: "storage.k8s.io",
},
viewFn: newResourceView,
listFn: resource.NewStorageClassList,
} }
} }
func primRes(m map[string]resCmd) { func addAPIResourceAliases(cmds map[string]*resCmd, resource metav1.APIResource) {
m["no"] = resCmd{ if strings.Contains(resource.Name, "/") {
title: "Nodes", // Ignore resources that has slash, e.g.,
crdCmd: crdCmd{ // deployment/status, namespace/finalizers and etc.
api: "", return
},
viewFn: newNodeView,
listFn: resource.NewNodeList,
colorerFn: nsColorer,
} }
m["ns"] = resCmd{
title: "Namespaces", if cmd, ok := cmds[strings.ToLower(resource.Kind)]; ok {
crdCmd: crdCmd{ addAlias(cmds, cmd, resource.Name)
api: "", addAlias(cmds, cmd, resource.SingularName)
}, for _, sn := range resource.ShortNames {
viewFn: newNamespaceView, addAlias(cmds, cmd, sn)
listFn: resource.NewNamespaceList, }
colorerFn: nsColorer,
}
m["po"] = resCmd{
title: "Pods",
crdCmd: crdCmd{
api: "",
},
viewFn: newPodView,
listFn: resource.NewPodList,
colorerFn: podColorer,
}
m["sa"] = resCmd{
title: "ServiceAccounts",
crdCmd: crdCmd{
api: "",
},
viewFn: newResourceView,
listFn: resource.NewServiceAccountList,
enterFn: showSAPolicy,
}
m["svc"] = resCmd{
title: "Services",
crdCmd: crdCmd{
api: "",
},
viewFn: newSvcView,
listFn: resource.NewServiceList,
} }
} }
func coreRes(m map[string]resCmd) { func discoverAliasesFromServer(con k8s.Connection, cmds map[string]*resCmd) {
m["ctx"] = resCmd{ _, resourceLists, _ := con.DialOrDie().Discovery().ServerGroupsAndResources()
title: "Contexts", for _, resourceList := range resourceLists {
crdCmd: crdCmd{ for _, resource := range resourceList.APIResources {
api: "", addAPIResourceAliases(cmds, resource)
}, }
viewFn: newContextView,
listFn: resource.NewContextList,
colorerFn: ctxColorer,
}
m["ds"] = resCmd{
title: "DaemonSets",
crdCmd: crdCmd{
api: "",
},
viewFn: newDaemonSetView,
listFn: resource.NewDaemonSetList,
colorerFn: dpColorer,
}
m["ep"] = resCmd{
title: "EndPoints",
crdCmd: crdCmd{
api: "",
},
viewFn: newResourceView,
listFn: resource.NewEndpointsList,
}
m["ev"] = resCmd{
title: "Events",
crdCmd: crdCmd{
api: "",
},
viewFn: newResourceView,
listFn: resource.NewEventList,
colorerFn: evColorer,
}
m["rc"] = resCmd{
title: "ReplicationControllers",
crdCmd: crdCmd{
api: "",
},
viewFn: newScalableResourceView,
listFn: resource.NewReplicationControllerList,
colorerFn: rsColorer,
} }
} }
func custRes(m map[string]resCmd) { func stateRes() []*resCmd {
m["usr"] = resCmd{ return []*resCmd{
title: "Users", {
crdCmd: crdCmd{ kind: "ConfigMap",
api: "", viewFn: newResourceView,
listFn: resource.NewConfigMapList,
}, },
viewFn: newSubjectView, {
} kind: "PersistentVolume",
m["grp"] = resCmd{ viewFn: newResourceView,
title: "Groups", listFn: resource.NewPersistentVolumeList,
crdCmd: crdCmd{ colorerFn: pvColorer,
api: "",
}, },
viewFn: newSubjectView, {
} kind: "PersistentVolumeClaim",
m["pf"] = resCmd{ viewFn: newResourceView,
title: "PortForward", listFn: resource.NewPersistentVolumeClaimList,
crdCmd: crdCmd{ colorerFn: pvcColorer,
api: "",
}, },
viewFn: newForwardView, {
} kind: "Secret",
m["be"] = resCmd{ viewFn: newSecretView,
title: "Benchmark", listFn: resource.NewSecretList,
crdCmd: crdCmd{
api: "",
}, },
viewFn: newBenchView, {
} kind: "StorageClass",
m["sd"] = resCmd{ crdCmd: crdCmd{
title: "ScreenDumps", api: "storage.k8s.io",
crdCmd: crdCmd{ },
api: "", viewFn: newResourceView,
listFn: resource.NewStorageClassList,
}, },
viewFn: newDumpView,
} }
} }
func rbacRes(m map[string]resCmd) { func primRes() []*resCmd {
m["cr"] = resCmd{ return []*resCmd{
title: "ClusterRoles", {
crdCmd: crdCmd{ kind: "Node",
api: "rbac.authorization.k8s.io", viewFn: newNodeView,
listFn: resource.NewNodeList,
colorerFn: nsColorer,
}, },
viewFn: newResourceView, {
listFn: resource.NewClusterRoleList, kind: "Namespace",
enterFn: showRBAC, viewFn: newNamespaceView,
} listFn: resource.NewNamespaceList,
m["crb"] = resCmd{ colorerFn: nsColorer,
title: "ClusterRoleBindings",
crdCmd: crdCmd{
api: "rbac.authorization.k8s.io",
}, },
viewFn: newResourceView, {
listFn: resource.NewClusterRoleBindingList, kind: "Pod",
enterFn: showClusterRole, viewFn: newPodView,
} listFn: resource.NewPodList,
colorerFn: podColorer,
m["rb"] = resCmd{
title: "RoleBindings",
crdCmd: crdCmd{
api: "rbac.authorization.k8s.io",
}, },
viewFn: newResourceView, {
listFn: resource.NewRoleBindingList, kind: "ServiceAccount",
enterFn: showRole, viewFn: newResourceView,
} listFn: resource.NewServiceAccountList,
m["ro"] = resCmd{ enterFn: showSAPolicy,
title: "Roles", },
crdCmd: crdCmd{ {
api: "rbac.authorization.k8s.io", kind: "Service",
viewFn: newSvcView,
listFn: resource.NewServiceList,
}, },
viewFn: newResourceView,
listFn: resource.NewRoleList,
enterFn: showRBAC,
} }
} }
func apiExtRes(m map[string]resCmd) { func coreRes() []*resCmd {
m["crd"] = resCmd{ return []*resCmd{
title: "CustomResourceDefinitions", {
crdCmd: crdCmd{ kind: "Contexts",
api: "apiextensions.k8s.io", viewFn: newContextView,
listFn: resource.NewContextList,
colorerFn: ctxColorer,
}, },
viewFn: newResourceView, {
listFn: resource.NewCustomResourceDefinitionList, kind: "DaemonSet",
enterFn: showCRD, viewFn: newDaemonSetView,
} listFn: resource.NewDaemonSetList,
m["np"] = resCmd{ colorerFn: dpColorer,
title: "NetworkPolicies", },
crdCmd: crdCmd{ {
api: "apiextensions.k8s.io", kind: "EndPoints",
viewFn: newResourceView,
listFn: resource.NewEndpointsList,
},
{
kind: "Event",
viewFn: newResourceView,
listFn: resource.NewEventList,
colorerFn: evColorer,
},
{
kind: "ReplicationController",
viewFn: newScalableResourceView,
listFn: resource.NewReplicationControllerList,
colorerFn: rsColorer,
}, },
viewFn: newResourceView,
listFn: resource.NewNetworkPolicyList,
} }
} }
func batchRes(m map[string]resCmd) { func custRes() []*resCmd {
m["cj"] = resCmd{ return []*resCmd{
title: "CronJobs", {
crdCmd: crdCmd{ kind: "Users",
api: "batch", viewFn: newSubjectView,
},
{
kind: "Groups",
viewFn: newSubjectView,
},
{
kind: "PortForward",
viewFn: newForwardView,
},
{
kind: "Benchmark",
viewFn: newBenchView,
},
{
kind: "ScreenDumps",
viewFn: newDumpView,
}, },
viewFn: newCronJobView,
listFn: resource.NewCronJobList,
} }
m["jo"] = resCmd{
title: "Jobs", }
crdCmd: crdCmd{
api: "batch", func rbacRes() []*resCmd {
return []*resCmd{
{
kind: "ClusterRole",
crdCmd: crdCmd{
api: "rbac.authorization.k8s.io",
},
viewFn: newResourceView,
listFn: resource.NewClusterRoleList,
enterFn: showRBAC,
},
{
kind: "ClusterRoleBinding",
crdCmd: crdCmd{
api: "rbac.authorization.k8s.io",
},
viewFn: newResourceView,
listFn: resource.NewClusterRoleBindingList,
enterFn: showClusterRole,
},
{
kind: "RoleBinding",
crdCmd: crdCmd{
api: "rbac.authorization.k8s.io",
},
viewFn: newResourceView,
listFn: resource.NewRoleBindingList,
enterFn: showRole,
},
{
kind: "Role",
crdCmd: crdCmd{
api: "rbac.authorization.k8s.io",
},
viewFn: newResourceView,
listFn: resource.NewRoleList,
enterFn: showRBAC,
}, },
viewFn: newJobView,
listFn: resource.NewJobList,
} }
} }
func appsRes(m map[string]resCmd) { func apiExtRes() []*resCmd {
m["dp"] = resCmd{ return []*resCmd{
title: "Deployments", {
crdCmd: crdCmd{ kind: "CustomResourceDefinition",
api: "apps", crdCmd: crdCmd{
api: "apiextensions.k8s.io",
},
viewFn: newResourceView,
listFn: resource.NewCustomResourceDefinitionList,
enterFn: showCRD,
}, },
viewFn: newDeployView, {
listFn: resource.NewDeploymentList, kind: "NetworkPolicy",
colorerFn: dpColorer, crdCmd: crdCmd{
} api: "apiextensions.k8s.io",
m["rs"] = resCmd{ },
title: "ReplicaSets", viewFn: newResourceView,
crdCmd: crdCmd{ listFn: resource.NewNetworkPolicyList,
api: "apps",
}, },
viewFn: newReplicaSetView,
listFn: resource.NewReplicaSetList,
colorerFn: rsColorer,
}
m["sts"] = resCmd{
title: "StatefulSets",
crdCmd: crdCmd{
api: "apps",
},
viewFn: newStatefulSetView,
listFn: resource.NewStatefulSetList,
colorerFn: stsColorer,
} }
} }
func extRes(m map[string]resCmd) { func batchRes() []*resCmd {
m["ing"] = resCmd{ return []*resCmd{
title: "Ingress", {
crdCmd: crdCmd{ kind: "CronJob",
api: "extensions", crdCmd: crdCmd{
api: "batch",
},
viewFn: newCronJobView,
listFn: resource.NewCronJobList,
},
{
kind: "Job",
crdCmd: crdCmd{
api: "batch",
},
viewFn: newJobView,
listFn: resource.NewJobList,
}, },
viewFn: newResourceView,
listFn: resource.NewIngressList,
} }
} }
func v1beta1Res(m map[string]resCmd) { func appsRes() []*resCmd {
m["pdb"] = resCmd{ return []*resCmd{
title: "PodDisruptionBudgets", {
crdCmd: crdCmd{ kind: "Deployment",
api: "v1.beta1", crdCmd: crdCmd{
api: "apps",
},
viewFn: newDeployView,
listFn: resource.NewDeploymentList,
colorerFn: dpColorer,
},
{
kind: "ReplicaSet",
crdCmd: crdCmd{
api: "apps",
},
viewFn: newReplicaSetView,
listFn: resource.NewReplicaSetList,
colorerFn: rsColorer,
},
{
kind: "StatefulSet",
crdCmd: crdCmd{
api: "apps",
},
viewFn: newStatefulSetView,
listFn: resource.NewStatefulSetList,
colorerFn: stsColorer,
},
}
}
func extRes() []*resCmd {
return []*resCmd{
{
kind: "Ingress",
crdCmd: crdCmd{
api: "extensions",
},
viewFn: newResourceView,
listFn: resource.NewIngressList,
}, },
viewFn: newResourceView,
listFn: resource.NewPDBList,
colorerFn: pdbColorer,
} }
} }
func hpaRes(c k8s.Connection, cmds map[string]resCmd) { func v1beta1Res() []*resCmd {
return []*resCmd{
{
kind: "PodDisruptionBudget",
crdCmd: crdCmd{
api: "v1.beta1",
},
viewFn: newResourceView,
listFn: resource.NewPDBList,
colorerFn: pdbColorer,
},
}
}
func hpaRes(c k8s.Connection) []*resCmd {
rev, ok, err := c.SupportsRes("autoscaling", []string{"v1", "v2beta1", "v2beta2"}) rev, ok, err := c.SupportsRes("autoscaling", []string{"v1", "v2beta1", "v2beta2"})
if err != nil { if err != nil {
log.Error().Err(err).Msg("Checking HPA") log.Error().Err(err).Msg("Checking HPA")
return return nil
} }
if !ok { if !ok {
log.Error().Msg("HPA are not supported on this cluster") log.Error().Msg("HPA are not supported on this cluster")
return return nil
}
hpa := &resCmd{
kind: "HorizontalPodAutoscaler",
crdCmd: crdCmd{
api: "autoscaling",
},
viewFn: newResourceView,
} }
switch rev { switch rev {
case "v1": case "v1":
cmds["hpa"] = resCmd{ hpa.listFn = resource.NewHorizontalPodAutoscalerV1List
title: "HorizontalPodAutoscalers",
crdCmd: crdCmd{
api: "autoscaling",
},
viewFn: newResourceView,
listFn: resource.NewHorizontalPodAutoscalerV1List,
}
case "v2beta1": case "v2beta1":
cmds["hpa"] = resCmd{ hpa.listFn = resource.NewHorizontalPodAutoscalerV2Beta1List
title: "HorizontalPodAutoscalers",
crdCmd: crdCmd{
api: "autoscaling",
},
viewFn: newResourceView,
listFn: resource.NewHorizontalPodAutoscalerV2Beta1List,
}
case "v2beta2": case "v2beta2":
cmds["hpa"] = resCmd{ hpa.listFn = resource.NewHorizontalPodAutoscalerList
title: "HorizontalPodAutoscalers",
crdCmd: crdCmd{
api: "autoscaling",
},
viewFn: newResourceView,
listFn: resource.NewHorizontalPodAutoscalerList,
}
default: default:
log.Panic().Msgf("K9s unsupported HPA version. Exiting!") log.Panic().Msgf("K9s unsupported HPA version. Exiting!")
} }
return []*resCmd{hpa}
} }