diff --git a/docs/tables/gcp_kubernetes_cluster.md b/docs/tables/gcp_kubernetes_cluster.md index 2d8d7de3..0ef56be3 100644 --- a/docs/tables/gcp_kubernetes_cluster.md +++ b/docs/tables/gcp_kubernetes_cluster.md @@ -103,22 +103,22 @@ Identify instances where clusters are using the default service account in Googl select name, location_type, - node_config ->> 'serviceAccount' service_account + node_config ->> 'ServiceAccount' service_account from gcp_kubernetes_cluster where - node_config ->> 'serviceAccount' = 'default'; + node_config ->> 'ServiceAccount' = 'default'; ``` ```sql+sqlite select name, location_type, - json_extract(node_config, '$.serviceAccount') service_account + json_extract(node_config, '$.ServiceAccount') service_account from gcp_kubernetes_cluster where - json_extract(node_config, '$.serviceAccount') = 'default'; + json_extract(node_config, '$.ServiceAccount') = 'default'; ``` ### List clusters with legacy authorization enabled @@ -200,14 +200,14 @@ Explore the configuration settings of your clusters to understand their disk siz ```sql+postgres select name, - node_config ->> 'diskSizeGb' as disk_size_gb, - node_config ->> 'diskType' as disk_type, - node_config ->> 'imageType' as image_type, - node_config ->> 'machineType' as machine_type, - node_config ->> 'diskType' as disk_type, - node_config -> 'metadata' ->> 'disable-legacy-endpoints' as disable_legacy_endpoints, - node_config ->> 'serviceAccount' as service_account, - node_config -> 'shieldedInstanceConfig' ->> 'enableIntegrityMonitoring' as enable_integrity_monitoring + node_config ->> 'Disksizegb' as disk_size_gb, + node_config ->> 'Disktype' as disk_type, + node_config ->> 'Imagetype' as image_type, + node_config ->> 'Machinetype' as machine_type, + node_config ->> 'Disktype' as disk_type, + node_config -> 'Metadata' ->> 'disable-legacy-endpoints' as disable_legacy_endpoints, + node_config ->> 'Serviceaccount' as service_account, + node_config -> 'Shieldedinstanceconfig' ->> 'EnableIntegrityMonitoring' as enable_integrity_monitoring from gcp_kubernetes_cluster; ``` @@ -215,14 +215,14 @@ from ```sql+sqlite select name, - json_extract(node_config, '$.diskSizeGb') as disk_size_gb, - json_extract(node_config, '$.diskType') as disk_type, - json_extract(node_config, '$.imageType') as image_type, - json_extract(node_config, '$.machineType') as machine_type, - json_extract(node_config, '$.diskType') as disk_type, - json_extract(json_extract(node_config, '$.metadata'), '$.disable-legacy-endpoints') as disable_legacy_endpoints, - json_extract(node_config, '$.serviceAccount') as service_account, - json_extract(json_extract(node_config, '$.shieldedInstanceConfig'), '$.enableIntegrityMonitoring') as enable_integrity_monitoring + json_extract(node_config, '$.Disksizegb') as disk_size_gb, + json_extract(node_config, '$.Disktype') as disk_type, + json_extract(node_config, '$.Imagetype') as image_type, + json_extract(node_config, '$.Machinetype') as machine_type, + json_extract(node_config, '$.Disktype') as disk_type, + json_extract(json_extract(node_config, '$.Metadata'), '$.disable-legacy-endpoints') as disable_legacy_endpoints, + json_extract(node_config, '$.ServiceAccount') as service_account, + json_extract(json_extract(node_config, '$.ShieldedInstanceConfig'), '$.EnableIntegrityMonitoring') as enable_integrity_monitoring from gcp_kubernetes_cluster; ``` \ No newline at end of file diff --git a/gcp-test/tests/gcp_kubernetes_cluster/test-invalid-name-expected.json b/gcp-test/tests/gcp_kubernetes_cluster/test-invalid-name-expected.json index ec747fa4..0637a088 100644 --- a/gcp-test/tests/gcp_kubernetes_cluster/test-invalid-name-expected.json +++ b/gcp-test/tests/gcp_kubernetes_cluster/test-invalid-name-expected.json @@ -1 +1 @@ -null \ No newline at end of file +[] \ No newline at end of file diff --git a/gcp-test/tests/gcp_kubernetes_cluster/test-not-found-expected.json b/gcp-test/tests/gcp_kubernetes_cluster/test-not-found-expected.json index ec747fa4..0637a088 100644 --- a/gcp-test/tests/gcp_kubernetes_cluster/test-not-found-expected.json +++ b/gcp-test/tests/gcp_kubernetes_cluster/test-not-found-expected.json @@ -1 +1 @@ -null \ No newline at end of file +[] \ No newline at end of file diff --git a/gcp/table_gcp_kubernetes_cluster.go b/gcp/table_gcp_kubernetes_cluster.go index 4d2fe499..a98b040e 100644 --- a/gcp/table_gcp_kubernetes_cluster.go +++ b/gcp/table_gcp_kubernetes_cluster.go @@ -2,6 +2,8 @@ package gcp import ( "context" + "encoding/json" + "reflect" "strings" "github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto" @@ -201,6 +203,7 @@ func tableGcpKubernetesCluster(ctx context.Context) *plugin.Table { Name: "addons_config", Description: "Configurations for the various addons available to run in the cluster.", Type: proto.ColumnType_JSON, + Transform: transform.From(gcpKubernetesClusterAddonConfig), }, { Name: "authenticator_groups_config", @@ -256,6 +259,7 @@ func tableGcpKubernetesCluster(ctx context.Context) *plugin.Table { Name: "network_config", Description: "Configuration for cluster networking.", Type: proto.ColumnType_JSON, + Transform: transform.From(gcpKubernetesClusterNetworkConfig), }, { Name: "network_policy", @@ -266,6 +270,7 @@ func tableGcpKubernetesCluster(ctx context.Context) *plugin.Table { Name: "node_config", Description: "Parameters used in creating the cluster's nodes.", Type: proto.ColumnType_JSON, + Transform: transform.From(gcpKubernetesClusterNodeConfig), }, { Name: "node_pools", @@ -428,6 +433,36 @@ func gcpKubernetesClusterTurbotData(ctx context.Context, d *transform.TransformD return result[d.Param.(string)], nil } +func gcpKubernetesClusterAddonConfig(ctx context.Context, d *transform.TransformData) (interface{}, error) { + cluster := d.HydrateItem.(*container.Cluster) + + result := make(map[string]interface{}) + extractNonNilFields(reflect.ValueOf(cluster.AddonsConfig), result) + jsonResult, _ := json.MarshalIndent(result, "", " ") + + return string(jsonResult), nil +} + +func gcpKubernetesClusterNetworkConfig(ctx context.Context, d *transform.TransformData) (interface{}, error) { + cluster := d.HydrateItem.(*container.Cluster) + + result := make(map[string]interface{}) + extractNonNilFields(reflect.ValueOf(cluster.NetworkConfig), result) + jsonResult, _ := json.MarshalIndent(result, "", " ") + + return string(jsonResult), nil +} + +func gcpKubernetesClusterNodeConfig(ctx context.Context, d *transform.TransformData) (interface{}, error) { + cluster := d.HydrateItem.(*container.Cluster) + + result := make(map[string]interface{}) + extractNonNilFields(reflect.ValueOf(cluster.NodeConfig), result) + jsonResult, _ := json.MarshalIndent(result, "", " ") + + return string(jsonResult), nil +} + func gcpKubernetesClusterLocationType(ctx context.Context, d *transform.TransformData) (interface{}, error) { plugin.Logger(ctx).Trace("gcpKubernetesClusterLocationType") cluster := d.HydrateItem.(*container.Cluster) @@ -439,3 +474,41 @@ func gcpKubernetesClusterLocationType(ctx context.Context, d *transform.Transfor } return "ZONAL", nil } + +//// UTILITY FUNCTION + +func extractNonNilFields(val reflect.Value, result map[string]interface{}) { + if val.Kind() == reflect.Ptr { + val = val.Elem() + } + + if val.Kind() != reflect.Struct { + return + } + + for i := 0; i < val.NumField(); i++ { + field := val.Field(i) + typeField := val.Type().Field(i) + + fieldName := typeField.Name + + if field.Kind() == reflect.Ptr { + if !field.IsNil() { + // Create a nested map for each non-nil struct + nestedMap := make(map[string]interface{}) + result[fieldName] = nestedMap + extractNonNilFields(field, nestedMap) + } else { + if fieldName != "NullFields" && fieldName != "ForceSendFields" { + // If the pointer is nil, create an empty map + result[fieldName] = make(map[string]interface{}) + } + } + } else { + if fieldName != "NullFields" && fieldName != "ForceSendFields" { + // For non-pointer types, add directly to the map + result[fieldName] = field.Interface() + } + } + } +}