diff --git a/README.md b/README.md index 892ffdc..db540b4 100644 --- a/README.md +++ b/README.md @@ -209,6 +209,8 @@ Press `Esc` to return to the previous resource and selection. | **Octavia / Load Balancing** | load balancers, listeners, pools, members | ✅ | | **Octavia / Load Balancing** | health monitors, L7 policies, L7 rules | ✅ | | **Barbican / Key Manager** | secrets, secret containers, orders | ✅ | +| **Manila / Shared File Systems** | shares, share snapshots, share networks, share types | ✅ | +| **Manila / Shared File Systems** | share replicas, access rules, export locations | ✅ | | **Trove / Databases** | instances | ⬜ | > [!CAUTION] @@ -263,6 +265,13 @@ Press `Esc` to return to the previous resource and selection. | Barbican / Key Manager | Secrets | `secrets` | `secret` | | Barbican / Key Manager | Secret Containers | `secret-containers` | `secret-container` | | Barbican / Key Manager | Orders | `orders` | `order` | +| Manila / Shared File Systems | Shares | `shares` | `share` | +| Manila / Shared File Systems | Share Snapshots | `share-snapshots` | `share-snapshot` | +| Manila / Shared File Systems | Share Replicas | `share-replicas` | `share-replica` | +| Manila / Shared File Systems | Share Networks | `share-networks` | `share-network` | +| Manila / Shared File Systems | Share Types | `share-types` | `share-type` | +| Manila / Shared File Systems | Share Access Rules | `share-access-rules` | `share-access-rule` | +| Manila / Shared File Systems | Share Export Locations | `share-export-locations` | `share-export-location` | | Designate / DNS | Zones | `zones` | `zone`, `dns-zones`, `dns-zone` | | Designate / DNS | Recordsets | `recordsets` | `recordset`, `records`, `record` | diff --git a/cmd/main.go b/cmd/main.go index 4762eb5..5d60750 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -55,6 +55,13 @@ import ( "github.com/akyriako/o7k/internal/resources/orchestration/stackresources" "github.com/akyriako/o7k/internal/resources/orchestration/stacks" pluginresource "github.com/akyriako/o7k/internal/resources/plugins" + "github.com/akyriako/o7k/internal/resources/sharedfilesystem/accessrules" + "github.com/akyriako/o7k/internal/resources/sharedfilesystem/exportlocations" + "github.com/akyriako/o7k/internal/resources/sharedfilesystem/replicas" + "github.com/akyriako/o7k/internal/resources/sharedfilesystem/sharenetworks" + "github.com/akyriako/o7k/internal/resources/sharedfilesystem/shares" + "github.com/akyriako/o7k/internal/resources/sharedfilesystem/sharetypes" + manilasnapshots "github.com/akyriako/o7k/internal/resources/sharedfilesystem/snapshots" "github.com/akyriako/o7k/internal/version" tea "github.com/charmbracelet/bubbletea" @@ -249,6 +256,10 @@ func printPluginUsage() { } func registerAll(r *resource.Registry, openstackContext *openstack.Context) (errs error) { + if err := r.Register(aliases.New(r)); err != nil { + return fmt.Errorf("registering aliases resource: %w", err) + } + if err := r.Register(catalog.New(openstackContext)); err != nil { errs = errors.Join(errs, fmt.Errorf("registering catalog resource: %w", err)) } @@ -413,8 +424,32 @@ func registerAll(r *resource.Registry, openstackContext *openstack.Context) (err return fmt.Errorf("registering orders resource: %w", err) } - if err := r.Register(aliases.New(r)); err != nil { - return fmt.Errorf("registering aliases resource: %w", err) + if err := r.Register(shares.New(openstackContext)); err != nil { + errs = errors.Join(errs, fmt.Errorf("registering shares resource: %w", err)) + } + + if err := r.Register(manilasnapshots.New(openstackContext)); err != nil { + errs = errors.Join(errs, fmt.Errorf("registering share snapshots resource: %w", err)) + } + + if err := r.Register(replicas.New(openstackContext)); err != nil { + errs = errors.Join(errs, fmt.Errorf("registering share replicas resource: %w", err)) + } + + if err := r.Register(sharenetworks.New(openstackContext)); err != nil { + errs = errors.Join(errs, fmt.Errorf("registering share networks resource: %w", err)) + } + + if err := r.RegisterNavigationOnly(accessrules.New(openstackContext)); err != nil { + errs = errors.Join(errs, fmt.Errorf("registering share access rules resource: %w", err)) + } + + if err := r.Register(sharetypes.New(openstackContext)); err != nil { + errs = errors.Join(errs, fmt.Errorf("registering share types resource: %w", err)) + } + + if err := r.RegisterNavigationOnly(exportlocations.New(openstackContext)); err != nil { + errs = errors.Join(errs, fmt.Errorf("registering share export locations resource: %w", err)) } return errs diff --git a/internal/openstack/context.go b/internal/openstack/context.go index 1695152..ba12bcd 100644 --- a/internal/openstack/context.go +++ b/internal/openstack/context.go @@ -136,6 +136,11 @@ func (c *Context) ObjectStorageV1() (*gophercloud.ServiceClient, error) { return c.getClientService("object-storage", gophercloud.EndpointOpts{Region: c.Region}, openstack.NewObjectStorageV1) } +// +//func (c *Context) SharedFileSystemV2() (*gophercloud.ServiceClient, error) { +// return c.getClientService("shared-file-system", gophercloud.EndpointOpts{Region: c.Region}, openstack.NewSharedFileSystemV2) +//} + type clientServiceBuilder func(*gophercloud.ProviderClient, gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) func (c *Context) getClientService(key string, opts gophercloud.EndpointOpts, builder clientServiceBuilder) (*gophercloud.ServiceClient, error) { @@ -155,3 +160,17 @@ func (c *Context) getClientService(key string, opts gophercloud.EndpointOpts, bu actual, _ := c.serviceClients.LoadOrStore(key, client) return actual.(*gophercloud.ServiceClient), nil } + +func (c *Context) SharedFileSystemV2() (*gophercloud.ServiceClient, error) { + return c.getClientService("shared-file-system", gophercloud.EndpointOpts{Region: c.Region}, newSharedFileSystemV2) +} + +func newSharedFileSystemV2(provider *gophercloud.ProviderClient, opts gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { + client, err := openstack.NewSharedFileSystemV2(provider, opts) + if err != nil { + return nil, err + } + + client.Microversion = "2.60" + return client, nil +} diff --git a/internal/resources/blockstorage/backups/backups.go b/internal/resources/blockstorage/backups/backups.go index 717c533..52d8f57 100644 --- a/internal/resources/blockstorage/backups/backups.go +++ b/internal/resources/blockstorage/backups/backups.go @@ -24,7 +24,7 @@ func (r *Resource) Kind() string { } func (r *Resource) Title() string { - return "Volume Backups" + return "Cinder Volume Backups" } func (r *Resource) Aliases() []string { diff --git a/internal/resources/blockstorage/snapshots/snapshots.go b/internal/resources/blockstorage/snapshots/snapshots.go index 5406cdf..78f9740 100644 --- a/internal/resources/blockstorage/snapshots/snapshots.go +++ b/internal/resources/blockstorage/snapshots/snapshots.go @@ -24,7 +24,7 @@ func (r *Resource) Kind() string { } func (r *Resource) Title() string { - return "Snapshots" + return "Cinder Snapshots" } func (r *Resource) Aliases() []string { diff --git a/internal/resources/blockstorage/volumes/volumes.go b/internal/resources/blockstorage/volumes/volumes.go index 6559ce2..9180f99 100644 --- a/internal/resources/blockstorage/volumes/volumes.go +++ b/internal/resources/blockstorage/volumes/volumes.go @@ -24,7 +24,7 @@ func (r *Resource) Kind() string { } func (r *Resource) Title() string { - return "Volumes" + return "Cinder Volumes" } func (r *Resource) Aliases() []string { diff --git a/internal/resources/blockstorage/volumetypes/volumetypes.go b/internal/resources/blockstorage/volumetypes/volumetypes.go index 11ae914..bfd6656 100644 --- a/internal/resources/blockstorage/volumetypes/volumetypes.go +++ b/internal/resources/blockstorage/volumetypes/volumetypes.go @@ -23,7 +23,7 @@ func (r *Resource) Kind() string { } func (r *Resource) Title() string { - return "Volume Types" + return "Cinder Volume Types" } func (r *Resource) Aliases() []string { diff --git a/internal/resources/compute/availabilityzones/availabilityzones.go b/internal/resources/compute/availabilityzones/availabilityzones.go index 256905a..70d8498 100644 --- a/internal/resources/compute/availabilityzones/availabilityzones.go +++ b/internal/resources/compute/availabilityzones/availabilityzones.go @@ -24,7 +24,7 @@ func (r *Resource) Kind() string { } func (r *Resource) Title() string { - return "Availability Zones" + return "Compute Availability Zones" } func (r *Resource) Aliases() []string { diff --git a/internal/resources/compute/flavors/flavors.go b/internal/resources/compute/flavors/flavors.go index c87938a..8d17917 100644 --- a/internal/resources/compute/flavors/flavors.go +++ b/internal/resources/compute/flavors/flavors.go @@ -24,7 +24,7 @@ func (r *Resource) Kind() string { } func (r *Resource) Title() string { - return "Flavors" + return "Compute Flavors" } func (r *Resource) Aliases() []string { diff --git a/internal/resources/compute/keypairs/keypairs.go b/internal/resources/compute/keypairs/keypairs.go index de12497..d054e89 100644 --- a/internal/resources/compute/keypairs/keypairs.go +++ b/internal/resources/compute/keypairs/keypairs.go @@ -23,7 +23,7 @@ func (r *Resource) Kind() string { } func (r *Resource) Title() string { - return "Keypairs" + return "Compute Keypairs" } func (r *Resource) Aliases() []string { diff --git a/internal/resources/compute/servergroups/servergroups.go b/internal/resources/compute/servergroups/servergroups.go index 45c481e..673b03c 100644 --- a/internal/resources/compute/servergroups/servergroups.go +++ b/internal/resources/compute/servergroups/servergroups.go @@ -24,7 +24,7 @@ func (r *Resource) Kind() string { } func (r *Resource) Title() string { - return "Server Groups" + return "Compute Server Groups" } func (r *Resource) Aliases() []string { diff --git a/internal/resources/compute/servers/servers.go b/internal/resources/compute/servers/servers.go index 126675b..b02e1a0 100644 --- a/internal/resources/compute/servers/servers.go +++ b/internal/resources/compute/servers/servers.go @@ -21,7 +21,7 @@ func New(context *openstack.Context) *Resource { } func (r *Resource) Title() string { - return "Servers" + return "Compute Servers" } func (r *Resource) Kind() string { diff --git a/internal/resources/dns/recordsets/recordsets.go b/internal/resources/dns/recordsets/recordsets.go index ed82033..e90f71e 100644 --- a/internal/resources/dns/recordsets/recordsets.go +++ b/internal/resources/dns/recordsets/recordsets.go @@ -22,7 +22,7 @@ func New(context *openstack.Context) *Resource { } func (r *Resource) Title() string { - return "DNS Recordsets" + return "Designate DNS Recordsets" } func (r *Resource) Kind() string { diff --git a/internal/resources/dns/zones/zones.go b/internal/resources/dns/zones/zones.go index 9574633..5fa44ae 100644 --- a/internal/resources/dns/zones/zones.go +++ b/internal/resources/dns/zones/zones.go @@ -20,7 +20,7 @@ func New(context *openstack.Context) *Resource { } func (r *Resource) Title() string { - return "DNS Zones" + return "Designate DNS Zones" } func (r *Resource) Kind() string { diff --git a/internal/resources/identity/catalog/catalog.go b/internal/resources/identity/catalog/catalog.go index 89eaba5..ecaf953 100644 --- a/internal/resources/identity/catalog/catalog.go +++ b/internal/resources/identity/catalog/catalog.go @@ -21,7 +21,7 @@ func (r *Resource) Kind() string { } func (r *Resource) Title() string { - return "Catalog" + return "Keystone Catalog" } func (r *Resource) Aliases() []string { diff --git a/internal/resources/identity/domains/domains.go b/internal/resources/identity/domains/domains.go index 9643543..851f738 100644 --- a/internal/resources/identity/domains/domains.go +++ b/internal/resources/identity/domains/domains.go @@ -24,7 +24,7 @@ func (r *Resource) Kind() string { } func (r *Resource) Title() string { - return "Domains" + return "Keystone Domains" } func (r *Resource) Aliases() []string { diff --git a/internal/resources/identity/endpoints/endpoints.go b/internal/resources/identity/endpoints/endpoints.go index 0f9dfe9..7dc8025 100644 --- a/internal/resources/identity/endpoints/endpoints.go +++ b/internal/resources/identity/endpoints/endpoints.go @@ -24,7 +24,7 @@ func (r *Resource) Kind() string { } func (r *Resource) Title() string { - return "Endpoints" + return "Keystone Endpoints" } func (r *Resource) Aliases() []string { diff --git a/internal/resources/identity/projects/projects.go b/internal/resources/identity/projects/projects.go index c4cbb44..3171e67 100644 --- a/internal/resources/identity/projects/projects.go +++ b/internal/resources/identity/projects/projects.go @@ -24,7 +24,7 @@ func (r *Resource) Kind() string { } func (r *Resource) Title() string { - return "Projects" + return "Keystone Projects" } func (r *Resource) Aliases() []string { diff --git a/internal/resources/identity/regions/regions.go b/internal/resources/identity/regions/regions.go index f883cc7..e7873c9 100644 --- a/internal/resources/identity/regions/regions.go +++ b/internal/resources/identity/regions/regions.go @@ -23,7 +23,7 @@ func (r *Resource) Kind() string { } func (r *Resource) Title() string { - return "Regions" + return "Keystone Regions" } func (r *Resource) Aliases() []string { diff --git a/internal/resources/identity/roles/roles.go b/internal/resources/identity/roles/roles.go index 33000b6..cd662f3 100644 --- a/internal/resources/identity/roles/roles.go +++ b/internal/resources/identity/roles/roles.go @@ -23,7 +23,7 @@ func (r *Resource) Kind() string { } func (r *Resource) Title() string { - return "Roles" + return "Keystone Roles" } func (r *Resource) Aliases() []string { diff --git a/internal/resources/identity/services/services.go b/internal/resources/identity/services/services.go index 4890090..4b40205 100644 --- a/internal/resources/identity/services/services.go +++ b/internal/resources/identity/services/services.go @@ -24,7 +24,7 @@ func (r *Resource) Kind() string { } func (r *Resource) Title() string { - return "Services" + return "Keystone Services" } func (r *Resource) Aliases() []string { diff --git a/internal/resources/images/images.go b/internal/resources/images/images.go index bd41c5a..9919611 100644 --- a/internal/resources/images/images.go +++ b/internal/resources/images/images.go @@ -24,7 +24,7 @@ func (r *Resource) Kind() string { } func (r *Resource) Title() string { - return "Images" + return "Glance Images" } func (r *Resource) Aliases() []string { diff --git a/internal/resources/keymanager/containers/containers.go b/internal/resources/keymanager/containers/containers.go index 329780d..eed2853 100644 --- a/internal/resources/keymanager/containers/containers.go +++ b/internal/resources/keymanager/containers/containers.go @@ -25,7 +25,7 @@ func (r *Resource) Kind() string { } func (r *Resource) Title() string { - return "Secret Containers" + return "Barbican Secret Containers" } func (r *Resource) Aliases() []string { diff --git a/internal/resources/keymanager/orders/orders.go b/internal/resources/keymanager/orders/orders.go index b47401f..f031cc9 100644 --- a/internal/resources/keymanager/orders/orders.go +++ b/internal/resources/keymanager/orders/orders.go @@ -25,7 +25,7 @@ func (r *Resource) Kind() string { } func (r *Resource) Title() string { - return "Orders" + return "Barbican Orders" } func (r *Resource) Aliases() []string { diff --git a/internal/resources/keymanager/secrets/secrets.go b/internal/resources/keymanager/secrets/secrets.go index a257dab..1ec6546 100644 --- a/internal/resources/keymanager/secrets/secrets.go +++ b/internal/resources/keymanager/secrets/secrets.go @@ -25,7 +25,7 @@ func (r *Resource) Kind() string { } func (r *Resource) Title() string { - return "Secrets" + return "Barbican Secrets" } func (r *Resource) Aliases() []string { diff --git a/internal/resources/loadbalancing/healthmonitors/healthmonitors.go b/internal/resources/loadbalancing/healthmonitors/healthmonitors.go index 30d2bf7..1b75cc9 100644 --- a/internal/resources/loadbalancing/healthmonitors/healthmonitors.go +++ b/internal/resources/loadbalancing/healthmonitors/healthmonitors.go @@ -20,7 +20,7 @@ func New(context *openstack.Context) *Resource { } func (r *Resource) Title() string { - return "Health Monitors" + return "Octavia Health Monitors" } func (r *Resource) Kind() string { diff --git a/internal/resources/loadbalancing/l7policies/l7policies.go b/internal/resources/loadbalancing/l7policies/l7policies.go index 4a18ef6..ac0cdd2 100644 --- a/internal/resources/loadbalancing/l7policies/l7policies.go +++ b/internal/resources/loadbalancing/l7policies/l7policies.go @@ -20,7 +20,7 @@ func New(context *openstack.Context) *Resource { } func (r *Resource) Title() string { - return "L7 Policies" + return "Octavia L7 Policies" } func (r *Resource) Kind() string { diff --git a/internal/resources/loadbalancing/l7rules/l7rules.go b/internal/resources/loadbalancing/l7rules/l7rules.go index 8378f45..ad8a91a 100644 --- a/internal/resources/loadbalancing/l7rules/l7rules.go +++ b/internal/resources/loadbalancing/l7rules/l7rules.go @@ -19,7 +19,7 @@ func New(context *openstack.Context) *Resource { } func (r *Resource) Title() string { - return "L7 Rules" + return "Octavia L7 Rules" } func (r *Resource) Kind() string { diff --git a/internal/resources/loadbalancing/listeners/listeners.go b/internal/resources/loadbalancing/listeners/listeners.go index d5faa35..8765b96 100644 --- a/internal/resources/loadbalancing/listeners/listeners.go +++ b/internal/resources/loadbalancing/listeners/listeners.go @@ -20,7 +20,7 @@ func New(context *openstack.Context) *Resource { } func (r *Resource) Title() string { - return "Listeners" + return "Octavia Listeners" } func (r *Resource) Kind() string { diff --git a/internal/resources/loadbalancing/loadbalancers/loadbalancers.go b/internal/resources/loadbalancing/loadbalancers/loadbalancers.go index e3f81e8..b497057 100644 --- a/internal/resources/loadbalancing/loadbalancers/loadbalancers.go +++ b/internal/resources/loadbalancing/loadbalancers/loadbalancers.go @@ -19,7 +19,7 @@ func New(context *openstack.Context) *Resource { } func (r *Resource) Title() string { - return "Load Balancers" + return "Octavia Load Balancers" } func (r *Resource) Kind() string { diff --git a/internal/resources/loadbalancing/members/members.go b/internal/resources/loadbalancing/members/members.go index e8b1f85..0814062 100644 --- a/internal/resources/loadbalancing/members/members.go +++ b/internal/resources/loadbalancing/members/members.go @@ -20,7 +20,7 @@ func New(context *openstack.Context) *Resource { } func (r *Resource) Title() string { - return "Members" + return "Octavia Pools Members" } func (r *Resource) Kind() string { diff --git a/internal/resources/loadbalancing/pools/pools.go b/internal/resources/loadbalancing/pools/pools.go index 8e150cf..c359f97 100644 --- a/internal/resources/loadbalancing/pools/pools.go +++ b/internal/resources/loadbalancing/pools/pools.go @@ -19,7 +19,7 @@ func New(context *openstack.Context) *Resource { } func (r *Resource) Title() string { - return "Pools" + return "Octavia Pools" } func (r *Resource) Kind() string { diff --git a/internal/resources/networking/floatingips/floatingips.go b/internal/resources/networking/floatingips/floatingips.go index d4b4ed9..e5e0e09 100644 --- a/internal/resources/networking/floatingips/floatingips.go +++ b/internal/resources/networking/floatingips/floatingips.go @@ -23,7 +23,7 @@ func (r *Resource) Kind() string { } func (r *Resource) Title() string { - return "Floating IPs" + return "Neutron Floating IPs" } func (r *Resource) Aliases() []string { diff --git a/internal/resources/networking/networks/networks.go b/internal/resources/networking/networks/networks.go index 96a6749..97bc11e 100644 --- a/internal/resources/networking/networks/networks.go +++ b/internal/resources/networking/networks/networks.go @@ -26,7 +26,7 @@ func (r *Resource) Kind() string { } func (r *Resource) Title() string { - return "Networks" + return "Neutron Networks" } func (r *Resource) Aliases() []string { diff --git a/internal/resources/networking/ports/ports.go b/internal/resources/networking/ports/ports.go index 18a326a..9f36497 100644 --- a/internal/resources/networking/ports/ports.go +++ b/internal/resources/networking/ports/ports.go @@ -23,7 +23,7 @@ func (r *Resource) Kind() string { } func (r *Resource) Title() string { - return "Ports" + return "Neutron Ports" } func (r *Resource) Aliases() []string { diff --git a/internal/resources/networking/routers/routers.go b/internal/resources/networking/routers/routers.go index c333e26..b34187a 100644 --- a/internal/resources/networking/routers/routers.go +++ b/internal/resources/networking/routers/routers.go @@ -24,7 +24,7 @@ func (r *Resource) Kind() string { } func (r *Resource) Title() string { - return "Routers" + return "Neutron Routers" } func (r *Resource) Aliases() []string { diff --git a/internal/resources/networking/securitygrouprules/securitygrouprules.go b/internal/resources/networking/securitygrouprules/securitygrouprules.go index 8e1a5e8..142dc34 100644 --- a/internal/resources/networking/securitygrouprules/securitygrouprules.go +++ b/internal/resources/networking/securitygrouprules/securitygrouprules.go @@ -23,7 +23,7 @@ func (r *Resource) Kind() string { } func (r *Resource) Title() string { - return "Security Group Rules" + return "Neutron Security Group Rules" } func (r *Resource) Aliases() []string { diff --git a/internal/resources/networking/securitygroups/securitygroups.go b/internal/resources/networking/securitygroups/securitygroups.go index 0c6e871..3ed37d9 100644 --- a/internal/resources/networking/securitygroups/securitygroups.go +++ b/internal/resources/networking/securitygroups/securitygroups.go @@ -23,7 +23,7 @@ func (r *Resource) Kind() string { } func (r *Resource) Title() string { - return "Security Groups" + return "Neutron Security Groups" } func (r *Resource) Aliases() []string { diff --git a/internal/resources/networking/subnets/subnets.go b/internal/resources/networking/subnets/subnets.go index 0ca5bd9..5de4ff3 100644 --- a/internal/resources/networking/subnets/subnets.go +++ b/internal/resources/networking/subnets/subnets.go @@ -24,7 +24,7 @@ func (r *Resource) Kind() string { } func (r *Resource) Title() string { - return "Subnets" + return "Neutron Subnets" } func (r *Resource) Aliases() []string { diff --git a/internal/resources/orchestration/stackevents/stackevents.go b/internal/resources/orchestration/stackevents/stackevents.go index 9d71997..241cd37 100644 --- a/internal/resources/orchestration/stackevents/stackevents.go +++ b/internal/resources/orchestration/stackevents/stackevents.go @@ -19,7 +19,7 @@ func New(context *openstack.Context) *Resource { } func (r *Resource) Title() string { - return "Stack Events" + return "Heat Stack Events" } func (r *Resource) Kind() string { diff --git a/internal/resources/orchestration/stackresources/stackresources.go b/internal/resources/orchestration/stackresources/stackresources.go index 00ee5f9..dd9b5bb 100644 --- a/internal/resources/orchestration/stackresources/stackresources.go +++ b/internal/resources/orchestration/stackresources/stackresources.go @@ -19,7 +19,7 @@ func New(context *openstack.Context) *Resource { } func (r *Resource) Title() string { - return "Stack Resources" + return "Heat Stack Resources" } func (r *Resource) Kind() string { diff --git a/internal/resources/orchestration/stacks/stacks.go b/internal/resources/orchestration/stacks/stacks.go index f3b1b42..c9d5b19 100644 --- a/internal/resources/orchestration/stacks/stacks.go +++ b/internal/resources/orchestration/stacks/stacks.go @@ -19,7 +19,7 @@ func New(context *openstack.Context) *Resource { } func (r *Resource) Title() string { - return "Stacks" + return "Heat Stacks" } func (r *Resource) Kind() string { @@ -43,9 +43,9 @@ func (r *Resource) Columns() []resource.Column { func (r *Resource) Commands() []resource.Command { return []resource.Command{ - {Key: "s", Description: "Show", Default: true}, + {Key: "s", Description: "Show"}, {Key: "shift-r", Description: "Resources"}, - {Key: "shift-e", Description: "Events"}, + {Key: "shift-e", Description: "Events", Default: true}, } } func (r *Resource) List(ctx context.Context) ([]resource.Row, error) { diff --git a/internal/resources/sharedfilesystem/accessrules/accessrules.go b/internal/resources/sharedfilesystem/accessrules/accessrules.go new file mode 100644 index 0000000..d3484f0 --- /dev/null +++ b/internal/resources/sharedfilesystem/accessrules/accessrules.go @@ -0,0 +1,90 @@ +package accessrules + +import ( + "context" + "fmt" + + "github.com/akyriako/o7k/internal/openstack" + "github.com/akyriako/o7k/internal/resource" + tea "github.com/charmbracelet/bubbletea" + "github.com/gophercloud/gophercloud/v2/openstack/sharedfilesystems/v2/shareaccessrules" +) + +type Resource struct { + context *openstack.Context +} + +func New(context *openstack.Context) *Resource { + return &Resource{context: context} +} + +func (r *Resource) Title() string { + return "Share Access Rules" +} + +func (r *Resource) Kind() string { + return "share-access-rules" +} + +func (r *Resource) Aliases() []string { + return []string{ + "share-access-rule", + } +} + +func (r *Resource) Columns() []resource.Column { + return []resource.Column{ + {Key: "id", Title: "ID", MinWidth: 40, Flex: 0}, + {Key: "access_type", Title: "TYPE", MinWidth: 10, Flex: 0}, + {Key: "access_to", Title: "ACCESS TO", MinWidth: 24, Flex: 1}, + {Key: "access_level", Title: "LEVEL", MinWidth: 10, Flex: 0}, + {Key: "state", Title: "STATE", MinWidth: 12, Flex: 0}, + } +} + +func (r *Resource) Commands() []resource.Command { + return nil +} + +func (r *Resource) List(ctx context.Context) ([]resource.Row, error) { + scope := resource.Scope(ctx) + shareID := scope["share_id"] + + if shareID == "" { + return nil, fmt.Errorf("share ID is required") + } + + client, err := r.context.SharedFileSystemV2() + if err != nil { + return nil, err + } + + result := shareaccessrules.List(ctx, client, shareID) + + items, err := result.Extract() + if err != nil { + return nil, fmt.Errorf("listing share access rules: %w", err) + } + + rows := make([]resource.Row, 0, len(items)) + + for _, rule := range items { + rows = append(rows, resource.Row{ + ID: rule.ID, + Fields: map[string]string{ + "id": rule.ID, + "share_id": rule.ShareID, + "access_type": rule.AccessType, + "access_to": rule.AccessTo, + "access_level": rule.AccessLevel, + "state": rule.State, + "access_key": rule.AccessKey, + }, + }) + } + + return rows, nil +} +func (r *Resource) Execute(command resource.Command, row resource.Row) tea.Cmd { + return nil +} diff --git a/internal/resources/sharedfilesystem/exportlocations/exportlocations.go b/internal/resources/sharedfilesystem/exportlocations/exportlocations.go new file mode 100644 index 0000000..eb66cf5 --- /dev/null +++ b/internal/resources/sharedfilesystem/exportlocations/exportlocations.go @@ -0,0 +1,90 @@ +package exportlocations + +import ( + "context" + "fmt" + "strconv" + + "github.com/akyriako/o7k/internal/openstack" + "github.com/akyriako/o7k/internal/resource" + tea "github.com/charmbracelet/bubbletea" + manilashares "github.com/gophercloud/gophercloud/v2/openstack/sharedfilesystems/v2/shares" +) + +type Resource struct { + context *openstack.Context +} + +func New(context *openstack.Context) *Resource { + return &Resource{context: context} +} + +func (r *Resource) Title() string { + return "Share Export Locations" +} + +func (r *Resource) Kind() string { + return "share-export-locations" +} + +func (r *Resource) Aliases() []string { + return []string{ + "share-export-location", + } +} + +func (r *Resource) Columns() []resource.Column { + return []resource.Column{ + {Key: "id", Title: "ID", MinWidth: 40, Flex: 0}, + {Key: "path", Title: "PATH", MinWidth: 40, Flex: 1}, + {Key: "preferred", Title: "PREFERRED", MinWidth: 10, Flex: 0}, + {Key: "is_admin_only", Title: "ADMIN ONLY", MinWidth: 10, Flex: 0}, + {Key: "share_instance_id", Title: "SHARE INSTANCE ID", MinWidth: 40, Flex: 0}, + } +} + +func (r *Resource) Commands() []resource.Command { + return nil +} + +func (r *Resource) List(ctx context.Context) ([]resource.Row, error) { + scope := resource.Scope(ctx) + shareID := scope["share_id"] + + if shareID == "" { + return nil, fmt.Errorf("share ID is required") + } + + client, err := r.context.SharedFileSystemV2() + if err != nil { + return nil, err + } + + result := manilashares.ListExportLocations(ctx, client, shareID) + + locations, err := result.Extract() + if err != nil { + return nil, fmt.Errorf("listing share export locations: %w", err) + } + + rows := make([]resource.Row, 0, len(locations)) + + for _, location := range locations { + rows = append(rows, resource.Row{ + ID: location.ID, + Fields: map[string]string{ + "id": location.ID, + "path": location.Path, + "preferred": strconv.FormatBool(location.Preferred), + "is_admin_only": strconv.FormatBool(location.IsAdminOnly), + "share_instance_id": location.ShareInstanceID, + }, + }) + } + + return rows, nil +} + +func (r *Resource) Execute(command resource.Command, row resource.Row) tea.Cmd { + return nil +} diff --git a/internal/resources/sharedfilesystem/replicas/commands.go b/internal/resources/sharedfilesystem/replicas/commands.go new file mode 100644 index 0000000..4f752a2 --- /dev/null +++ b/internal/resources/sharedfilesystem/replicas/commands.go @@ -0,0 +1,31 @@ +package replicas + +import ( + "context" + "fmt" + + "github.com/akyriako/o7k/internal/resource" + tea "github.com/charmbracelet/bubbletea" + manilareplicas "github.com/gophercloud/gophercloud/v2/openstack/sharedfilesystems/v2/replicas" +) + +func (r *Resource) show(id string) tea.Cmd { + return func() tea.Msg { + client, err := r.context.SharedFileSystemV2() + if err != nil { + return resource.DetailsMsg{Err: err} + } + + replica, err := manilareplicas.Get(context.Background(), client, id).Extract() + if err != nil { + return resource.DetailsMsg{ + Err: fmt.Errorf("getting share replica %q: %w", id, err), + } + } + + return resource.DetailsMsg{ + ID: replica.ID, + Content: replica, + } + } +} diff --git a/internal/resources/sharedfilesystem/replicas/replicas.go b/internal/resources/sharedfilesystem/replicas/replicas.go new file mode 100644 index 0000000..82f7663 --- /dev/null +++ b/internal/resources/sharedfilesystem/replicas/replicas.go @@ -0,0 +1,96 @@ +package replicas + +import ( + "context" + "fmt" + + "github.com/akyriako/o7k/internal/openstack" + "github.com/akyriako/o7k/internal/resource" + tea "github.com/charmbracelet/bubbletea" + manilareplicas "github.com/gophercloud/gophercloud/v2/openstack/sharedfilesystems/v2/replicas" +) + +type Resource struct { + context *openstack.Context +} + +func New(context *openstack.Context) *Resource { + return &Resource{context: context} +} + +func (r *Resource) Title() string { + return "Manila Share Replicas" +} + +func (r *Resource) Kind() string { + return "share-replicas" +} + +func (r *Resource) Aliases() []string { + return []string{ + "share-replica", + } +} + +func (r *Resource) Columns() []resource.Column { + return []resource.Column{ + {Key: "id", Title: "ID", MinWidth: 40, Flex: 0}, + {Key: "share_id", Title: "SHARE ID", MinWidth: 40, Flex: 0}, + {Key: "status", Title: "STATUS", MinWidth: 12, Flex: 0}, + {Key: "state", Title: "REPLICA STATE", MinWidth: 16, Flex: 0}, + {Key: "availability_zone", Title: "AZ", MinWidth: 12, Flex: 0}, + {Key: "host", Title: "HOST", MinWidth: 24, Flex: 1}, + } +} + +func (r *Resource) Commands() []resource.Command { + return []resource.Command{ + {Key: "s", Description: "Show", Default: true}, + } +} + +func (r *Resource) List(ctx context.Context) ([]resource.Row, error) { + client, err := r.context.SharedFileSystemV2() + if err != nil { + return nil, err + } + + pages, err := manilareplicas.ListDetail(client, manilareplicas.ListOpts{}).AllPages(ctx) + if err != nil { + return nil, fmt.Errorf("listing share replicas: %w", err) + } + + items, err := manilareplicas.ExtractReplicas(pages) + if err != nil { + return nil, fmt.Errorf("extracting share replicas: %w", err) + } + + rows := make([]resource.Row, 0, len(items)) + + for _, replica := range items { + rows = append(rows, resource.Row{ + ID: replica.ID, + Fields: map[string]string{ + "id": replica.ID, + "share_id": replica.ShareID, + "status": replica.Status, + "state": replica.State, + "availability_zone": replica.AvailabilityZone, + "host": replica.Host, + "share_network_id": replica.ShareNetworkID, + "share_server_id": replica.ShareServerID, + }, + }) + } + + return rows, nil +} + +func (r *Resource) Execute(command resource.Command, row resource.Row) tea.Cmd { + switch command.Key { + case "s": + return r.show(row.ID) + } + + return nil +} diff --git a/internal/resources/sharedfilesystem/sharenetworks/commands.go b/internal/resources/sharedfilesystem/sharenetworks/commands.go new file mode 100644 index 0000000..4fa1384 --- /dev/null +++ b/internal/resources/sharedfilesystem/sharenetworks/commands.go @@ -0,0 +1,31 @@ +package sharenetworks + +import ( + "context" + "fmt" + + "github.com/akyriako/o7k/internal/resource" + tea "github.com/charmbracelet/bubbletea" + manilasharenetworks "github.com/gophercloud/gophercloud/v2/openstack/sharedfilesystems/v2/sharenetworks" +) + +func (r *Resource) show(id string) tea.Cmd { + return func() tea.Msg { + client, err := r.context.SharedFileSystemV2() + if err != nil { + return resource.DetailsMsg{Err: err} + } + + network, err := manilasharenetworks.Get(context.Background(), client, id).Extract() + if err != nil { + return resource.DetailsMsg{ + Err: fmt.Errorf("getting share network %q: %w", id, err), + } + } + + return resource.DetailsMsg{ + ID: network.ID, + Content: network, + } + } +} diff --git a/internal/resources/sharedfilesystem/sharenetworks/sharenetworks.go b/internal/resources/sharedfilesystem/sharenetworks/sharenetworks.go new file mode 100644 index 0000000..d7504bd --- /dev/null +++ b/internal/resources/sharedfilesystem/sharenetworks/sharenetworks.go @@ -0,0 +1,89 @@ +package sharenetworks + +import ( + "context" + "fmt" + + "github.com/akyriako/o7k/internal/openstack" + "github.com/akyriako/o7k/internal/resource" + tea "github.com/charmbracelet/bubbletea" + manilasharenetworks "github.com/gophercloud/gophercloud/v2/openstack/sharedfilesystems/v2/sharenetworks" +) + +type Resource struct { + context *openstack.Context +} + +func New(context *openstack.Context) *Resource { + return &Resource{context: context} +} + +func (r *Resource) Title() string { + return "Manila Share Networks" +} + +func (r *Resource) Kind() string { + return "share-networks" +} + +func (r *Resource) Aliases() []string { + return []string{ + "share-network", + } +} + +func (r *Resource) Columns() []resource.Column { + return []resource.Column{ + {Key: "id", Title: "ID", MinWidth: 40, Flex: 0}, + {Key: "name", Title: "NAME", MinWidth: 24, Flex: 1}, + {Key: "description", Title: "DESCRIPTION", MinWidth: 32, Flex: 2}, + } +} + +func (r *Resource) Commands() []resource.Command { + return []resource.Command{ + {Key: "s", Description: "Show", Default: true}, + } +} + +func (r *Resource) List(ctx context.Context) ([]resource.Row, error) { + client, err := r.context.SharedFileSystemV2() + if err != nil { + return nil, err + } + + pages, err := manilasharenetworks.ListDetail(client, manilasharenetworks.ListOpts{}).AllPages(ctx) + if err != nil { + return nil, fmt.Errorf("listing share networks: %w", err) + } + + items, err := manilasharenetworks.ExtractShareNetworks(pages) + if err != nil { + return nil, fmt.Errorf("extracting share networks: %w", err) + } + + rows := make([]resource.Row, 0, len(items)) + + for _, network := range items { + rows = append(rows, resource.Row{ + ID: network.ID, + Fields: map[string]string{ + "id": network.ID, + "name": network.Name, + "description": network.Description, + "project_id": network.ProjectID, + }, + }) + } + + return rows, nil +} + +func (r *Resource) Execute(command resource.Command, row resource.Row) tea.Cmd { + switch command.Key { + case "s": + return r.show(row.ID) + } + + return nil +} diff --git a/internal/resources/sharedfilesystem/shares/commands.go b/internal/resources/sharedfilesystem/shares/commands.go new file mode 100644 index 0000000..4b31254 --- /dev/null +++ b/internal/resources/sharedfilesystem/shares/commands.go @@ -0,0 +1,93 @@ +package shares + +import ( + "context" + "fmt" + + "github.com/akyriako/o7k/internal/resource" + tea "github.com/charmbracelet/bubbletea" + manilashares "github.com/gophercloud/gophercloud/v2/openstack/sharedfilesystems/v2/shares" +) + +func (r *Resource) show(id string) tea.Cmd { + return func() tea.Msg { + client, err := r.context.SharedFileSystemV2() + if err != nil { + return resource.DetailsMsg{Err: err} + } + + share, err := manilashares.Get(context.Background(), client, id).Extract() + if err != nil { + return resource.DetailsMsg{ + Err: fmt.Errorf("getting share %q: %w", id, err), + } + } + + return resource.DetailsMsg{ + ID: share.ID, + Content: share, + } + } +} + +func (r *Resource) snapshots(row resource.Row) tea.Cmd { + return func() tea.Msg { + return resource.NavigateFilteredMsg{ + Resource: "share-snapshots", + Field: "share_id", + Value: row.ID, + } + } +} + +func (r *Resource) replicas(row resource.Row) tea.Cmd { + return func() tea.Msg { + return resource.NavigateFilteredMsg{ + Resource: "share-replicas", + Field: "share_id", + Value: row.ID, + } + } +} + +func (r *Resource) shareNetwork(row resource.Row) tea.Cmd { + return func() tea.Msg { + return resource.NavigateFilteredMsg{ + Resource: "share-networks", + Field: "id", + Value: row.Fields["share_network_id"], + } + } +} + +func (r *Resource) accessRules(row resource.Row) tea.Cmd { + return func() tea.Msg { + return resource.NavigateScopedMsg{ + Resource: "share-access-rules", + Scope: map[string]string{ + "share_id": row.ID, + }, + } + } +} + +func (r *Resource) shareType(row resource.Row) tea.Cmd { + return func() tea.Msg { + return resource.NavigateFilteredMsg{ + Resource: "share-types", + Field: "id", + Value: row.Fields["share_type_id"], + } + } +} + +func (r *Resource) exportLocations(row resource.Row) tea.Cmd { + return func() tea.Msg { + return resource.NavigateScopedMsg{ + Resource: "share-export-locations", + Scope: map[string]string{ + "share_id": row.ID, + }, + } + } +} diff --git a/internal/resources/sharedfilesystem/shares/shares.go b/internal/resources/sharedfilesystem/shares/shares.go new file mode 100644 index 0000000..56abcdc --- /dev/null +++ b/internal/resources/sharedfilesystem/shares/shares.go @@ -0,0 +1,125 @@ +package shares + +import ( + "context" + "fmt" + "strconv" + + "github.com/akyriako/o7k/internal/openstack" + "github.com/akyriako/o7k/internal/resource" + tea "github.com/charmbracelet/bubbletea" + manilashares "github.com/gophercloud/gophercloud/v2/openstack/sharedfilesystems/v2/shares" +) + +type Resource struct { + context *openstack.Context +} + +func New(context *openstack.Context) *Resource { + return &Resource{context: context} +} + +func (r *Resource) Title() string { + return "Manila Shares" +} + +func (r *Resource) Kind() string { + return "shares" +} + +func (r *Resource) Aliases() []string { + return []string{ + "share", + } +} + +func (r *Resource) Columns() []resource.Column { + return []resource.Column{ + {Key: "id", Title: "ID", MinWidth: 40, Flex: 0}, + {Key: "name", Title: "NAME", MinWidth: 24, Flex: 1}, + {Key: "size", Title: "SIZE", MinWidth: 8, Flex: 0}, + {Key: "protocol", Title: "PROTOCOL", MinWidth: 10, Flex: 0}, + {Key: "availability_zone", Title: "AVAILABILITY ZONE", MinWidth: 12, Flex: 0}, + {Key: "share_type", Title: "SHARE TYPE", MinWidth: 16, Flex: 1}, + {Key: "has_replicas", Title: "REPLICAS", MinWidth: 10, Flex: 0}, + {Key: "snapshot_support", Title: "SNAPSHOTS", MinWidth: 10, Flex: 0}, + {Key: "status", Title: "STATUS", MinWidth: 12, Flex: 0}, + + //{Key: "host", Title: "HOST", MinWidth: 24, Flex: 1}, + } +} + +func (r *Resource) Commands() []resource.Command { + return []resource.Command{ + {Key: "s", Description: "Show", Default: true}, + {Key: "shift-s", Description: "Snapshots"}, + {Key: "shift-r", Description: "Replicas"}, + {Key: "shift-n", Description: "Share Network"}, + {Key: "shift-a", Description: "Access Rules"}, + {Key: "shift-t", Description: "Share Type"}, + {Key: "shift-e", Description: "Export Locations"}, + } +} + +func (r *Resource) List(ctx context.Context) ([]resource.Row, error) { + client, err := r.context.SharedFileSystemV2() + if err != nil { + return nil, err + } + + pages, err := manilashares.ListDetail(client, manilashares.ListOpts{}).AllPages(ctx) + if err != nil { + return nil, fmt.Errorf("listing shares: %w", err) + } + + items, err := manilashares.ExtractShares(pages) + if err != nil { + return nil, fmt.Errorf("extracting shares: %w", err) + } + + rows := make([]resource.Row, 0, len(items)) + + for _, share := range items { + rows = append(rows, resource.Row{ + ID: share.ID, + Fields: map[string]string{ + "id": share.ID, + "name": share.Name, + "size": strconv.Itoa(share.Size), + "protocol": share.ShareProto, + "status": share.Status, + "share_type": share.ShareTypeName, + "share_type_id": share.ShareType, + "share_network_id": share.ShareNetworkID, + "share_server_id": share.ShareServerID, + "host": share.Host, + "availability_zone": share.AvailabilityZone, + "has_replicas": strconv.FormatBool(share.HasReplicas), + "snapshot_support": strconv.FormatBool(share.SnapshotSupport), + }, + }) + } + + return rows, nil +} + +func (r *Resource) Execute(command resource.Command, row resource.Row) tea.Cmd { + switch command.Key { + case "s": + return r.show(row.ID) + case "shift-s": + return r.snapshots(row) + case "shift-r": + return r.replicas(row) + case "shift-n": + return r.shareNetwork(row) + case "shift-a": + return r.accessRules(row) + case "shift-t": + return r.shareType(row) + case "shift-e": + return r.exportLocations(row) + } + + return nil +} diff --git a/internal/resources/sharedfilesystem/sharetypes/commands.go b/internal/resources/sharedfilesystem/sharetypes/commands.go new file mode 100644 index 0000000..6c7d3a8 --- /dev/null +++ b/internal/resources/sharedfilesystem/sharetypes/commands.go @@ -0,0 +1,31 @@ +package sharetypes + +import ( + "context" + "fmt" + + "github.com/akyriako/o7k/internal/resource" + tea "github.com/charmbracelet/bubbletea" + manilasharetypes "github.com/gophercloud/gophercloud/v2/openstack/sharedfilesystems/v2/sharetypes" +) + +func (r *Resource) show(id string) tea.Cmd { + return func() tea.Msg { + client, err := r.context.SharedFileSystemV2() + if err != nil { + return resource.DetailsMsg{Err: err} + } + + shareType, err := manilasharetypes.Get(context.Background(), client, id).Extract() + if err != nil { + return resource.DetailsMsg{ + Err: fmt.Errorf("getting share type %q: %w", id, err), + } + } + + return resource.DetailsMsg{ + ID: shareType.ID, + Content: shareType, + } + } +} diff --git a/internal/resources/sharedfilesystem/sharetypes/sharetypes.go b/internal/resources/sharedfilesystem/sharetypes/sharetypes.go new file mode 100644 index 0000000..24a5e64 --- /dev/null +++ b/internal/resources/sharedfilesystem/sharetypes/sharetypes.go @@ -0,0 +1,103 @@ +package sharetypes + +import ( + "context" + "fmt" + "strconv" + + "github.com/akyriako/o7k/internal/openstack" + "github.com/akyriako/o7k/internal/resource" + tea "github.com/charmbracelet/bubbletea" + manilasharetypes "github.com/gophercloud/gophercloud/v2/openstack/sharedfilesystems/v2/sharetypes" +) + +type Resource struct { + context *openstack.Context +} + +func New(context *openstack.Context) *Resource { + return &Resource{context: context} +} + +func (r *Resource) Title() string { + return "Share Types" +} + +func (r *Resource) Kind() string { + return "share-types" +} + +func (r *Resource) Aliases() []string { + return []string{ + "share-type", + } +} + +func (r *Resource) Columns() []resource.Column { + return []resource.Column{ + {Key: "id", Title: "ID", MinWidth: 40, Flex: 0}, + {Key: "name", Title: "NAME", MinWidth: 24, Flex: 1}, + {Key: "is_public", Title: "PUBLIC", MinWidth: 8, Flex: 0}, + {Key: "is_default", Title: "DEFAULT", MinWidth: 8, Flex: 0}, + {Key: "description", Title: "DESCRIPTION", MinWidth: 32, Flex: 2}, + } +} + +func (r *Resource) Commands() []resource.Command { + return []resource.Command{ + {Key: "s", Description: "Show", Default: true}, + } +} + +func (r *Resource) List(ctx context.Context) ([]resource.Row, error) { + client, err := r.context.SharedFileSystemV2() + if err != nil { + return nil, err + } + + pages, err := manilasharetypes.List(client, manilasharetypes.ListOpts{}).AllPages(ctx) + if err != nil { + return nil, fmt.Errorf("listing share types: %w", err) + } + + items, err := manilasharetypes.ExtractShareTypes(pages) + if err != nil { + return nil, fmt.Errorf("extracting share types: %w", err) + } + + rows := make([]resource.Row, 0, len(items)) + + for _, shareType := range items { + description := "" + if shareType.Description != nil { + description = *shareType.Description + } + + isDefault := "" + if shareType.IsDefault != nil { + isDefault = strconv.FormatBool(*shareType.IsDefault) + } + + rows = append(rows, resource.Row{ + ID: shareType.ID, + Fields: map[string]string{ + "id": shareType.ID, + "name": shareType.Name, + "is_public": strconv.FormatBool(shareType.IsPublic), + "is_default": isDefault, + "description": description, + }, + }) + } + + return rows, nil +} + +func (r *Resource) Execute(command resource.Command, row resource.Row) tea.Cmd { + switch command.Key { + case "s": + return r.show(row.ID) + } + + return nil +} diff --git a/internal/resources/sharedfilesystem/snapshots/commands.go b/internal/resources/sharedfilesystem/snapshots/commands.go new file mode 100644 index 0000000..621fbc4 --- /dev/null +++ b/internal/resources/sharedfilesystem/snapshots/commands.go @@ -0,0 +1,31 @@ +package snapshots + +import ( + "context" + "fmt" + + "github.com/akyriako/o7k/internal/resource" + tea "github.com/charmbracelet/bubbletea" + manilasnapshots "github.com/gophercloud/gophercloud/v2/openstack/sharedfilesystems/v2/snapshots" +) + +func (r *Resource) show(id string) tea.Cmd { + return func() tea.Msg { + client, err := r.context.SharedFileSystemV2() + if err != nil { + return resource.DetailsMsg{Err: err} + } + + snapshot, err := manilasnapshots.Get(context.Background(), client, id).Extract() + if err != nil { + return resource.DetailsMsg{ + Err: fmt.Errorf("getting share snapshot %q: %w", id, err), + } + } + + return resource.DetailsMsg{ + ID: snapshot.ID, + Content: snapshot, + } + } +} diff --git a/internal/resources/sharedfilesystem/snapshots/snapshots.go b/internal/resources/sharedfilesystem/snapshots/snapshots.go new file mode 100644 index 0000000..1db9416 --- /dev/null +++ b/internal/resources/sharedfilesystem/snapshots/snapshots.go @@ -0,0 +1,93 @@ +package snapshots + +import ( + "context" + "fmt" + "strconv" + + "github.com/akyriako/o7k/internal/openstack" + "github.com/akyriako/o7k/internal/resource" + tea "github.com/charmbracelet/bubbletea" + manilasnapshots "github.com/gophercloud/gophercloud/v2/openstack/sharedfilesystems/v2/snapshots" +) + +type Resource struct { + context *openstack.Context +} + +func New(context *openstack.Context) *Resource { + return &Resource{context: context} +} + +func (r *Resource) Title() string { + return "Manila Share Snapshots" +} + +func (r *Resource) Kind() string { + return "share-snapshots" +} + +func (r *Resource) Aliases() []string { + return []string{ + "share-snapshot", + } +} + +func (r *Resource) Columns() []resource.Column { + return []resource.Column{ + {Key: "id", Title: "ID", MinWidth: 40, Flex: 0}, + {Key: "name", Title: "NAME", MinWidth: 24, Flex: 1}, + {Key: "status", Title: "STATUS", MinWidth: 12, Flex: 0}, + {Key: "size", Title: "SIZE", MinWidth: 8, Flex: 0}, + {Key: "share_id", Title: "SHARE ID", MinWidth: 40, Flex: 0}, + } +} + +func (r *Resource) Commands() []resource.Command { + return []resource.Command{ + {Key: "s", Description: "Show", Default: true}, + } +} + +func (r *Resource) List(ctx context.Context) ([]resource.Row, error) { + client, err := r.context.SharedFileSystemV2() + if err != nil { + return nil, err + } + + pages, err := manilasnapshots.ListDetail(client, manilasnapshots.ListOpts{}).AllPages(ctx) + if err != nil { + return nil, fmt.Errorf("listing share snapshots: %w", err) + } + + items, err := manilasnapshots.ExtractSnapshots(pages) + if err != nil { + return nil, fmt.Errorf("extracting share snapshots: %w", err) + } + + rows := make([]resource.Row, 0, len(items)) + + for _, snapshot := range items { + rows = append(rows, resource.Row{ + ID: snapshot.ID, + Fields: map[string]string{ + "id": snapshot.ID, + "name": snapshot.Name, + "status": snapshot.Status, + "size": strconv.Itoa(snapshot.Size), + "share_id": snapshot.ShareID, + }, + }) + } + + return rows, nil +} + +func (r *Resource) Execute(command resource.Command, row resource.Row) tea.Cmd { + switch command.Key { + case "s": + return r.show(row.ID) + } + + return nil +}