Merge pull request #4811 from medyagh/add_profile_list_cmd
Add a new command (profile list)pull/4827/head
commit
9f42df6209
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
Copyright 2019 The Kubernetes Authors 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 config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"k8s.io/minikube/pkg/minikube/config"
|
||||
"k8s.io/minikube/pkg/minikube/console"
|
||||
"k8s.io/minikube/pkg/minikube/exit"
|
||||
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var profileListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "Lists all minikube profiles.",
|
||||
Long: "Lists all minikube profiles.",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
var validData [][]string
|
||||
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Profile", "VM Driver", "NodeIP", "Node Port", "Kubernetes Version"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table.SetBorders(tablewriter.Border{Left: true, Top: true, Right: true, Bottom: true})
|
||||
table.SetCenterSeparator("|")
|
||||
validProfiles, invalidProfiles, err := config.ListProfiles()
|
||||
|
||||
for _, p := range validProfiles {
|
||||
validData = append(validData, []string{p.Name, p.Config.MachineConfig.VMDriver, p.Config.KubernetesConfig.NodeIP, strconv.Itoa(p.Config.KubernetesConfig.NodePort), p.Config.KubernetesConfig.KubernetesVersion})
|
||||
}
|
||||
|
||||
table.AppendBulk(validData)
|
||||
table.Render()
|
||||
|
||||
if invalidProfiles != nil {
|
||||
console.OutT(console.WarningType, "Found {{.number}} invalid profile(s) ! ", console.Arg{"number": len(invalidProfiles)})
|
||||
for _, p := range invalidProfiles {
|
||||
console.OutT(console.Empty, "\t "+p.Name)
|
||||
}
|
||||
console.OutT(console.Tip, "You can delete them using the following command(s): ")
|
||||
for _, p := range invalidProfiles {
|
||||
console.Out(fmt.Sprintf("\t $ minikube delete -p %s \n", p.Name))
|
||||
}
|
||||
|
||||
}
|
||||
if err != nil {
|
||||
exit.WithCode(exit.Config, fmt.Sprintf("error loading profiles: %v", err))
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
ProfileCmd.AddCommand(profileListCmd)
|
||||
}
|
|
@ -109,7 +109,7 @@ func Load() (*Config, error) {
|
|||
|
||||
// Loader loads the kubernetes and machine config based on the machine profile name
|
||||
type Loader interface {
|
||||
LoadConfigFromFile(profile string) (*Config, error)
|
||||
LoadConfigFromFile(profile string, miniHome ...string) (*Config, error)
|
||||
}
|
||||
|
||||
type simpleConfigLoader struct{}
|
||||
|
@ -117,10 +117,10 @@ type simpleConfigLoader struct{}
|
|||
// DefaultLoader is the default config loader
|
||||
var DefaultLoader Loader = &simpleConfigLoader{}
|
||||
|
||||
func (c *simpleConfigLoader) LoadConfigFromFile(profile string) (*Config, error) {
|
||||
func (c *simpleConfigLoader) LoadConfigFromFile(profile string, miniHome ...string) (*Config, error) {
|
||||
var cc Config
|
||||
|
||||
path := constants.GetProfileFile(profile)
|
||||
path := constants.GetProfileFile(profile, miniHome...)
|
||||
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
return nil, err
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
Copyright 2019 The Kubernetes Authors 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 config
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
|
||||
"k8s.io/minikube/pkg/minikube/constants"
|
||||
)
|
||||
|
||||
// isValid checks if the profile has the essential info needed for a profile
|
||||
func (p *Profile) isValid() bool {
|
||||
if p.Config.MachineConfig.VMDriver == "" {
|
||||
return false
|
||||
}
|
||||
if p.Config.KubernetesConfig.KubernetesVersion == "" {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ListProfiles returns all valid and invalid (if any) minikube profiles
|
||||
// invalidPs are the profiles that have a directory or config file but not usable
|
||||
// invalidPs would be suggeted to be deleted
|
||||
func ListProfiles(miniHome ...string) (validPs []*Profile, inValidPs []*Profile, err error) {
|
||||
pDirs, err := profileDirs(miniHome...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
for _, n := range pDirs {
|
||||
p, err := loadProfile(n, miniHome...)
|
||||
if err != nil {
|
||||
inValidPs = append(inValidPs, p)
|
||||
continue
|
||||
}
|
||||
if !p.isValid() {
|
||||
inValidPs = append(inValidPs, p)
|
||||
continue
|
||||
}
|
||||
validPs = append(validPs, p)
|
||||
}
|
||||
return validPs, inValidPs, nil
|
||||
}
|
||||
|
||||
// loadProfile loads type Profile based on its name
|
||||
func loadProfile(name string, miniHome ...string) (*Profile, error) {
|
||||
cfg, err := DefaultLoader.LoadConfigFromFile(name, miniHome...)
|
||||
p := &Profile{
|
||||
Name: name,
|
||||
Config: cfg,
|
||||
}
|
||||
return p, err
|
||||
}
|
||||
|
||||
// profileDirs gets all the folders in the user's profiles folder regardless of valid or invalid config
|
||||
func profileDirs(miniHome ...string) (dirs []string, err error) {
|
||||
miniPath := constants.GetMinipath()
|
||||
if len(miniHome) > 0 {
|
||||
miniPath = miniHome[0]
|
||||
}
|
||||
pRootDir := filepath.Join(miniPath, "profiles")
|
||||
items, err := ioutil.ReadDir(pRootDir)
|
||||
for _, f := range items {
|
||||
if f.IsDir() {
|
||||
dirs = append(dirs, f.Name())
|
||||
}
|
||||
}
|
||||
return dirs, err
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
Copyright 2019 The Kubernetes Authors 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 config
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestListProfiles(t *testing.T) {
|
||||
miniDir, err := filepath.Abs("./testdata/.minikube")
|
||||
if err != nil {
|
||||
t.Errorf("error getting dir path for ./testdata/.minikube : %v", err)
|
||||
}
|
||||
// test cases for valid profiles
|
||||
var testCasesValidProfs = []struct {
|
||||
index int
|
||||
expectName string
|
||||
vmDriver string
|
||||
}{
|
||||
{0, "p1", "hyperkit"},
|
||||
{1, "p2", "virtualbox"},
|
||||
}
|
||||
|
||||
// test cases for invalid profiles
|
||||
var testCasesInValidProfs = []struct {
|
||||
index int
|
||||
expectName string
|
||||
vmDriver string
|
||||
}{
|
||||
{0, "p3_empty", ""},
|
||||
{1, "p4_invalid_file", ""},
|
||||
{2, "p5_partial_config", ""},
|
||||
}
|
||||
|
||||
val, inv, err := ListProfiles(miniDir)
|
||||
|
||||
for _, tt := range testCasesValidProfs {
|
||||
if val[tt.index].Name != tt.expectName {
|
||||
t.Errorf("expected %s got %v", tt.expectName, val[tt.index].Name)
|
||||
}
|
||||
if val[tt.index].Config.MachineConfig.VMDriver != tt.vmDriver {
|
||||
t.Errorf("expected %s got %v", tt.vmDriver, val[tt.index].Config.MachineConfig.VMDriver)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// making sure it returns the invalid profiles
|
||||
for _, tt := range testCasesInValidProfs {
|
||||
if inv[tt.index].Name != tt.expectName {
|
||||
t.Errorf("expected %s got %v", tt.expectName, inv[tt.index].Name)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("error listing profiles %v", err)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"MachineConfig": {
|
||||
"KeepContext": false,
|
||||
"MinikubeISO": "https://storage.googleapis.com/minikube/iso/minikube-v1.2.0.iso",
|
||||
"Memory": 2000,
|
||||
"CPUs": 2,
|
||||
"DiskSize": 20000,
|
||||
"VMDriver": "hyperkit",
|
||||
"ContainerRuntime": "docker",
|
||||
"HyperkitVpnKitSock": "",
|
||||
"HyperkitVSockPorts": [],
|
||||
"XhyveDiskDriver": "ahci-hd",
|
||||
"DockerEnv": null,
|
||||
"InsecureRegistry": null,
|
||||
"RegistryMirror": null,
|
||||
"HostOnlyCIDR": "192.168.99.1/24",
|
||||
"HypervVirtualSwitch": "",
|
||||
"KVMNetwork": "default",
|
||||
"KVMQemuURI": "qemu:///system",
|
||||
"KVMGPU": false,
|
||||
"KVMHidden": false,
|
||||
"DockerOpt": null,
|
||||
"DisableDriverMounts": false,
|
||||
"NFSShare": [],
|
||||
"NFSSharesRoot": "/nfsshares",
|
||||
"UUID": "",
|
||||
"NoVTXCheck": false,
|
||||
"DNSProxy": false,
|
||||
"HostDNSResolver": true
|
||||
},
|
||||
"KubernetesConfig": {
|
||||
"KubernetesVersion": "v1.15.0",
|
||||
"NodeIP": "192.168.64.75",
|
||||
"NodePort": 8443,
|
||||
"NodeName": "minikube",
|
||||
"APIServerName": "minikubeCA",
|
||||
"APIServerNames": null,
|
||||
"APIServerIPs": null,
|
||||
"DNSDomain": "cluster.local",
|
||||
"ContainerRuntime": "docker",
|
||||
"CRISocket": "",
|
||||
"NetworkPlugin": "",
|
||||
"FeatureGates": "",
|
||||
"ServiceCIDR": "10.96.0.0/12",
|
||||
"ImageRepository": "",
|
||||
"ExtraOptions": null,
|
||||
"ShouldLoadCachedImages": true,
|
||||
"EnableDefaultCNI": false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"MachineConfig": {
|
||||
"KeepContext": false,
|
||||
"MinikubeISO": "https://storage.googleapis.com/minikube/iso/minikube-v1.2.0.iso",
|
||||
"Memory": 2000,
|
||||
"CPUs": 2,
|
||||
"DiskSize": 20000,
|
||||
"VMDriver": "virtualbox",
|
||||
"ContainerRuntime": "docker",
|
||||
"HyperkitVpnKitSock": "",
|
||||
"HyperkitVSockPorts": [],
|
||||
"DockerEnv": null,
|
||||
"InsecureRegistry": null,
|
||||
"RegistryMirror": null,
|
||||
"HostOnlyCIDR": "192.168.99.1/24",
|
||||
"HypervVirtualSwitch": "",
|
||||
"KVMNetwork": "default",
|
||||
"KVMQemuURI": "qemu:///system",
|
||||
"KVMGPU": false,
|
||||
"KVMHidden": false,
|
||||
"DockerOpt": null,
|
||||
"DisableDriverMounts": false,
|
||||
"NFSShare": [],
|
||||
"NFSSharesRoot": "/nfsshares",
|
||||
"UUID": "",
|
||||
"NoVTXCheck": false,
|
||||
"DNSProxy": false,
|
||||
"HostDNSResolver": true
|
||||
},
|
||||
"KubernetesConfig": {
|
||||
"KubernetesVersion": "v1.15.0",
|
||||
"NodeIP": "192.168.99.136",
|
||||
"NodePort": 8443,
|
||||
"NodeName": "minikube",
|
||||
"APIServerName": "minikubeCA",
|
||||
"APIServerNames": null,
|
||||
"APIServerIPs": null,
|
||||
"DNSDomain": "cluster.local",
|
||||
"ContainerRuntime": "docker",
|
||||
"CRISocket": "",
|
||||
"NetworkPlugin": "",
|
||||
"FeatureGates": "",
|
||||
"ServiceCIDR": "10.96.0.0/12",
|
||||
"ImageRepository": "",
|
||||
"ExtraOptions": null,
|
||||
"ShouldLoadCachedImages": true,
|
||||
"EnableDefaultCNI": false
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
invalid json file :)
|
47
pkg/minikube/config/testdata/.minikube/profiles/p5_partial_config/config.json
vendored
Normal file
47
pkg/minikube/config/testdata/.minikube/profiles/p5_partial_config/config.json
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"MachineConfig": {
|
||||
"KeepContext": false,
|
||||
"MinikubeISO": "https://storage.googleapis.com/minikube/iso/minikube-v1.2.0.iso",
|
||||
"Memory": 2000,
|
||||
"CPUs": 2,
|
||||
"DiskSize": 20000,
|
||||
"ContainerRuntime": "docker",
|
||||
"HyperkitVpnKitSock": "",
|
||||
"HyperkitVSockPorts": [],
|
||||
"XhyveDiskDriver": "ahci-hd",
|
||||
"DockerEnv": null,
|
||||
"InsecureRegistry": null,
|
||||
"RegistryMirror": null,
|
||||
"HostOnlyCIDR": "192.168.99.1/24",
|
||||
"HypervVirtualSwitch": "",
|
||||
"KVMNetwork": "default",
|
||||
"KVMQemuURI": "qemu:///system",
|
||||
"KVMGPU": false,
|
||||
"KVMHidden": false,
|
||||
"DockerOpt": null,
|
||||
"DisableDriverMounts": false,
|
||||
"NFSShare": [],
|
||||
"NFSSharesRoot": "/nfsshares",
|
||||
"UUID": "",
|
||||
"NoVTXCheck": false,
|
||||
"DNSProxy": false,
|
||||
"HostDNSResolver": true
|
||||
},
|
||||
"KubernetesConfig": {
|
||||
"NodePort": 8443,
|
||||
"NodeName": "minikube",
|
||||
"APIServerName": "minikubeCA",
|
||||
"APIServerNames": null,
|
||||
"APIServerIPs": null,
|
||||
"DNSDomain": "cluster.local",
|
||||
"ContainerRuntime": "docker",
|
||||
"CRISocket": "",
|
||||
"NetworkPlugin": "",
|
||||
"FeatureGates": "",
|
||||
"ServiceCIDR": "10.96.0.0/12",
|
||||
"ImageRepository": "",
|
||||
"ExtraOptions": null,
|
||||
"ShouldLoadCachedImages": true,
|
||||
"EnableDefaultCNI": false
|
||||
}
|
||||
}
|
|
@ -22,6 +22,12 @@ import (
|
|||
"k8s.io/minikube/pkg/util"
|
||||
)
|
||||
|
||||
// Profile represents a minikube profile
|
||||
type Profile struct {
|
||||
Name string
|
||||
Config *Config
|
||||
}
|
||||
|
||||
// Config contains machine and k8s config
|
||||
type Config struct {
|
||||
MachineConfig MachineConfig
|
||||
|
|
|
@ -188,13 +188,21 @@ var ConfigFilePath = MakeMiniPath("config")
|
|||
var ConfigFile = MakeMiniPath("config", "config.json")
|
||||
|
||||
// GetProfileFile returns the Minikube profile config file
|
||||
func GetProfileFile(profile string) string {
|
||||
return filepath.Join(GetMinipath(), "profiles", profile, "config.json")
|
||||
func GetProfileFile(profile string, miniHome ...string) string {
|
||||
miniPath := GetMinipath()
|
||||
if len(miniHome) > 0 {
|
||||
miniPath = miniHome[0]
|
||||
}
|
||||
return filepath.Join(miniPath, "profiles", profile, "config.json")
|
||||
}
|
||||
|
||||
// GetProfilePath returns the Minikube profile path of config file
|
||||
func GetProfilePath(profile string) string {
|
||||
return filepath.Join(GetMinipath(), "profiles", profile)
|
||||
func GetProfilePath(profile string, miniHome ...string) string {
|
||||
miniPath := GetMinipath()
|
||||
if len(miniHome) > 0 {
|
||||
miniPath = miniHome[0]
|
||||
}
|
||||
return filepath.Join(miniPath, "profiles", profile)
|
||||
}
|
||||
|
||||
// AddonsPath is the default path of the addons configuration
|
||||
|
|
|
@ -86,6 +86,6 @@ type stubConfigLoader struct {
|
|||
e error
|
||||
}
|
||||
|
||||
func (l *stubConfigLoader) LoadConfigFromFile(profile string) (*config.Config, error) {
|
||||
func (l *stubConfigLoader) LoadConfigFromFile(profile string, miniHome ...string) (*config.Config, error) {
|
||||
return l.c, l.e
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ func TestFunctional(t *testing.T) {
|
|||
// This one is not parallel, and ensures the cluster comes up
|
||||
// before we run any other tests.
|
||||
t.Run("Status", testClusterStatus)
|
||||
|
||||
t.Run("ProfileList", testProfileList)
|
||||
t.Run("DNS", testClusterDNS)
|
||||
t.Run("Logs", testClusterLogs)
|
||||
t.Run("Addons", testAddons)
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
// +build integration
|
||||
|
||||
/*
|
||||
Copyright 2019 The Kubernetes Authors 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 integration
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// testProfileList tests the `minikube profile list` command
|
||||
func testProfileList(t *testing.T) {
|
||||
t.Parallel()
|
||||
profile := "minikube"
|
||||
mk := NewMinikubeRunner(t, "--wait=false")
|
||||
out := mk.RunCommand("profile list", true)
|
||||
if !strings.Contains(out, profile) {
|
||||
t.Errorf("Error , failed to read profile name (%s) in `profile list` command output : \n %q ", profile, out)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue