diff --git a/cmd/aks-periscope/aks-periscope.go b/cmd/aks-periscope/aks-periscope.go index 376adafe..85d1fc80 100644 --- a/cmd/aks-periscope/aks-periscope.go +++ b/cmd/aks-periscope/aks-periscope.go @@ -53,6 +53,7 @@ func main() { systemPerfCollector := collector.NewSystemPerfCollector() helmCollector := collector.NewHelmCollector() osmCollector := collector.NewOsmCollector() + smiCollector := collector.NewSmiCollector() collectors := []interfaces.Collector{ containerLogsCollector, @@ -71,8 +72,12 @@ func main() { collectors = append(collectors, systemPerfCollector) } + // OSM and SMI flags are mutually exclusive if contains(collectorList, "OSM") { collectors = append(collectors, osmCollector) + collectors = append(collectors, smiCollector) + } else if contains(collectorList, "SMI") { + collectors = append(collectors, smiCollector) } collectorGrp := new(sync.WaitGroup) diff --git a/deployment/cluster-role.yaml b/deployment/cluster-role.yaml index cd58e155..d817103d 100644 --- a/deployment/cluster-role.yaml +++ b/deployment/cluster-role.yaml @@ -9,3 +9,9 @@ rules: - apiGroups: ["aks-periscope.azure.github.com"] resources: ["diagnostics"] verbs: ["get", "watch", "list", "create", "patch"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get", "list", "watch"] +- apiGroups: ["access.smi-spec.io", "specs.smi-spec.io", "split.smi-spec.io"] + resources: ["*"] + verbs: ["get", "list", "watch"] diff --git a/pkg/collector/smi_collector.go b/pkg/collector/smi_collector.go new file mode 100644 index 00000000..712c0f93 --- /dev/null +++ b/pkg/collector/smi_collector.go @@ -0,0 +1,96 @@ +package collector + +import ( + "errors" + "fmt" + "log" + "strings" + + "github.com/Azure/aks-periscope/pkg/utils" +) + +// SmiCollector defines an Smi Collector struct +type SmiCollector struct { + data map[string]string +} + +// NewSmiCollector is a constructor +func NewSmiCollector() *SmiCollector { + return &SmiCollector{ + data: make(map[string]string), + } +} + +func (collector *SmiCollector) GetName() string { + return "smi" +} + +func (collector *SmiCollector) GetData() map[string]string { + return collector.data +} + +// Collect implements the interface method +func (collector *SmiCollector) Collect() error { + // Get all CustomResourceDefinitions in the cluster + allCrdsList, err := utils.GetResourceList([]string{"get", "crds", "-o", "jsonpath={..metadata.name}"}, " ") + if err != nil { + return err + } + + // Filter to obtain a list of Smi CustomResourceDefinitions in the cluster + var smiCrdsList []string + for _, s := range allCrdsList { + if strings.Contains(s, "smi-spec.io") { + smiCrdsList = append(smiCrdsList, s) + } + } + if len(smiCrdsList) == 0 { + return errors.New("cluster does not contain any SMI CRDs") + } + + collectSmiCrds(collector, smiCrdsList) + return collectSmiCustomResourcesFromAllNamespaces(collector, smiCrdsList) +} + +func collectSmiCrds(collector *SmiCollector, smiCrdsList []string) { + for _, smiCrd := range smiCrdsList { + yamlDefinition, err := utils.RunCommandOnContainer("kubectl", "get", "crd", smiCrd, "-o", "yaml") + if err != nil { + log.Printf("Skipping: unable to collect yaml definition of %s: %+v", smiCrd, err) + } + collector.data["smi_crd_definition_"+smiCrd] = yamlDefinition + } +} + +func collectSmiCustomResourcesFromAllNamespaces(collector *SmiCollector, smiCrdsList []string) error { + // Get all namespaces in the cluster + namespacesList, err := utils.GetResourceList([]string{"get", "namespaces", "-o", "jsonpath={..metadata.name}"}, " ") + if err != nil { + return fmt.Errorf("collect SMI custom resources: unable to list namespaces in the cluster: %w", err) + } + + for _, namespace := range namespacesList { + collectSmiCustomResourcesFromNamespace(collector, smiCrdsList, namespace) + } + + return nil +} + +func collectSmiCustomResourcesFromNamespace(collector *SmiCollector, smiCrdsList []string, namespace string) { + for _, smiCrdType := range smiCrdsList { + // get all custom resources of this smi crd type + customResourcesList, err := utils.GetResourceList([]string{"get", smiCrdType, "-n", namespace, "-o", "jsonpath={..metadata.name}"}, " ") + if err != nil { + log.Printf("Skipping: unable to list custom resources of type %s in namespace %s: %+v", smiCrdType, namespace, err) + continue + } + + for _, customResourceName := range customResourcesList { + yamlDefinition, err := utils.RunCommandOnContainer("kubectl", "get", smiCrdType, customResourceName, "-n", namespace, "-o", "yaml") + if err != nil { + log.Printf("Skipping: unable to collect yaml definition of %s (custom resource type: %s): %+v", customResourceName, smiCrdType, err) + } + collector.data["namespace_"+namespace+"_"+smiCrdType+"_custom_resource_"+customResourceName] = yamlDefinition + } + } +}