- Add comprehensive database migrations (001-024) for schema evolution - Enhance API schema with expanded type definitions and resolvers - Add new middleware: audit logging, rate limiting, MFA enforcement, security, tenant auth - Implement new services: AI optimization, billing, blockchain, compliance, marketplace - Add adapter layer for cloud integrations (Cloudflare, Kubernetes, Proxmox, storage) - Update Crossplane provider with enhanced VM management capabilities - Add comprehensive test suite for API endpoints and services - Update frontend components with improved GraphQL subscriptions and real-time updates - Enhance security configurations and headers (CSP, CORS, etc.) - Update documentation and configuration files - Add new CI/CD workflows and validation scripts - Implement design system improvements and UI enhancements
237 lines
6.6 KiB
Go
237 lines
6.6 KiB
Go
package discovery
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/pkg/errors"
|
|
"github.com/sankofa/crossplane-provider-proxmox/pkg/proxmox"
|
|
)
|
|
|
|
// ProxmoxDiscoveryAgent discovers Proxmox resources
|
|
type ProxmoxDiscoveryAgent struct {
|
|
client *proxmox.Client
|
|
site string
|
|
region string
|
|
}
|
|
|
|
// NewProxmoxDiscoveryAgent creates a new Proxmox discovery agent
|
|
func NewProxmoxDiscoveryAgent(client *proxmox.Client, site, region string) *ProxmoxDiscoveryAgent {
|
|
return &ProxmoxDiscoveryAgent{
|
|
client: client,
|
|
site: site,
|
|
region: region,
|
|
}
|
|
}
|
|
|
|
// DiscoveredResource represents a discovered resource
|
|
type DiscoveredResource struct {
|
|
ResourceType string
|
|
Provider string
|
|
ProviderID string
|
|
ProviderResourceID string
|
|
Name string
|
|
Region string
|
|
SiteID string
|
|
Metadata map[string]interface{}
|
|
Tags []string
|
|
}
|
|
|
|
// DiscoverVMs discovers all VMs in the Proxmox cluster
|
|
func (a *ProxmoxDiscoveryAgent) DiscoverVMs(ctx context.Context) ([]DiscoveredResource, error) {
|
|
// Use Proxmox API to list all VMs
|
|
// This requires implementing ListVMs in the Proxmox client
|
|
// For now, we'll make a direct API call
|
|
|
|
// Get cluster nodes first
|
|
nodes, err := a.client.ListNodes(ctx)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to list nodes")
|
|
}
|
|
|
|
var resources []DiscoveredResource
|
|
|
|
// List VMs from each node
|
|
for _, node := range nodes {
|
|
vms, err := a.client.ListVMs(ctx, node)
|
|
if err != nil {
|
|
// Log error but continue with other nodes
|
|
continue
|
|
}
|
|
|
|
for _, vm := range vms {
|
|
resources = append(resources, DiscoveredResource{
|
|
ResourceType: "VM",
|
|
Provider: "PROXMOX",
|
|
ProviderID: fmt.Sprintf("%d", vm.ID),
|
|
ProviderResourceID: fmt.Sprintf("proxmox://nodes/%s/qemu/%d", node, vm.ID),
|
|
Name: vm.Name,
|
|
Region: a.region,
|
|
SiteID: a.site,
|
|
Metadata: map[string]interface{}{
|
|
"node": node,
|
|
"vmId": vm.ID,
|
|
"status": vm.Status,
|
|
"ip": vm.IP,
|
|
"created": vm.Created,
|
|
},
|
|
Tags: []string{fmt.Sprintf("node:%s", node)},
|
|
})
|
|
}
|
|
}
|
|
|
|
return resources, nil
|
|
}
|
|
|
|
// DiscoverStoragePools discovers all storage pools
|
|
func (a *ProxmoxDiscoveryAgent) DiscoverStoragePools(ctx context.Context) ([]DiscoveredResource, error) {
|
|
// List storage pools from Proxmox API
|
|
storages, err := a.client.ListStorages(ctx)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to list storage pools")
|
|
}
|
|
|
|
var resources []DiscoveredResource
|
|
|
|
for _, storage := range storages {
|
|
resources = append(resources, DiscoveredResource{
|
|
ResourceType: "STORAGE",
|
|
Provider: "PROXMOX",
|
|
ProviderID: storage.Name,
|
|
ProviderResourceID: fmt.Sprintf("proxmox://storage/%s", storage.Name),
|
|
Name: storage.Name,
|
|
Region: a.region,
|
|
SiteID: a.site,
|
|
Metadata: map[string]interface{}{
|
|
"type": storage.Type,
|
|
"content": storage.Content,
|
|
"shared": storage.Shared,
|
|
"enabled": storage.Enabled,
|
|
"capacity": storage.Capacity,
|
|
"used": storage.Used,
|
|
},
|
|
Tags: []string{fmt.Sprintf("type:%s", storage.Type)},
|
|
})
|
|
}
|
|
|
|
return resources, nil
|
|
}
|
|
|
|
// DiscoverNetworks discovers all network bridges
|
|
func (a *ProxmoxDiscoveryAgent) DiscoverNetworks(ctx context.Context) ([]DiscoveredResource, error) {
|
|
// Get cluster nodes first
|
|
nodes, err := a.client.ListNodes(ctx)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to list nodes")
|
|
}
|
|
|
|
var resources []DiscoveredResource
|
|
seenNetworks := make(map[string]bool)
|
|
|
|
// List networks from each node
|
|
for _, node := range nodes {
|
|
networks, err := a.client.ListNetworks(ctx, node)
|
|
if err != nil {
|
|
// Log error but continue with other nodes
|
|
continue
|
|
}
|
|
|
|
for _, network := range networks {
|
|
// Avoid duplicates (same network on multiple nodes)
|
|
networkKey := fmt.Sprintf("%s-%s", network.Name, network.Type)
|
|
if seenNetworks[networkKey] {
|
|
continue
|
|
}
|
|
seenNetworks[networkKey] = true
|
|
|
|
resources = append(resources, DiscoveredResource{
|
|
ResourceType: "NETWORK",
|
|
Provider: "PROXMOX",
|
|
ProviderID: network.Name,
|
|
ProviderResourceID: fmt.Sprintf("proxmox://nodes/%s/network/%s", node, network.Name),
|
|
Name: network.Name,
|
|
Region: a.region,
|
|
SiteID: a.site,
|
|
Metadata: map[string]interface{}{
|
|
"node": node,
|
|
"type": network.Type,
|
|
"bridge": network.Bridge,
|
|
"vlan": network.VLAN,
|
|
"active": network.Active,
|
|
"autostart": network.Autostart,
|
|
},
|
|
Tags: []string{fmt.Sprintf("type:%s", network.Type)},
|
|
})
|
|
}
|
|
}
|
|
|
|
return resources, nil
|
|
}
|
|
|
|
// DiscoverClusters discovers Proxmox clusters
|
|
func (a *ProxmoxDiscoveryAgent) DiscoverClusters(ctx context.Context) ([]DiscoveredResource, error) {
|
|
// Get cluster information
|
|
clusterInfo, err := a.client.GetClusterInfo(ctx)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to get cluster info")
|
|
}
|
|
|
|
var resources []DiscoveredResource
|
|
|
|
// Add cluster as a resource
|
|
resources = append(resources, DiscoveredResource{
|
|
ResourceType: "CLUSTER",
|
|
Provider: "PROXMOX",
|
|
ProviderID: clusterInfo.Name,
|
|
ProviderResourceID: fmt.Sprintf("proxmox://cluster/%s", clusterInfo.Name),
|
|
Name: clusterInfo.Name,
|
|
Region: a.region,
|
|
SiteID: a.site,
|
|
Metadata: map[string]interface{}{
|
|
"nodes": clusterInfo.Nodes,
|
|
"quorum": clusterInfo.Quorum,
|
|
"version": clusterInfo.Version,
|
|
"nodeCount": len(clusterInfo.Nodes),
|
|
},
|
|
Tags: []string{"cluster"},
|
|
})
|
|
|
|
return resources, nil
|
|
}
|
|
|
|
// DiscoverAll discovers all Proxmox resources
|
|
func (a *ProxmoxDiscoveryAgent) DiscoverAll(ctx context.Context) ([]DiscoveredResource, error) {
|
|
var allResources []DiscoveredResource
|
|
|
|
// Discover VMs
|
|
vms, err := a.DiscoverVMs(ctx)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to discover VMs")
|
|
}
|
|
allResources = append(allResources, vms...)
|
|
|
|
// Discover storage pools
|
|
storagePools, err := a.DiscoverStoragePools(ctx)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to discover storage pools")
|
|
}
|
|
allResources = append(allResources, storagePools...)
|
|
|
|
// Discover networks
|
|
networks, err := a.DiscoverNetworks(ctx)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to discover networks")
|
|
}
|
|
allResources = append(allResources, networks...)
|
|
|
|
// Discover clusters
|
|
clusters, err := a.DiscoverClusters(ctx)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to discover clusters")
|
|
}
|
|
allResources = append(allResources, clusters...)
|
|
|
|
return allResources, nil
|
|
}
|
|
|