incus-mirror/cmd/incus/completion.go
Stéphane Graber dfb97c68cb
incus/storage_volume: Add bitmap subcommand
Signed-off-by: Stéphane Graber <stgraber@stgraber.org>
2026-07-30 00:43:33 -04:00

1429 lines
35 KiB
Go

package main
import (
"fmt"
"io/fs"
"os"
"path/filepath"
"regexp"
"strings"
"github.com/spf13/cobra"
"github.com/lxc/incus/v7/internal/instance"
"github.com/lxc/incus/v7/shared/api"
)
func (g *cmdGlobal) cmpClusterGroupNames(toComplete string) ([]string, cobra.ShellCompDirective) {
var results []string
cmpDirectives := cobra.ShellCompDirectiveNoFileComp
resources, _ := g.parseServers(toComplete)
if len(resources) <= 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
cluster, _, err := resource.server.GetCluster()
if err != nil || !cluster.Enabled {
return nil, cobra.ShellCompDirectiveError
}
results, err = resource.server.GetClusterGroupNames()
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
return results, cmpDirectives
}
func (g *cmdGlobal) cmpClusterGroups(toComplete string) ([]string, cobra.ShellCompDirective) {
results := []string{}
cmpDirectives := cobra.ShellCompDirectiveNoFileComp
resources, _ := g.parseServers(toComplete)
if len(resources) <= 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
cluster, _, err := resource.server.GetCluster()
if err != nil || !cluster.Enabled {
return nil, cobra.ShellCompDirectiveError
}
groups, err := resource.server.GetClusterGroupNames()
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
for _, group := range groups {
var name string
if resource.remote == g.conf.DefaultRemote && !strings.Contains(toComplete, g.conf.DefaultRemote) {
name = group
} else {
name = fmt.Sprintf("%s:%s", resource.remote, group)
}
results = append(results, name)
}
if !strings.Contains(toComplete, ":") {
remotes, directives := g.cmpRemotes(toComplete, false)
results = append(results, remotes...)
cmpDirectives |= directives
}
return results, cmpDirectives
}
func (g *cmdGlobal) cmpClusterGroupConfigs(groupName string) ([]string, cobra.ShellCompDirective) {
// Parse remote
resources, err := g.parseServers(groupName)
if err != nil || len(resources) == 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
client := resource.server
cluster, _, err := client.GetCluster()
if err != nil || !cluster.Enabled {
return nil, cobra.ShellCompDirectiveError
}
group, _, err := client.GetClusterGroup(groupName)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
var results []string
for k := range group.Config {
results = append(results, k)
}
return results, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpClusterMemberConfigs(memberName string) ([]string, cobra.ShellCompDirective) {
// Parse remote
resources, err := g.parseServers(memberName)
if err != nil || len(resources) == 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
client := resource.server
cluster, _, err := client.GetCluster()
if err != nil || !cluster.Enabled {
return nil, cobra.ShellCompDirectiveError
}
member, _, err := client.GetClusterMember(memberName)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
var results []string
for k := range member.Config {
results = append(results, k)
}
return results, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpClusterMemberRoles(memberName string) ([]string, cobra.ShellCompDirective) {
// Parse remote
resources, err := g.parseServers(memberName)
if err != nil || len(resources) == 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
client := resource.server
cluster, _, err := client.GetCluster()
if err != nil || !cluster.Enabled {
return nil, cobra.ShellCompDirectiveError
}
member, _, err := client.GetClusterMember(memberName)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
return member.Roles, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpClusterMembers(toComplete string) ([]string, cobra.ShellCompDirective) {
results := []string{}
cmpDirectives := cobra.ShellCompDirectiveNoFileComp
resources, _ := g.parseServers(toComplete)
if len(resources) > 0 {
resource := resources[0]
cluster, _, err := resource.server.GetCluster()
if err != nil || !cluster.Enabled {
return nil, cobra.ShellCompDirectiveError
}
// Get the cluster members
members, err := resource.server.GetClusterMembers()
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
for _, member := range members {
var name string
if resource.remote == g.conf.DefaultRemote && !strings.Contains(toComplete, g.conf.DefaultRemote) {
name = member.ServerName
} else {
name = fmt.Sprintf("%s:%s", resource.remote, member.ServerName)
}
results = append(results, name)
}
}
if !strings.Contains(toComplete, ":") {
remotes, directives := g.cmpRemotes(toComplete, false)
results = append(results, remotes...)
cmpDirectives |= directives
}
return results, cmpDirectives
}
func (g *cmdGlobal) cmpImages(toComplete string) ([]string, cobra.ShellCompDirective) {
results := []string{}
var remote string
cmpDirectives := cobra.ShellCompDirectiveNoFileComp
if strings.Contains(toComplete, ":") {
remote = strings.Split(toComplete, ":")[0]
} else {
remote = g.conf.DefaultRemote
}
remoteServer, _ := g.conf.GetImageServer(remote)
images, _ := remoteServer.GetImages()
for _, image := range images {
for _, alias := range image.Aliases {
var name string
if remote == g.conf.DefaultRemote && !strings.Contains(toComplete, g.conf.DefaultRemote) {
name = alias.Name
} else {
name = fmt.Sprintf("%s:%s", remote, alias.Name)
}
results = append(results, name)
}
}
if !strings.Contains(toComplete, ":") {
remotes, directives := g.cmpRemotes(toComplete, true)
results = append(results, remotes...)
cmpDirectives |= directives
}
return results, cmpDirectives
}
func (g *cmdGlobal) cmpImageFingerprintsFromRemote(toComplete string, remote string) ([]string, cobra.ShellCompDirective) {
results := []string{}
if remote == "" {
remote = g.conf.DefaultRemote
}
remoteServer, _ := g.conf.GetImageServer(remote)
images, _ := remoteServer.GetImages()
for _, image := range images {
if !strings.HasPrefix(image.Fingerprint, toComplete) {
continue
}
results = append(results, image.Fingerprint)
}
return results, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpInstanceAllKeys() ([]string, cobra.ShellCompDirective) {
keys := []string{}
for k := range instance.InstanceConfigKeysAny {
keys = append(keys, k)
}
for k := range instance.InstanceConfigKeysContainer {
keys = append(keys, k)
}
for k := range instance.InstanceConfigKeysVM {
keys = append(keys, k)
}
return keys, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpInstanceConfigTemplates(instanceName string) ([]string, cobra.ShellCompDirective) {
// Parse remote
resources, err := g.parseServers(instanceName)
if err != nil || len(resources) == 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
client := resource.server
instanceNameOnly := instanceName
if strings.Contains(instanceName, ":") {
instanceNameOnly = strings.Split(instanceName, ":")[1]
}
results, err := client.GetInstanceTemplateFiles(instanceNameOnly)
if err != nil {
cobra.CompDebug(fmt.Sprintf("%v", err), true)
return nil, cobra.ShellCompDirectiveError
}
return results, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpInstanceDeviceNames(instanceName string) ([]string, cobra.ShellCompDirective) {
// Parse remote
resources, err := g.parseServers(instanceName)
if err != nil || len(resources) == 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
client := resource.server
instanceNameOnly, _, err := client.GetInstance(instanceName)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
var results []string
for k := range instanceNameOnly.Devices {
results = append(results, k)
}
return results, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpInstanceSnapshots(instanceName string) ([]string, cobra.ShellCompDirective) {
resources, err := g.parseServers(instanceName)
if err != nil || len(resources) == 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
client := resource.server
snapshots, err := client.GetInstanceSnapshotNames(instanceName)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
return snapshots, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpInstances(toComplete string) ([]string, cobra.ShellCompDirective) {
results := []string{}
cmpDirectives := cobra.ShellCompDirectiveNoFileComp
resources, _ := g.parseServers(toComplete)
if len(resources) > 0 {
resource := resources[0]
instances, _ := resource.server.GetInstanceNames(api.InstanceTypeAny)
for _, instName := range instances {
var name string
if resource.remote == g.conf.DefaultRemote && !strings.Contains(toComplete, g.conf.DefaultRemote) {
name = instName
} else {
name = fmt.Sprintf("%s:%s", resource.remote, instName)
}
if !strings.HasPrefix(name, toComplete) {
continue
}
results = append(results, name)
}
}
if !strings.Contains(toComplete, ":") {
remotes, directives := g.cmpRemotes(toComplete, false)
results = append(results, remotes...)
cmpDirectives |= directives
}
return results, cmpDirectives
}
func (g *cmdGlobal) cmpInstancesAndSnapshots(toComplete string) ([]string, cobra.ShellCompDirective) {
results := []string{}
cmpDirectives := cobra.ShellCompDirectiveNoFileComp
resources, _ := g.parseServers(toComplete)
if len(resources) > 0 {
resource := resources[0]
if strings.Contains(resource.name, instance.SnapshotDelimiter) {
instName, _, _ := strings.Cut(resource.name, instance.SnapshotDelimiter)
snapshots, _ := resource.server.GetInstanceSnapshotNames(instName)
for _, snapshot := range snapshots {
results = append(results, fmt.Sprintf("%s/%s", instName, snapshot))
}
} else {
instances, _ := resource.server.GetInstanceNames(api.InstanceTypeAny)
for _, instName := range instances {
var name string
if resource.remote == g.conf.DefaultRemote && !strings.Contains(toComplete, g.conf.DefaultRemote) {
name = instName
} else {
name = fmt.Sprintf("%s:%s", resource.remote, instName)
}
results = append(results, name)
}
}
}
if !strings.Contains(toComplete, ":") {
remotes, directives := g.cmpRemotes(toComplete, false)
results = append(results, remotes...)
cmpDirectives |= directives
}
return results, cmpDirectives
}
func (g *cmdGlobal) cmpInstanceNamesFromRemote(toComplete string) ([]string, cobra.ShellCompDirective) {
results := []string{}
resources, _ := g.parseServers(toComplete)
if len(resources) > 0 {
resource := resources[0]
containers, _ := resource.server.GetInstanceNames("container")
results = append(results, containers...)
vms, _ := resource.server.GetInstanceNames("virtual-machine")
results = append(results, vms...)
}
return results, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpNetworkACLConfigs(aclName string) ([]string, cobra.ShellCompDirective) {
// Parse remote
resources, err := g.parseServers(aclName)
if err != nil || len(resources) == 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
client := resource.server
acl, _, err := client.GetNetworkACL(resource.name)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
var results []string
for k := range acl.Config {
results = append(results, k)
}
return results, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpNetworkACLs(toComplete string) ([]string, cobra.ShellCompDirective) {
results := []string{}
cmpDirectives := cobra.ShellCompDirectiveNoFileComp
resources, _ := g.parseServers(toComplete)
if len(resources) <= 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
acls, err := resource.server.GetNetworkACLNames()
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
for _, acl := range acls {
var name string
if resource.remote == g.conf.DefaultRemote && !strings.Contains(toComplete, g.conf.DefaultRemote) {
name = acl
} else {
name = fmt.Sprintf("%s:%s", resource.remote, acl)
}
results = append(results, name)
}
if !strings.Contains(toComplete, ":") {
remotes, directives := g.cmpRemotes(toComplete, false)
results = append(results, remotes...)
cmpDirectives |= directives
}
return results, cmpDirectives
}
func (g *cmdGlobal) cmpNetworkACLRuleProperties() ([]string, cobra.ShellCompDirective) {
var results []string
allowedKeys := networkACLRuleJSONStructFieldMap()
for key := range allowedKeys {
results = append(results, fmt.Sprintf("%s=", key))
}
return results, cobra.ShellCompDirectiveNoSpace
}
func (g *cmdGlobal) cmpNetworkAddressSets(toComplete string) ([]string, cobra.ShellCompDirective) {
results := []string{}
cmpDirectives := cobra.ShellCompDirectiveNoFileComp
resources, _ := g.parseServers(toComplete)
if len(resources) <= 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
// Get the network address set names from the server.
addrSets, err := resource.server.GetNetworkAddressSetNames()
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
for _, addrSet := range addrSets {
var name string
if resource.remote == g.conf.DefaultRemote && !strings.Contains(toComplete, g.conf.DefaultRemote) {
name = addrSet
} else {
name = fmt.Sprintf("%s:%s", resource.remote, addrSet)
}
results = append(results, name)
}
// Also suggest remotes if no ":" in toComplete.
if !strings.Contains(toComplete, ":") {
remotes, directives := g.cmpRemotes(toComplete, false)
results = append(results, remotes...)
cmpDirectives |= directives
}
return results, cmpDirectives
}
func (g *cmdGlobal) cmpNetworkAddressSetConfigs(addressSetName string) ([]string, cobra.ShellCompDirective) {
// Parse remote
resources, err := g.parseServers(addressSetName)
if err != nil || len(resources) == 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
client := resource.server
// Get the network address set.
addrSet, _, err := client.GetNetworkAddressSet(resource.name)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
var results []string
for k := range addrSet.Config {
results = append(results, k)
}
return results, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpNetworkForwardConfigs(networkName string, listenAddress string) ([]string, cobra.ShellCompDirective) {
// Parse remote
resources, err := g.parseServers(networkName)
if err != nil || len(resources) == 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
client := resource.server
forward, _, err := client.GetNetworkForward(networkName, listenAddress)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
var results []string
for k := range forward.Config {
results = append(results, k)
}
return results, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpNetworkForwards(networkName string) ([]string, cobra.ShellCompDirective) {
cmpDirectives := cobra.ShellCompDirectiveNoFileComp
resources, _ := g.parseServers(networkName)
if len(resources) <= 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
results, err := resource.server.GetNetworkForwardAddresses(networkName)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
return results, cmpDirectives
}
func (g *cmdGlobal) cmpNetworkLoadBalancers(networkName string) ([]string, cobra.ShellCompDirective) {
cmpDirectives := cobra.ShellCompDirectiveNoFileComp
resources, _ := g.parseServers(networkName)
if len(resources) <= 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
results, err := resource.server.GetNetworkForwardAddresses(networkName)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
return results, cmpDirectives
}
func (g *cmdGlobal) cmpNetworkPeerConfigs(networkName string, peerName string) ([]string, cobra.ShellCompDirective) {
results := []string{}
cmpDirectives := cobra.ShellCompDirectiveNoFileComp
resources, _ := g.parseServers(networkName)
if len(resources) <= 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
peer, _, err := resource.server.GetNetworkPeer(resource.name, peerName)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
for k := range peer.Config {
results = append(results, k)
}
return results, cmpDirectives
}
func (g *cmdGlobal) cmpNetworkPeers(networkName string) ([]string, cobra.ShellCompDirective) {
cmpDirectives := cobra.ShellCompDirectiveNoFileComp
resources, _ := g.parseServers(networkName)
if len(resources) <= 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
results, err := resource.server.GetNetworkPeerNames(networkName)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
return results, cmpDirectives
}
func (g *cmdGlobal) cmpNetworks(toComplete string) ([]string, cobra.ShellCompDirective) {
results := []string{}
cmpDirectives := cobra.ShellCompDirectiveNoFileComp
resources, _ := g.parseServers(toComplete)
if len(resources) > 0 {
resource := resources[0]
networks, err := resource.server.GetNetworkNames()
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
for _, network := range networks {
var name string
if resource.remote == g.conf.DefaultRemote && !strings.Contains(toComplete, g.conf.DefaultRemote) {
name = network
} else {
name = fmt.Sprintf("%s:%s", resource.remote, network)
}
results = append(results, name)
}
}
if !strings.Contains(toComplete, ":") {
remotes, directives := g.cmpRemotes(toComplete, false)
results = append(results, remotes...)
cmpDirectives |= directives
}
return results, cmpDirectives
}
func (g *cmdGlobal) cmpNetworkConfigs(networkName string) ([]string, cobra.ShellCompDirective) {
// Parse remote
resources, err := g.parseServers(networkName)
if err != nil || len(resources) == 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
client := resource.server
network, _, err := client.GetNetwork(networkName)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
var results []string
for k := range network.Config {
results = append(results, k)
}
return results, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpNetworkInstances(networkName string) ([]string, cobra.ShellCompDirective) {
// Parse remote
resources, err := g.parseServers(networkName)
if err != nil || len(resources) == 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
client := resource.server
network, _, err := client.GetNetwork(networkName)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
var results []string
for _, i := range network.UsedBy {
r := regexp.MustCompile(`/1.0/instances/(.*)`)
match := r.FindStringSubmatch(i)
if len(match) == 2 {
results = append(results, match[1])
}
}
return results, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpNetworkProfiles(networkName string) ([]string, cobra.ShellCompDirective) {
// Parse remote
resources, err := g.parseServers(networkName)
if err != nil || len(resources) == 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
client := resource.server
network, _, err := client.GetNetwork(networkName)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
var results []string
for _, i := range network.UsedBy {
r := regexp.MustCompile(`/1.0/profiles/(.*)`)
match := r.FindStringSubmatch(i)
if len(match) == 2 {
results = append(results, match[1])
}
}
return results, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpNetworkZoneConfigs(zoneName string) ([]string, cobra.ShellCompDirective) {
// Parse remote
resources, err := g.parseServers(zoneName)
if err != nil || len(resources) == 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
client := resource.server
zone, _, err := client.GetNetworkZone(zoneName)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
var results []string
for k := range zone.Config {
results = append(results, k)
}
return results, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpNetworkZoneRecordConfigs(zoneName string, recordName string) ([]string, cobra.ShellCompDirective) {
results := []string{}
cmpDirectives := cobra.ShellCompDirectiveNoFileComp
resources, _ := g.parseServers(zoneName)
if len(resources) <= 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
peer, _, err := resource.server.GetNetworkZoneRecord(resource.name, recordName)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
for k := range peer.Config {
results = append(results, k)
}
return results, cmpDirectives
}
func (g *cmdGlobal) cmpNetworkZoneRecords(zoneName string) ([]string, cobra.ShellCompDirective) {
cmpDirectives := cobra.ShellCompDirectiveNoFileComp
resources, _ := g.parseServers(zoneName)
if len(resources) <= 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
results, err := resource.server.GetNetworkZoneRecordNames(zoneName)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
return results, cmpDirectives
}
func (g *cmdGlobal) cmpNetworkZones(toComplete string) ([]string, cobra.ShellCompDirective) {
results := []string{}
cmpDirectives := cobra.ShellCompDirectiveNoFileComp
resources, _ := g.parseServers(toComplete)
if len(resources) > 0 {
resource := resources[0]
zones, err := resource.server.GetNetworkZoneNames()
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
for _, project := range zones {
var name string
if resource.remote == g.conf.DefaultRemote && !strings.Contains(toComplete, g.conf.DefaultRemote) {
name = project
} else {
name = fmt.Sprintf("%s:%s", resource.remote, project)
}
results = append(results, name)
}
}
if !strings.Contains(toComplete, ":") {
remotes, directives := g.cmpRemotes(toComplete, false)
results = append(results, remotes...)
cmpDirectives |= directives
}
return results, cmpDirectives
}
func (g *cmdGlobal) cmpProfileConfigs(profileName string) ([]string, cobra.ShellCompDirective) {
resources, err := g.parseServers(profileName)
if err != nil || len(resources) == 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
client := resource.server
profile, _, err := client.GetProfile(resource.name)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
var configs []string
for c := range profile.Config {
configs = append(configs, c)
}
return configs, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpProfileDeviceNames(instanceName string) ([]string, cobra.ShellCompDirective) {
// Parse remote
resources, err := g.parseServers(instanceName)
if err != nil || len(resources) == 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
client := resource.server
profile, _, err := client.GetProfile(resource.name)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
var results []string
for k := range profile.Devices {
results = append(results, k)
}
return results, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpProfileNamesFromRemote(toComplete string) ([]string, cobra.ShellCompDirective) {
results := []string{}
resources, _ := g.parseServers(toComplete)
if len(resources) > 0 {
resource := resources[0]
profiles, _ := resource.server.GetProfileNames()
results = append(results, profiles...)
}
return results, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpProfiles(toComplete string, includeRemotes bool) ([]string, cobra.ShellCompDirective) {
results := []string{}
cmpDirectives := cobra.ShellCompDirectiveNoFileComp
resources, _ := g.parseServers(toComplete)
if len(resources) > 0 {
resource := resources[0]
profiles, _ := resource.server.GetProfileNames()
for _, profile := range profiles {
var name string
if resource.remote == g.conf.DefaultRemote && !strings.Contains(toComplete, g.conf.DefaultRemote) {
name = profile
} else {
name = fmt.Sprintf("%s:%s", resource.remote, profile)
}
results = append(results, name)
}
}
if includeRemotes && !strings.Contains(toComplete, ":") {
remotes, directives := g.cmpRemotes(toComplete, false)
results = append(results, remotes...)
cmpDirectives |= directives
}
return results, cmpDirectives
}
func (g *cmdGlobal) cmpProjectConfigs(projectName string) ([]string, cobra.ShellCompDirective) {
resources, err := g.parseServers(projectName)
if err != nil || len(resources) == 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
client := resource.server
project, _, err := client.GetProject(resource.name)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
var configs []string
for c := range project.Config {
configs = append(configs, c)
}
return configs, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpProjects(toComplete string) ([]string, cobra.ShellCompDirective) {
results := []string{}
cmpDirectives := cobra.ShellCompDirectiveNoFileComp
resources, _ := g.parseServers(toComplete)
if len(resources) > 0 {
resource := resources[0]
projects, err := resource.server.GetProjectNames()
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
for _, project := range projects {
var name string
if resource.remote == g.conf.DefaultRemote && !strings.Contains(toComplete, g.conf.DefaultRemote) {
name = project
} else {
name = fmt.Sprintf("%s:%s", resource.remote, project)
}
results = append(results, name)
}
}
if !strings.Contains(toComplete, ":") {
remotes, directives := g.cmpRemotes(toComplete, false)
results = append(results, remotes...)
cmpDirectives |= directives
}
return results, cmpDirectives
}
func (g *cmdGlobal) cmpRemotes(toComplete string, includeAll bool) ([]string, cobra.ShellCompDirective) {
results := []string{}
for remoteName, rc := range g.conf.Remotes {
if !includeAll && rc.Protocol != "incus" && rc.Protocol != "" {
continue
}
if !strings.HasPrefix(remoteName, toComplete) {
continue
}
results = append(results, fmt.Sprintf("%s:", remoteName))
}
if len(results) > 0 {
return results, cobra.ShellCompDirectiveNoSpace
}
return results, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpRemoteNames() ([]string, cobra.ShellCompDirective) {
results := []string{}
for remoteName := range g.conf.Remotes {
results = append(results, remoteName)
}
return results, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpStoragePoolConfigs(poolName string) ([]string, cobra.ShellCompDirective) {
// Parse remote
resources, err := g.parseServers(poolName)
if err != nil || len(resources) == 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
client := resource.server
if strings.Contains(poolName, ":") {
poolName = strings.Split(poolName, ":")[1]
}
pool, _, err := client.GetStoragePool(poolName)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
var results []string
for k := range pool.Config {
results = append(results, k)
}
return results, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpStoragePoolWithVolume(toComplete string) ([]string, cobra.ShellCompDirective) {
if !strings.Contains(toComplete, "/") {
pools, compdir := g.cmpStoragePools(toComplete)
if compdir == cobra.ShellCompDirectiveError {
return nil, compdir
}
results := []string{}
for _, pool := range pools {
if strings.HasSuffix(pool, ":") {
results = append(results, pool)
} else {
results = append(results, fmt.Sprintf("%s/", pool))
}
}
return results, cobra.ShellCompDirectiveNoSpace
}
pool, _, _ := strings.Cut(toComplete, "/")
volumes, compdir := g.cmpStoragePoolVolumes(pool)
if compdir == cobra.ShellCompDirectiveError {
return nil, compdir
}
results := []string{}
for _, volume := range volumes {
results = append(results, fmt.Sprintf("%s/%s", pool, volume))
}
return results, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpStoragePools(toComplete string) ([]string, cobra.ShellCompDirective) {
results := []string{}
resources, _ := g.parseServers(toComplete)
if len(resources) > 0 {
resource := resources[0]
storagePools, _ := resource.server.GetStoragePoolNames()
for _, storage := range storagePools {
var name string
if resource.remote == g.conf.DefaultRemote && !strings.Contains(toComplete, g.conf.DefaultRemote) {
name = storage
} else {
name = fmt.Sprintf("%s:%s", resource.remote, storage)
}
results = append(results, name)
}
}
if !strings.Contains(toComplete, ":") {
remotes, _ := g.cmpRemotes(toComplete, false)
results = append(results, remotes...)
}
return results, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpStoragePoolVolumeConfigs(poolName string, volumeName string) ([]string, cobra.ShellCompDirective) {
// Parse remote
resources, err := g.parseServers(poolName)
if err != nil || len(resources) == 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
client := resource.server
pool := poolName
if strings.Contains(poolName, ":") {
pool = strings.Split(poolName, ":")[1]
}
volName, volType := parseVolume("custom", volumeName)
volume, _, err := client.GetStoragePoolVolume(pool, volType, volName)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
var results []string
for k := range volume.Config {
results = append(results, k)
}
return results, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpStoragePoolVolumeInstances(poolName string, volumeName string) ([]string, cobra.ShellCompDirective) {
// Parse remote
resources, err := g.parseServers(poolName)
if err != nil || len(resources) == 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
client := resource.server
pool := poolName
if strings.Contains(poolName, ":") {
pool = strings.Split(poolName, ":")[1]
}
volName, volType := parseVolume("custom", volumeName)
volume, _, err := client.GetStoragePoolVolume(pool, volType, volName)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
var results []string
for _, i := range volume.UsedBy {
r := regexp.MustCompile(`/1.0/instances/(.*)`)
match := r.FindStringSubmatch(i)
if len(match) == 2 {
results = append(results, match[1])
}
}
return results, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpStoragePoolVolumeProfiles(poolName string, volumeName string) ([]string, cobra.ShellCompDirective) {
// Parse remote
resources, err := g.parseServers(poolName)
if err != nil || len(resources) == 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
client := resource.server
pool := poolName
if strings.Contains(poolName, ":") {
pool = strings.Split(poolName, ":")[1]
}
volName, volType := parseVolume("custom", volumeName)
volume, _, err := client.GetStoragePoolVolume(pool, volType, volName)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
var results []string
for _, i := range volume.UsedBy {
r := regexp.MustCompile(`/1.0/profiles/(.*)`)
match := r.FindStringSubmatch(i)
if len(match) == 2 {
results = append(results, match[1])
}
}
return results, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpStoragePoolVolumeBitmaps(poolName string, volumeName string) ([]string, cobra.ShellCompDirective) {
// Parse remote
resources, err := g.parseServers(poolName)
if err != nil || len(resources) == 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
client := resource.server
pool := poolName
if strings.Contains(poolName, ":") {
pool = strings.Split(poolName, ":")[1]
}
volName, volType := parseVolume("custom", volumeName)
bitmaps, err := client.GetStorageVolumeBitmapNames(pool, volType, volName)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
return bitmaps, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpStoragePoolVolumeSnapshots(poolName string, volumeName string) ([]string, cobra.ShellCompDirective) {
// Parse remote
resources, err := g.parseServers(poolName)
if err != nil || len(resources) == 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
client := resource.server
pool := poolName
if strings.Contains(poolName, ":") {
pool = strings.Split(poolName, ":")[1]
}
volName, volType := parseVolume("custom", volumeName)
snapshots, err := client.GetStoragePoolVolumeSnapshotNames(pool, volType, volName)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
return snapshots, cobra.ShellCompDirectiveNoFileComp
}
func (g *cmdGlobal) cmpStoragePoolVolumes(poolName string) ([]string, cobra.ShellCompDirective) {
// Parse remote
resources, err := g.parseServers(poolName)
if err != nil || len(resources) == 0 {
return nil, cobra.ShellCompDirectiveError
}
resource := resources[0]
client := resource.server
pool := poolName
if strings.Contains(poolName, ":") {
pool = strings.Split(poolName, ":")[1]
}
volumes, err := client.GetStoragePoolVolumeNames(pool)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
return volumes, cobra.ShellCompDirectiveNoFileComp
}
func isSymlinkToDir(path string, d fs.DirEntry) bool {
if d.Type()&fs.ModeSymlink == 0 {
return false
}
info, err := os.Stat(path)
if err != nil || !info.IsDir() {
return false
}
return true
}
func (g *cmdGlobal) cmpFiles(toComplete string, includeLocalFiles bool) ([]string, cobra.ShellCompDirective) {
instances, directives := g.cmpInstances(toComplete)
for i := range instances {
if strings.HasSuffix(instances[i], ":") {
continue
}
instances[i] += "/"
}
if len(instances) == 0 {
if includeLocalFiles {
return nil, cobra.ShellCompDirectiveDefault
}
return instances, directives
}
directives |= cobra.ShellCompDirectiveNoSpace
if !includeLocalFiles {
return instances, directives
}
var files []string
sep := string(filepath.Separator)
dir, prefix := filepath.Split(toComplete)
switch prefix {
case ".":
files = append(files, dir+"."+sep)
fallthrough
case "..":
files = append(files, dir+".."+sep)
directives |= cobra.ShellCompDirectiveNoSpace
}
root, err := filepath.EvalSymlinks(filepath.Dir(dir))
if err != nil {
return append(instances, files...), directives
}
_ = filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
if err != nil || path == root {
return err
}
base := filepath.Base(path)
if strings.HasPrefix(base, prefix) {
file := dir + base
switch {
case d.IsDir():
directives |= cobra.ShellCompDirectiveNoSpace
file += sep
case isSymlinkToDir(path, d):
directives |= cobra.ShellCompDirectiveNoSpace
if base == prefix {
file += sep
}
}
files = append(files, file)
}
if d.IsDir() {
return fs.SkipDir
}
return nil
})
return append(instances, files...), directives
}