Compare commits

...

4 Commits

Author SHA1 Message Date
nikhilmantri0902
4e0d9efe06 Merge branch 'main' into infraM/meta_maps_strong_typing
# Conflicts:
#	docs/api/openapi.yml
#	frontend/src/api/generated/services/sigNoz.schemas.ts
2026-08-04 12:52:02 +05:30
nikhilmantri0902
dff443f68c chore: added tests 2026-07-21 20:21:55 +05:30
nikhilmantri0902
dadec2acc4 chore: using the type directly instead of a middle variable 2026-07-21 19:49:04 +05:30
nikhilmantri0902
51edea502d chore: strong typing added for meta map 2026-07-21 19:30:59 +05:30
37 changed files with 1220 additions and 341 deletions

View File

@@ -4212,6 +4212,15 @@ components:
- missingOptionalMetrics
- missingRequiredAttributes
type: object
InframonitoringtypesClusterMeta:
additionalProperties:
type: string
properties:
k8s.cluster.name:
type: string
required:
- k8s.cluster.name
type: object
InframonitoringtypesClusterRecord:
properties:
clusterCPU:
@@ -4257,10 +4266,7 @@ components:
- statefulSets
type: object
meta:
additionalProperties:
type: string
nullable: true
type: object
$ref: '#/components/schemas/InframonitoringtypesClusterMeta'
nodeCountsByReadiness:
$ref: '#/components/schemas/InframonitoringtypesNodeCountsByReadiness'
podCountsByStatus:
@@ -4349,6 +4355,51 @@ components:
- containerCannotRun
- unknown
type: object
InframonitoringtypesContainerMeta:
additionalProperties:
type: string
properties:
container.image.name:
type: string
container.image.tag:
type: string
k8s.cluster.name:
type: string
k8s.container.name:
type: string
k8s.cronjob.name:
type: string
k8s.daemonset.name:
type: string
k8s.deployment.name:
type: string
k8s.job.name:
type: string
k8s.namespace.name:
type: string
k8s.node.name:
type: string
k8s.pod.name:
type: string
k8s.pod.uid:
type: string
k8s.statefulset.name:
type: string
required:
- k8s.pod.uid
- k8s.container.name
- k8s.pod.name
- container.image.name
- container.image.tag
- k8s.namespace.name
- k8s.node.name
- k8s.deployment.name
- k8s.statefulset.name
- k8s.daemonset.name
- k8s.job.name
- k8s.cronjob.name
- k8s.cluster.name
type: object
InframonitoringtypesContainerReady:
enum:
- ready
@@ -4382,10 +4433,7 @@ components:
format: double
type: number
meta:
additionalProperties:
type: string
nullable: true
type: object
$ref: '#/components/schemas/InframonitoringtypesContainerMeta'
podUID:
type: string
ready:
@@ -4448,6 +4496,21 @@ components:
- total
- endTimeBeforeRetention
type: object
InframonitoringtypesDaemonSetMeta:
additionalProperties:
type: string
properties:
k8s.cluster.name:
type: string
k8s.daemonset.name:
type: string
k8s.namespace.name:
type: string
required:
- k8s.daemonset.name
- k8s.namespace.name
- k8s.cluster.name
type: object
InframonitoringtypesDaemonSetRecord:
properties:
currentNodes:
@@ -4475,10 +4538,7 @@ components:
desiredNodes:
type: integer
meta:
additionalProperties:
type: string
nullable: true
type: object
$ref: '#/components/schemas/InframonitoringtypesDaemonSetMeta'
misscheduledNodes:
type: integer
podCountsByStatus:
@@ -4520,6 +4580,21 @@ components:
- total
- endTimeBeforeRetention
type: object
InframonitoringtypesDeploymentMeta:
additionalProperties:
type: string
properties:
k8s.cluster.name:
type: string
k8s.deployment.name:
type: string
k8s.namespace.name:
type: string
required:
- k8s.deployment.name
- k8s.namespace.name
- k8s.cluster.name
type: object
InframonitoringtypesDeploymentRecord:
properties:
availablePods:
@@ -4547,10 +4622,7 @@ components:
desiredPods:
type: integer
meta:
additionalProperties:
type: string
nullable: true
type: object
$ref: '#/components/schemas/InframonitoringtypesDeploymentMeta'
podCountsByStatus:
$ref: '#/components/schemas/InframonitoringtypesPodCountsByStatus'
required:
@@ -4593,6 +4665,18 @@ components:
filterByStatus:
$ref: '#/components/schemas/InframonitoringtypesHostStatus'
type: object
InframonitoringtypesHostMeta:
additionalProperties:
type: string
properties:
host.name:
type: string
os.type:
type: string
required:
- os.type
- host.name
type: object
InframonitoringtypesHostRecord:
properties:
activeHostCount:
@@ -4614,10 +4698,7 @@ components:
format: double
type: number
meta:
additionalProperties:
type: string
nullable: true
type: object
$ref: '#/components/schemas/InframonitoringtypesHostMeta'
status:
$ref: '#/components/schemas/InframonitoringtypesHostStatus'
wait:
@@ -4661,6 +4742,21 @@ components:
- total
- endTimeBeforeRetention
type: object
InframonitoringtypesJobMeta:
additionalProperties:
type: string
properties:
k8s.cluster.name:
type: string
k8s.job.name:
type: string
k8s.namespace.name:
type: string
required:
- k8s.job.name
- k8s.namespace.name
- k8s.cluster.name
type: object
InframonitoringtypesJobRecord:
properties:
activePods:
@@ -4690,10 +4786,7 @@ components:
jobName:
type: string
meta:
additionalProperties:
type: string
nullable: true
type: object
$ref: '#/components/schemas/InframonitoringtypesJobMeta'
podCountsByStatus:
$ref: '#/components/schemas/InframonitoringtypesPodCountsByStatus'
successfulPods:
@@ -4784,6 +4877,18 @@ components:
- message
- documentationLink
type: object
InframonitoringtypesNamespaceMeta:
additionalProperties:
type: string
properties:
k8s.cluster.name:
type: string
k8s.namespace.name:
type: string
required:
- k8s.namespace.name
- k8s.cluster.name
type: object
InframonitoringtypesNamespaceRecord:
properties:
counts:
@@ -4807,10 +4912,7 @@ components:
- statefulSets
type: object
meta:
additionalProperties:
type: string
nullable: true
type: object
$ref: '#/components/schemas/InframonitoringtypesNamespaceMeta'
namespaceCPU:
format: double
type: number
@@ -4865,15 +4967,27 @@ components:
- ready
- notReady
type: object
InframonitoringtypesNodeMeta:
additionalProperties:
type: string
properties:
k8s.cluster.name:
type: string
k8s.node.name:
type: string
k8s.node.uid:
type: string
required:
- k8s.node.uid
- k8s.cluster.name
- k8s.node.name
type: object
InframonitoringtypesNodeRecord:
properties:
condition:
$ref: '#/components/schemas/InframonitoringtypesNodeCondition'
meta:
additionalProperties:
type: string
nullable: true
type: object
$ref: '#/components/schemas/InframonitoringtypesNodeMeta'
nodeCPU:
format: double
type: number
@@ -4981,13 +5095,49 @@ components:
- shutdown
- unexpectedAdmissionError
type: object
InframonitoringtypesPodMeta:
additionalProperties:
type: string
properties:
k8s.cluster.name:
type: string
k8s.cronjob.name:
type: string
k8s.daemonset.name:
type: string
k8s.deployment.name:
type: string
k8s.job.name:
type: string
k8s.namespace.name:
type: string
k8s.node.name:
type: string
k8s.pod.name:
type: string
k8s.pod.start_time:
type: string
k8s.pod.uid:
type: string
k8s.statefulset.name:
type: string
required:
- k8s.pod.uid
- k8s.pod.name
- k8s.namespace.name
- k8s.node.name
- k8s.deployment.name
- k8s.statefulset.name
- k8s.daemonset.name
- k8s.job.name
- k8s.cronjob.name
- k8s.cluster.name
- k8s.pod.start_time
type: object
InframonitoringtypesPodRecord:
properties:
meta:
additionalProperties:
type: string
nullable: true
type: object
$ref: '#/components/schemas/InframonitoringtypesPodMeta'
podAge:
format: int64
type: integer
@@ -5365,6 +5515,21 @@ components:
- list
- grouped_list
type: string
InframonitoringtypesStatefulSetMeta:
additionalProperties:
type: string
properties:
k8s.cluster.name:
type: string
k8s.namespace.name:
type: string
k8s.statefulset.name:
type: string
required:
- k8s.statefulset.name
- k8s.namespace.name
- k8s.cluster.name
type: object
InframonitoringtypesStatefulSetRecord:
properties:
currentPods:
@@ -5372,10 +5537,7 @@ components:
desiredPods:
type: integer
meta:
additionalProperties:
type: string
nullable: true
type: object
$ref: '#/components/schemas/InframonitoringtypesStatefulSetMeta'
podCountsByStatus:
$ref: '#/components/schemas/InframonitoringtypesPodCountsByStatus'
statefulSetCPU:
@@ -5431,13 +5593,37 @@ components:
- total
- endTimeBeforeRetention
type: object
InframonitoringtypesVolumeMeta:
additionalProperties:
type: string
properties:
k8s.cluster.name:
type: string
k8s.namespace.name:
type: string
k8s.node.name:
type: string
k8s.persistentvolumeclaim.name:
type: string
k8s.pod.name:
type: string
k8s.pod.uid:
type: string
k8s.statefulset.name:
type: string
required:
- k8s.persistentvolumeclaim.name
- k8s.pod.uid
- k8s.pod.name
- k8s.namespace.name
- k8s.node.name
- k8s.statefulset.name
- k8s.cluster.name
type: object
InframonitoringtypesVolumeRecord:
properties:
meta:
additionalProperties:
type: string
nullable: true
type: object
$ref: '#/components/schemas/InframonitoringtypesVolumeMeta'
persistentVolumeClaimName:
type: string
volumeAvailable:

View File

@@ -5635,6 +5635,14 @@ export interface InframonitoringtypesChecksDTO {
type: InframonitoringtypesCheckTypeDTO;
}
export interface InframonitoringtypesClusterMetaDTO {
/**
* @type string
*/
'k8s.cluster.name': string;
[key: string]: string;
}
export type InframonitoringtypesClusterRecordDTOCounts = {
/**
* @type integer
@@ -5668,16 +5676,6 @@ export type InframonitoringtypesClusterRecordDTOCounts = {
statefulSets: number;
};
export type InframonitoringtypesClusterRecordDTOMetaAnyOf = {
[key: string]: string;
};
/**
* @nullable
*/
export type InframonitoringtypesClusterRecordDTOMeta =
InframonitoringtypesClusterRecordDTOMetaAnyOf | null;
export interface InframonitoringtypesNodeCountsByReadinessDTO {
/**
* @type integer
@@ -5793,10 +5791,7 @@ export interface InframonitoringtypesClusterRecordDTO {
* @type object
*/
counts: InframonitoringtypesClusterRecordDTOCounts;
/**
* @type object,null
*/
meta: InframonitoringtypesClusterRecordDTOMeta;
meta: InframonitoringtypesClusterMetaDTO;
nodeCountsByReadiness: InframonitoringtypesNodeCountsByReadinessDTO;
podCountsByStatus: InframonitoringtypesPodCountsByStatusDTO;
}
@@ -5910,21 +5905,67 @@ export interface InframonitoringtypesContainerCountsByStatusDTO {
waiting: number;
}
export interface InframonitoringtypesContainerMetaDTO {
/**
* @type string
*/
'container.image.name': string;
/**
* @type string
*/
'container.image.tag': string;
/**
* @type string
*/
'k8s.cluster.name': string;
/**
* @type string
*/
'k8s.container.name': string;
/**
* @type string
*/
'k8s.cronjob.name': string;
/**
* @type string
*/
'k8s.daemonset.name': string;
/**
* @type string
*/
'k8s.deployment.name': string;
/**
* @type string
*/
'k8s.job.name': string;
/**
* @type string
*/
'k8s.namespace.name': string;
/**
* @type string
*/
'k8s.node.name': string;
/**
* @type string
*/
'k8s.pod.name': string;
/**
* @type string
*/
'k8s.pod.uid': string;
/**
* @type string
*/
'k8s.statefulset.name': string;
[key: string]: string;
}
export enum InframonitoringtypesContainerReadyDTO {
ready = 'ready',
not_ready = 'not_ready',
no_data = 'no_data',
}
export type InframonitoringtypesContainerRecordDTOMetaAnyOf = {
[key: string]: string;
};
/**
* @nullable
*/
export type InframonitoringtypesContainerRecordDTOMeta =
InframonitoringtypesContainerRecordDTOMetaAnyOf | null;
export enum InframonitoringtypesContainerStatusDTO {
running = 'running',
waiting = 'waiting',
@@ -5978,10 +6019,7 @@ export interface InframonitoringtypesContainerRecordDTO {
* @format double
*/
memoryRequestUtilization: number;
/**
* @type object,null
*/
meta: InframonitoringtypesContainerRecordDTOMeta;
meta: InframonitoringtypesContainerMetaDTO;
/**
* @type string
*/
@@ -6012,15 +6050,21 @@ export interface InframonitoringtypesContainersDTO {
warning?: Querybuildertypesv5QueryWarnDataDTO;
}
export type InframonitoringtypesDaemonSetRecordDTOMetaAnyOf = {
export interface InframonitoringtypesDaemonSetMetaDTO {
/**
* @type string
*/
'k8s.cluster.name': string;
/**
* @type string
*/
'k8s.daemonset.name': string;
/**
* @type string
*/
'k8s.namespace.name': string;
[key: string]: string;
};
/**
* @nullable
*/
export type InframonitoringtypesDaemonSetRecordDTOMeta =
InframonitoringtypesDaemonSetRecordDTOMetaAnyOf | null;
}
export interface InframonitoringtypesDaemonSetRecordDTO {
/**
@@ -6065,10 +6109,7 @@ export interface InframonitoringtypesDaemonSetRecordDTO {
* @type integer
*/
desiredNodes: number;
/**
* @type object,null
*/
meta: InframonitoringtypesDaemonSetRecordDTOMeta;
meta: InframonitoringtypesDaemonSetMetaDTO;
/**
* @type integer
*/
@@ -6097,15 +6138,21 @@ export interface InframonitoringtypesDaemonSetsDTO {
warning?: Querybuildertypesv5QueryWarnDataDTO;
}
export type InframonitoringtypesDeploymentRecordDTOMetaAnyOf = {
export interface InframonitoringtypesDeploymentMetaDTO {
/**
* @type string
*/
'k8s.cluster.name': string;
/**
* @type string
*/
'k8s.deployment.name': string;
/**
* @type string
*/
'k8s.namespace.name': string;
[key: string]: string;
};
/**
* @nullable
*/
export type InframonitoringtypesDeploymentRecordDTOMeta =
InframonitoringtypesDeploymentRecordDTOMetaAnyOf | null;
}
export interface InframonitoringtypesDeploymentRecordDTO {
/**
@@ -6150,10 +6197,7 @@ export interface InframonitoringtypesDeploymentRecordDTO {
* @type integer
*/
desiredPods: number;
/**
* @type object,null
*/
meta: InframonitoringtypesDeploymentRecordDTOMeta;
meta: InframonitoringtypesDeploymentMetaDTO;
podCountsByStatus: InframonitoringtypesPodCountsByStatusDTO;
}
@@ -6187,15 +6231,17 @@ export interface InframonitoringtypesHostFilterDTO {
filterByStatus?: InframonitoringtypesHostStatusDTO;
}
export type InframonitoringtypesHostRecordDTOMetaAnyOf = {
export interface InframonitoringtypesHostMetaDTO {
/**
* @type string
*/
'host.name': string;
/**
* @type string
*/
'os.type': string;
[key: string]: string;
};
/**
* @nullable
*/
export type InframonitoringtypesHostRecordDTOMeta =
InframonitoringtypesHostRecordDTOMetaAnyOf | null;
}
export interface InframonitoringtypesHostRecordDTO {
/**
@@ -6230,10 +6276,7 @@ export interface InframonitoringtypesHostRecordDTO {
* @format double
*/
memory: number;
/**
* @type object,null
*/
meta: InframonitoringtypesHostRecordDTOMeta;
meta: InframonitoringtypesHostMetaDTO;
status: InframonitoringtypesHostStatusDTO;
/**
* @type number
@@ -6259,15 +6302,21 @@ export interface InframonitoringtypesHostsDTO {
warning?: Querybuildertypesv5QueryWarnDataDTO;
}
export type InframonitoringtypesJobRecordDTOMetaAnyOf = {
export interface InframonitoringtypesJobMetaDTO {
/**
* @type string
*/
'k8s.cluster.name': string;
/**
* @type string
*/
'k8s.job.name': string;
/**
* @type string
*/
'k8s.namespace.name': string;
[key: string]: string;
};
/**
* @nullable
*/
export type InframonitoringtypesJobRecordDTOMeta =
InframonitoringtypesJobRecordDTOMetaAnyOf | null;
}
export interface InframonitoringtypesJobRecordDTO {
/**
@@ -6316,10 +6365,7 @@ export interface InframonitoringtypesJobRecordDTO {
* @type string
*/
jobName: string;
/**
* @type object,null
*/
meta: InframonitoringtypesJobRecordDTOMeta;
meta: InframonitoringtypesJobMetaDTO;
podCountsByStatus: InframonitoringtypesPodCountsByStatusDTO;
/**
* @type integer
@@ -6344,6 +6390,18 @@ export interface InframonitoringtypesJobsDTO {
warning?: Querybuildertypesv5QueryWarnDataDTO;
}
export interface InframonitoringtypesNamespaceMetaDTO {
/**
* @type string
*/
'k8s.cluster.name': string;
/**
* @type string
*/
'k8s.namespace.name': string;
[key: string]: string;
}
export type InframonitoringtypesNamespaceRecordDTOCounts = {
/**
* @type integer
@@ -6367,25 +6425,12 @@ export type InframonitoringtypesNamespaceRecordDTOCounts = {
statefulSets: number;
};
export type InframonitoringtypesNamespaceRecordDTOMetaAnyOf = {
[key: string]: string;
};
/**
* @nullable
*/
export type InframonitoringtypesNamespaceRecordDTOMeta =
InframonitoringtypesNamespaceRecordDTOMetaAnyOf | null;
export interface InframonitoringtypesNamespaceRecordDTO {
/**
* @type object
*/
counts: InframonitoringtypesNamespaceRecordDTOCounts;
/**
* @type object,null
*/
meta: InframonitoringtypesNamespaceRecordDTOMeta;
meta: InframonitoringtypesNamespaceMetaDTO;
/**
* @type number
* @format double
@@ -6425,22 +6470,25 @@ export enum InframonitoringtypesNodeConditionDTO {
not_ready = 'not_ready',
no_data = 'no_data',
}
export type InframonitoringtypesNodeRecordDTOMetaAnyOf = {
export interface InframonitoringtypesNodeMetaDTO {
/**
* @type string
*/
'k8s.cluster.name': string;
/**
* @type string
*/
'k8s.node.name': string;
/**
* @type string
*/
'k8s.node.uid': string;
[key: string]: string;
};
/**
* @nullable
*/
export type InframonitoringtypesNodeRecordDTOMeta =
InframonitoringtypesNodeRecordDTOMetaAnyOf | null;
}
export interface InframonitoringtypesNodeRecordDTO {
condition: InframonitoringtypesNodeConditionDTO;
/**
* @type object,null
*/
meta: InframonitoringtypesNodeRecordDTOMeta;
meta: InframonitoringtypesNodeMetaDTO;
/**
* @type number
* @format double
@@ -6486,15 +6534,53 @@ export interface InframonitoringtypesNodesDTO {
warning?: Querybuildertypesv5QueryWarnDataDTO;
}
export type InframonitoringtypesPodRecordDTOMetaAnyOf = {
export interface InframonitoringtypesPodMetaDTO {
/**
* @type string
*/
'k8s.cluster.name': string;
/**
* @type string
*/
'k8s.cronjob.name': string;
/**
* @type string
*/
'k8s.daemonset.name': string;
/**
* @type string
*/
'k8s.deployment.name': string;
/**
* @type string
*/
'k8s.job.name': string;
/**
* @type string
*/
'k8s.namespace.name': string;
/**
* @type string
*/
'k8s.node.name': string;
/**
* @type string
*/
'k8s.pod.name': string;
/**
* @type string
*/
'k8s.pod.start_time': string;
/**
* @type string
*/
'k8s.pod.uid': string;
/**
* @type string
*/
'k8s.statefulset.name': string;
[key: string]: string;
};
/**
* @nullable
*/
export type InframonitoringtypesPodRecordDTOMeta =
InframonitoringtypesPodRecordDTOMetaAnyOf | null;
}
export enum InframonitoringtypesPodStatusDTO {
pending = 'pending',
@@ -6518,10 +6604,7 @@ export enum InframonitoringtypesPodStatusDTO {
no_data = 'no_data',
}
export interface InframonitoringtypesPodRecordDTO {
/**
* @type object,null
*/
meta: InframonitoringtypesPodRecordDTOMeta;
meta: InframonitoringtypesPodMetaDTO;
/**
* @type integer
* @format int64
@@ -6884,15 +6967,21 @@ export interface InframonitoringtypesPostableVolumesDTO {
start: number;
}
export type InframonitoringtypesStatefulSetRecordDTOMetaAnyOf = {
export interface InframonitoringtypesStatefulSetMetaDTO {
/**
* @type string
*/
'k8s.cluster.name': string;
/**
* @type string
*/
'k8s.namespace.name': string;
/**
* @type string
*/
'k8s.statefulset.name': string;
[key: string]: string;
};
/**
* @nullable
*/
export type InframonitoringtypesStatefulSetRecordDTOMeta =
InframonitoringtypesStatefulSetRecordDTOMetaAnyOf | null;
}
export interface InframonitoringtypesStatefulSetRecordDTO {
/**
@@ -6903,10 +6992,7 @@ export interface InframonitoringtypesStatefulSetRecordDTO {
* @type integer
*/
desiredPods: number;
/**
* @type object,null
*/
meta: InframonitoringtypesStatefulSetRecordDTOMeta;
meta: InframonitoringtypesStatefulSetMetaDTO;
podCountsByStatus: InframonitoringtypesPodCountsByStatusDTO;
/**
* @type number
@@ -6961,21 +7047,40 @@ export interface InframonitoringtypesStatefulSetsDTO {
warning?: Querybuildertypesv5QueryWarnDataDTO;
}
export type InframonitoringtypesVolumeRecordDTOMetaAnyOf = {
export interface InframonitoringtypesVolumeMetaDTO {
/**
* @type string
*/
'k8s.cluster.name': string;
/**
* @type string
*/
'k8s.namespace.name': string;
/**
* @type string
*/
'k8s.node.name': string;
/**
* @type string
*/
'k8s.persistentvolumeclaim.name': string;
/**
* @type string
*/
'k8s.pod.name': string;
/**
* @type string
*/
'k8s.pod.uid': string;
/**
* @type string
*/
'k8s.statefulset.name': string;
[key: string]: string;
};
/**
* @nullable
*/
export type InframonitoringtypesVolumeRecordDTOMeta =
InframonitoringtypesVolumeRecordDTOMetaAnyOf | null;
}
export interface InframonitoringtypesVolumeRecordDTO {
/**
* @type object,null
*/
meta: InframonitoringtypesVolumeRecordDTOMeta;
meta: InframonitoringtypesVolumeMetaDTO;
/**
* @type string
*/

View File

@@ -35,7 +35,7 @@ func buildClusterRecords(
ClusterCPUAllocatable: -1,
ClusterMemory: -1,
ClusterMemoryAllocatable: -1,
Meta: map[string]string{},
Meta: inframonitoringtypes.NewClusterMeta(nil),
}
if metrics, ok := metricsMap[compositeKey]; ok {
@@ -74,9 +74,7 @@ func buildClusterRecords(
}
if attrs, ok := metadataMap[compositeKey]; ok {
for k, v := range attrs {
record.Meta[k] = v
}
record.Meta = inframonitoringtypes.NewClusterMeta(attrs)
}
records = append(records, record)
@@ -165,7 +163,7 @@ func (m *module) getTopClusterGroupsAndMetadata(
func (m *module) getClustersTableMetadata(ctx context.Context, orgID valuer.UUID, req *inframonitoringtypes.PostableClusters) (map[string]map[string]string, error) {
var nonGroupByAttrs []string
for _, key := range clusterAttrKeysForMetadata {
for _, key := range inframonitoringtypes.ClusterMetaKeys {
if !isKeyInGroupByAttrs(req.GroupBy, key) {
nonGroupByAttrs = append(nonGroupByAttrs, key)
}

View File

@@ -31,10 +31,6 @@ var clustersTableMetricNamesList = []string{
"k8s.container.status.reason",
}
var clusterAttrKeysForMetadata = []string{
"k8s.cluster.name",
}
// clusterCountAttrKeys are the resource attributes whose distinct values are
// counted per cluster. Node name is read from the node metric universe, while
// namespace + workload names come from the pod metric universe — both unioned

View File

@@ -49,7 +49,7 @@ func buildContainerRecords(
Memory: -1,
MemoryRequestUtilization: -1,
MemoryLimitUtilization: -1,
Meta: map[string]string{},
Meta: inframonitoringtypes.NewContainerMeta(nil),
}
if metrics, ok := metricsMap[compositeKey]; ok {
@@ -129,9 +129,7 @@ func buildContainerRecords(
}
if attrs, ok := metadataMap[compositeKey]; ok {
for k, v := range attrs {
record.Meta[k] = v
}
record.Meta = inframonitoringtypes.NewContainerMeta(attrs)
}
records = append(records, record)
@@ -220,7 +218,7 @@ func (m *module) getTopContainerGroupsAndMetadata(
func (m *module) getContainersTableMetadata(ctx context.Context, orgID valuer.UUID, req *inframonitoringtypes.PostableContainers) (map[string]map[string]string, error) {
var nonGroupByAttrs []string
for _, key := range containerAttrKeysForMetadata {
for _, key := range inframonitoringtypes.ContainerMetaKeys {
if !isKeyInGroupByAttrs(req.GroupBy, key) {
nonGroupByAttrs = append(nonGroupByAttrs, key)
}

View File

@@ -58,22 +58,6 @@ var containersTableMetricNamesList = []string{
"k8s.container.status.state",
}
var containerAttrKeysForMetadata = []string{
"k8s.pod.uid",
"k8s.container.name",
"k8s.pod.name",
"container.image.name",
"container.image.tag",
"k8s.namespace.name",
"k8s.node.name",
"k8s.deployment.name",
"k8s.statefulset.name",
"k8s.daemonset.name",
"k8s.job.name",
"k8s.cronjob.name",
"k8s.cluster.name",
}
var orderByToContainersQueryNames = map[string][]string{
inframonitoringtypes.ContainersOrderByCPU: {"A"},
inframonitoringtypes.ContainersOrderByCPURequest: {"B"},

View File

@@ -39,7 +39,7 @@ func buildDaemonSetRecords(
CurrentNodes: -1,
ReadyNodes: -1,
MisscheduledNodes: -1,
Meta: map[string]string{},
Meta: inframonitoringtypes.NewDaemonSetMeta(nil),
}
if metrics, ok := metricsMap[compositeKey]; ok {
@@ -80,9 +80,7 @@ func buildDaemonSetRecords(
}
if attrs, ok := metadataMap[compositeKey]; ok {
for k, v := range attrs {
record.Meta[k] = v
}
record.Meta = inframonitoringtypes.NewDaemonSetMeta(attrs)
}
records = append(records, record)
@@ -171,7 +169,7 @@ func (m *module) getTopDaemonSetGroupsAndMetadata(
func (m *module) getDaemonSetsTableMetadata(ctx context.Context, orgID valuer.UUID, req *inframonitoringtypes.PostableDaemonSets) (map[string]map[string]string, error) {
var nonGroupByAttrs []string
for _, key := range daemonSetAttrKeysForMetadata {
for _, key := range inframonitoringtypes.DaemonSetMetaKeys {
if !isKeyInGroupByAttrs(req.GroupBy, key) {
nonGroupByAttrs = append(nonGroupByAttrs, key)
}

View File

@@ -39,11 +39,6 @@ var daemonSetsTableMetricNamesList = []string{
// Carried forward from v1 daemonSetAttrsToEnrich
// (pkg/query-service/app/inframetrics/daemonsets.go:29-33).
var daemonSetAttrKeysForMetadata = []string{
"k8s.daemonset.name",
"k8s.namespace.name",
"k8s.cluster.name",
}
// orderByToDaemonSetsQueryNames maps the orderBy column to the query name
// used for ranking daemonset groups. v2 B/C/E/F are direct metrics, no

View File

@@ -37,7 +37,7 @@ func buildDeploymentRecords(
DeploymentMemoryLimit: -1,
DesiredPods: -1,
AvailablePods: -1,
Meta: map[string]string{},
Meta: inframonitoringtypes.NewDeploymentMeta(nil),
}
if metrics, ok := metricsMap[compositeKey]; ok {
@@ -72,9 +72,7 @@ func buildDeploymentRecords(
}
if attrs, ok := metadataMap[compositeKey]; ok {
for k, v := range attrs {
record.Meta[k] = v
}
record.Meta = inframonitoringtypes.NewDeploymentMeta(attrs)
}
records = append(records, record)
@@ -163,7 +161,7 @@ func (m *module) getTopDeploymentGroupsAndMetadata(
func (m *module) getDeploymentsTableMetadata(ctx context.Context, orgID valuer.UUID, req *inframonitoringtypes.PostableDeployments) (map[string]map[string]string, error) {
var nonGroupByAttrs []string
for _, key := range deploymentAttrKeysForMetadata {
for _, key := range inframonitoringtypes.DeploymentMetaKeys {
if !isKeyInGroupByAttrs(req.GroupBy, key) {
nonGroupByAttrs = append(nonGroupByAttrs, key)
}

View File

@@ -37,11 +37,6 @@ var deploymentsTableMetricNamesList = []string{
// Carried forward from v1 deploymentAttrsToEnrich
// (pkg/query-service/app/inframetrics/deployments.go:29-33).
var deploymentAttrKeysForMetadata = []string{
"k8s.deployment.name",
"k8s.namespace.name",
"k8s.cluster.name",
}
// orderByToDeploymentsQueryNames maps the orderBy column to the query name
// used for ranking deployment groups. v2 B/C/E/F are direct metrics, no

View File

@@ -217,7 +217,7 @@ func buildHostRecords(
Wait: -1,
Load15: -1,
DiskUsage: -1,
Meta: map[string]string{},
Meta: inframonitoringtypes.NewHostMeta(nil),
}
if metrics, ok := metricsMap[compositeKey]; ok {
@@ -239,9 +239,7 @@ func buildHostRecords(
}
if attrs, ok := metadataMap[compositeKey]; ok {
for k, v := range attrs {
record.Meta[k] = v
}
record.Meta = inframonitoringtypes.NewHostMeta(attrs)
}
records = append(records, record)
@@ -363,7 +361,7 @@ func (m *module) applyHostsActiveStatusFilter(req *inframonitoringtypes.Postable
func (m *module) getHostsTableMetadata(ctx context.Context, orgID valuer.UUID, req *inframonitoringtypes.PostableHosts) (map[string]map[string]string, error) {
var nonGroupByAttrs []string
for _, key := range hostAttrKeysForMetadata {
for _, key := range inframonitoringtypes.HostMetaKeys {
if !isKeyInGroupByAttrs(req.GroupBy, key) {
nonGroupByAttrs = append(nonGroupByAttrs, key)
}

View File

@@ -23,10 +23,6 @@ var hostsTableMetricNamesList = []string{
"system.filesystem.usage",
}
var hostAttrKeysForMetadata = []string{
"os.type",
}
// orderByToHostsQueryNames maps the orderBy column to the query/formula names
// from HostsTableListQuery used for ranking host groups.
var orderByToHostsQueryNames = map[string][]string{

View File

@@ -39,7 +39,7 @@ func buildJobRecords(
ActivePods: -1,
FailedPods: -1,
SuccessfulPods: -1,
Meta: map[string]string{},
Meta: inframonitoringtypes.NewJobMeta(nil),
}
if metrics, ok := metricsMap[compositeKey]; ok {
@@ -80,9 +80,7 @@ func buildJobRecords(
}
if attrs, ok := metadataMap[compositeKey]; ok {
for k, v := range attrs {
record.Meta[k] = v
}
record.Meta = inframonitoringtypes.NewJobMeta(attrs)
}
records = append(records, record)
@@ -171,7 +169,7 @@ func (m *module) getTopJobGroupsAndMetadata(
func (m *module) getJobsTableMetadata(ctx context.Context, orgID valuer.UUID, req *inframonitoringtypes.PostableJobs) (map[string]map[string]string, error) {
var nonGroupByAttrs []string
for _, key := range jobAttrKeysForMetadata {
for _, key := range inframonitoringtypes.JobMetaKeys {
if !isKeyInGroupByAttrs(req.GroupBy, key) {
nonGroupByAttrs = append(nonGroupByAttrs, key)
}

View File

@@ -39,11 +39,6 @@ var jobsTableMetricNamesList = []string{
// Carried forward from v1 jobAttrsToEnrich
// (pkg/query-service/app/inframetrics/jobs.go:31-35).
var jobAttrKeysForMetadata = []string{
"k8s.job.name",
"k8s.namespace.name",
"k8s.cluster.name",
}
// orderByToJobsQueryNames maps the orderBy column to the query name
// used for ranking job groups. v2 B/C/E/F are direct metrics, no

View File

@@ -31,7 +31,7 @@ func buildNamespaceRecords(
NamespaceName: namespaceName,
NamespaceCPU: -1,
NamespaceMemory: -1,
Meta: map[string]string{},
Meta: inframonitoringtypes.NewNamespaceMeta(nil),
}
if metrics, ok := metricsMap[compositeKey]; ok {
@@ -55,9 +55,7 @@ func buildNamespaceRecords(
}
if attrs, ok := metadataMap[compositeKey]; ok {
for k, v := range attrs {
record.Meta[k] = v
}
record.Meta = inframonitoringtypes.NewNamespaceMeta(attrs)
}
records = append(records, record)
@@ -146,7 +144,7 @@ func (m *module) getTopNamespaceGroupsAndMetadata(
func (m *module) getNamespacesTableMetadata(ctx context.Context, orgID valuer.UUID, req *inframonitoringtypes.PostableNamespaces) (map[string]map[string]string, error) {
var nonGroupByAttrs []string
for _, key := range namespaceAttrKeysForMetadata {
for _, key := range inframonitoringtypes.NamespaceMetaKeys {
if !isKeyInGroupByAttrs(req.GroupBy, key) {
nonGroupByAttrs = append(nonGroupByAttrs, key)
}

View File

@@ -59,11 +59,6 @@ var namespacesMetricNamesListForCounts = []string{
"k8s.pod.status_reason",
}
var namespaceAttrKeysForMetadata = []string{
"k8s.namespace.name",
"k8s.cluster.name",
}
// namespaceCountAttrKeys are the workload resource attributes whose distinct
// values are counted per namespace. They are read from the pod metric universe,
// which carries the owner workload names for each pod series.

View File

@@ -42,7 +42,7 @@ func buildNodeRecords(
NodeCPUAllocatable: -1,
NodeMemory: -1,
NodeMemoryAllocatable: -1,
Meta: map[string]string{},
Meta: inframonitoringtypes.NewNodeMeta(nil),
}
if metrics, ok := metricsMap[compositeKey]; ok {
@@ -82,9 +82,7 @@ func buildNodeRecords(
}
if attrs, ok := metadataMap[compositeKey]; ok {
for k, v := range attrs {
record.Meta[k] = v
}
record.Meta = inframonitoringtypes.NewNodeMeta(attrs)
}
records = append(records, record)
@@ -173,7 +171,7 @@ func (m *module) getTopNodeGroupsAndMetadata(
func (m *module) getNodesTableMetadata(ctx context.Context, orgID valuer.UUID, req *inframonitoringtypes.PostableNodes) (map[string]map[string]string, error) {
var nonGroupByAttrs []string
for _, key := range nodeAttrKeysForMetadata {
for _, key := range inframonitoringtypes.NodeMetaKeys {
if !isKeyInGroupByAttrs(req.GroupBy, key) {
nonGroupByAttrs = append(nonGroupByAttrs, key)
}

View File

@@ -30,11 +30,6 @@ var nodesTableMetricNamesList = []string{
"k8s.container.status.reason",
}
var nodeAttrKeysForMetadata = []string{
"k8s.node.uid",
"k8s.cluster.name",
}
var orderByToNodesQueryNames = map[string][]string{
inframonitoringtypes.NodesOrderByCPU: {"A"},
inframonitoringtypes.NodesOrderByCPUAllocatable: {"B"},

View File

@@ -48,7 +48,7 @@ func buildPodRecords(
PodMemoryRequest: -1,
PodMemoryLimit: -1,
PodAge: -1,
Meta: map[string]string{},
Meta: inframonitoringtypes.NewPodMeta(nil),
}
if metrics, ok := metricsMap[compositeKey]; ok {
@@ -136,9 +136,7 @@ func buildPodRecords(
}
}
}
for k, v := range attrs {
record.Meta[k] = v
}
record.Meta = inframonitoringtypes.NewPodMeta(attrs)
}
records = append(records, record)
@@ -231,7 +229,7 @@ func (m *module) getTopPodGroupsAndMetadata(
func (m *module) getPodsTableMetadata(ctx context.Context, orgID valuer.UUID, req *inframonitoringtypes.PostablePods) (map[string]map[string]string, error) {
var nonGroupByAttrs []string
for _, key := range podAttrKeysForMetadata {
for _, key := range inframonitoringtypes.PodMetaKeys {
if !isKeyInGroupByAttrs(req.GroupBy, key) {
nonGroupByAttrs = append(nonGroupByAttrs, key)
}

View File

@@ -45,20 +45,6 @@ var podsTableMetricNamesList = []string{
// "k8s.container.restarts",
}
var podAttrKeysForMetadata = []string{
"k8s.pod.uid",
"k8s.pod.name",
"k8s.namespace.name",
"k8s.node.name",
"k8s.deployment.name",
"k8s.statefulset.name",
"k8s.daemonset.name",
"k8s.job.name",
"k8s.cronjob.name",
"k8s.cluster.name",
"k8s.pod.start_time",
}
var orderByToPodsQueryNames = map[string][]string{
inframonitoringtypes.PodsOrderByCPU: {"A"},
inframonitoringtypes.PodsOrderByCPURequest: {"B"},

View File

@@ -37,7 +37,7 @@ func buildStatefulSetRecords(
StatefulSetMemoryLimit: -1,
DesiredPods: -1,
CurrentPods: -1,
Meta: map[string]string{},
Meta: inframonitoringtypes.NewStatefulSetMeta(nil),
}
if metrics, ok := metricsMap[compositeKey]; ok {
@@ -72,9 +72,7 @@ func buildStatefulSetRecords(
}
if attrs, ok := metadataMap[compositeKey]; ok {
for k, v := range attrs {
record.Meta[k] = v
}
record.Meta = inframonitoringtypes.NewStatefulSetMeta(attrs)
}
records = append(records, record)
@@ -163,7 +161,7 @@ func (m *module) getTopStatefulSetGroupsAndMetadata(
func (m *module) getStatefulSetsTableMetadata(ctx context.Context, orgID valuer.UUID, req *inframonitoringtypes.PostableStatefulSets) (map[string]map[string]string, error) {
var nonGroupByAttrs []string
for _, key := range statefulSetAttrKeysForMetadata {
for _, key := range inframonitoringtypes.StatefulSetMetaKeys {
if !isKeyInGroupByAttrs(req.GroupBy, key) {
nonGroupByAttrs = append(nonGroupByAttrs, key)
}

View File

@@ -37,11 +37,6 @@ var statefulSetsTableMetricNamesList = []string{
// Carried forward from v1 statefulSetAttrsToEnrich
// (pkg/query-service/app/inframetrics/statefulsets.go:29-33).
var statefulSetAttrKeysForMetadata = []string{
"k8s.statefulset.name",
"k8s.namespace.name",
"k8s.cluster.name",
}
// orderByToStatefulSetsQueryNames maps the orderBy column to the query name
// used for ranking statefulset groups. v2 B/C/E/F are direct metrics, no

View File

@@ -34,7 +34,7 @@ func buildVolumeRecords(
VolumeInodes: -1,
VolumeInodesFree: -1,
VolumeInodesUsed: -1,
Meta: map[string]string{},
Meta: inframonitoringtypes.NewVolumeMeta(nil),
}
if metrics, ok := metricsMap[compositeKey]; ok {
@@ -59,9 +59,7 @@ func buildVolumeRecords(
}
if attrs, ok := metadataMap[compositeKey]; ok {
for k, v := range attrs {
record.Meta[k] = v
}
record.Meta = inframonitoringtypes.NewVolumeMeta(attrs)
}
records = append(records, record)
@@ -150,7 +148,7 @@ func (m *module) getTopVolumeGroupsAndMetadata(
func (m *module) getVolumesTableMetadata(ctx context.Context, orgID valuer.UUID, req *inframonitoringtypes.PostableVolumes) (map[string]map[string]string, error) {
var nonGroupByAttrs []string
for _, key := range volumeAttrKeysForMetadata {
for _, key := range inframonitoringtypes.VolumeMetaKeys {
if !isKeyInGroupByAttrs(req.GroupBy, key) {
nonGroupByAttrs = append(nonGroupByAttrs, key)
}

View File

@@ -28,15 +28,6 @@ var volumesTableMetricNamesList = []string{
// Carried forward from v1 volumeAttrsToEnrich
// (pkg/query-service/app/inframetrics/pvcs.go:23-31).
var volumeAttrKeysForMetadata = []string{
"k8s.persistentvolumeclaim.name",
"k8s.pod.uid",
"k8s.pod.name",
"k8s.namespace.name",
"k8s.node.name",
"k8s.statefulset.name",
"k8s.cluster.name",
}
// orderByToVolumesQueryNames maps the orderBy column to the query/formula names
// from newVolumesTableListQuery used for ranking volume groups. For "usage",

View File

@@ -6,6 +6,8 @@ import (
"github.com/SigNoz/signoz/pkg/errors"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/swaggest/jsonschema-go"
)
type Clusters struct {
@@ -35,7 +37,7 @@ type ClusterRecord struct {
Jobs int64 `json:"jobs" required:"true"`
StatefulSets int64 `json:"statefulSets" required:"true"`
} `json:"counts" required:"true"`
Meta map[string]string `json:"meta" required:"true"`
Meta ClusterMeta `json:"meta" required:"true"`
}
// PostableClusters is the request body for the v2 clusters list API.
@@ -113,3 +115,36 @@ func (req *PostableClusters) UnmarshalJSON(data []byte) error {
*req = PostableClusters(decoded)
return req.Validate()
}
// ClusterMeta carries the guaranteed cluster metadata keys as typed fields plus
// any dynamic group-by keys in Extra.
type ClusterMeta struct {
ClusterName string `json:"k8s.cluster.name" required:"true"`
Extra map[string]string `json:"-"`
}
var ClusterMetaKeys = getMetaKeys(&ClusterMeta{})
func NewClusterMeta(attrs map[string]string) ClusterMeta {
var m ClusterMeta
m.Extra = populateMeta(&m, attrs)
return m
}
func (m ClusterMeta) MarshalJSON() ([]byte, error) {
return marshalMeta(&m, m.Extra)
}
func (m *ClusterMeta) UnmarshalJSON(data []byte) error {
raw, err := splitMeta(data)
if err != nil {
return err
}
m.Extra = populateMeta(m, raw)
return nil
}
func (ClusterMeta) PrepareJSONSchema(s *jsonschema.Schema) error {
addStringAdditionalProps(s)
return nil
}

View File

@@ -6,6 +6,8 @@ import (
"github.com/SigNoz/signoz/pkg/errors"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/swaggest/jsonschema-go"
)
type Containers struct {
@@ -68,7 +70,7 @@ type ContainerRecord struct {
MemoryRequestUtilization float64 `json:"memoryRequestUtilization" required:"true"` // k8s.container.memory_request_utilization
MemoryLimitUtilization float64 `json:"memoryLimitUtilization" required:"true"` // k8s.container.memory_limit_utilization
Meta map[string]string `json:"meta" required:"true"`
Meta ContainerMeta `json:"meta" required:"true"`
}
// PostableContainers is the request body for the v2 containers list API.
@@ -146,3 +148,48 @@ func (req *PostableContainers) UnmarshalJSON(data []byte) error {
*req = PostableContainers(decoded)
return req.Validate()
}
// ContainerMeta carries the guaranteed container metadata keys as typed fields
// plus any dynamic group-by keys in Extra.
type ContainerMeta struct {
PodUID string `json:"k8s.pod.uid" required:"true"`
ContainerName string `json:"k8s.container.name" required:"true"`
PodName string `json:"k8s.pod.name" required:"true"`
ImageName string `json:"container.image.name" required:"true"`
ImageTag string `json:"container.image.tag" required:"true"`
NamespaceName string `json:"k8s.namespace.name" required:"true"`
NodeName string `json:"k8s.node.name" required:"true"`
DeploymentName string `json:"k8s.deployment.name" required:"true"`
StatefulSetName string `json:"k8s.statefulset.name" required:"true"`
DaemonSetName string `json:"k8s.daemonset.name" required:"true"`
JobName string `json:"k8s.job.name" required:"true"`
CronJobName string `json:"k8s.cronjob.name" required:"true"`
ClusterName string `json:"k8s.cluster.name" required:"true"`
Extra map[string]string `json:"-"`
}
var ContainerMetaKeys = getMetaKeys(&ContainerMeta{})
func NewContainerMeta(attrs map[string]string) ContainerMeta {
var m ContainerMeta
m.Extra = populateMeta(&m, attrs)
return m
}
func (m ContainerMeta) MarshalJSON() ([]byte, error) {
return marshalMeta(&m, m.Extra)
}
func (m *ContainerMeta) UnmarshalJSON(data []byte) error {
raw, err := splitMeta(data)
if err != nil {
return err
}
m.Extra = populateMeta(m, raw)
return nil
}
func (ContainerMeta) PrepareJSONSchema(s *jsonschema.Schema) error {
addStringAdditionalProps(s)
return nil
}

View File

@@ -6,6 +6,8 @@ import (
"github.com/SigNoz/signoz/pkg/errors"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/swaggest/jsonschema-go"
)
type DaemonSets struct {
@@ -29,7 +31,7 @@ type DaemonSetRecord struct {
ReadyNodes int `json:"readyNodes" required:"true"`
MisscheduledNodes int `json:"misscheduledNodes" required:"true"`
PodCountsByStatus PodCountsByStatus `json:"podCountsByStatus" required:"true"`
Meta map[string]string `json:"meta" required:"true"`
Meta DaemonSetMeta `json:"meta" required:"true"`
}
// PostableDaemonSets is the request body for the v2 daemonsets list API.
@@ -107,3 +109,38 @@ func (req *PostableDaemonSets) UnmarshalJSON(data []byte) error {
*req = PostableDaemonSets(decoded)
return req.Validate()
}
// DaemonSetMeta carries the guaranteed daemonset metadata keys as typed fields
// plus any dynamic group-by keys in Extra.
type DaemonSetMeta struct {
DaemonSetName string `json:"k8s.daemonset.name" required:"true"`
NamespaceName string `json:"k8s.namespace.name" required:"true"`
ClusterName string `json:"k8s.cluster.name" required:"true"`
Extra map[string]string `json:"-"`
}
var DaemonSetMetaKeys = getMetaKeys(&DaemonSetMeta{})
func NewDaemonSetMeta(attrs map[string]string) DaemonSetMeta {
var m DaemonSetMeta
m.Extra = populateMeta(&m, attrs)
return m
}
func (m DaemonSetMeta) MarshalJSON() ([]byte, error) {
return marshalMeta(&m, m.Extra)
}
func (m *DaemonSetMeta) UnmarshalJSON(data []byte) error {
raw, err := splitMeta(data)
if err != nil {
return err
}
m.Extra = populateMeta(m, raw)
return nil
}
func (DaemonSetMeta) PrepareJSONSchema(s *jsonschema.Schema) error {
addStringAdditionalProps(s)
return nil
}

View File

@@ -6,6 +6,8 @@ import (
"github.com/SigNoz/signoz/pkg/errors"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/swaggest/jsonschema-go"
)
type Deployments struct {
@@ -27,7 +29,7 @@ type DeploymentRecord struct {
DesiredPods int `json:"desiredPods" required:"true"`
AvailablePods int `json:"availablePods" required:"true"`
PodCountsByStatus PodCountsByStatus `json:"podCountsByStatus" required:"true"`
Meta map[string]string `json:"meta" required:"true"`
Meta DeploymentMeta `json:"meta" required:"true"`
}
// PostableDeployments is the request body for the v2 deployments list API.
@@ -105,3 +107,38 @@ func (req *PostableDeployments) UnmarshalJSON(data []byte) error {
*req = PostableDeployments(decoded)
return req.Validate()
}
// DeploymentMeta carries the guaranteed deployment metadata keys as typed fields
// plus any dynamic group-by keys in Extra.
type DeploymentMeta struct {
DeploymentName string `json:"k8s.deployment.name" required:"true"`
NamespaceName string `json:"k8s.namespace.name" required:"true"`
ClusterName string `json:"k8s.cluster.name" required:"true"`
Extra map[string]string `json:"-"`
}
var DeploymentMetaKeys = getMetaKeys(&DeploymentMeta{})
func NewDeploymentMeta(attrs map[string]string) DeploymentMeta {
var m DeploymentMeta
m.Extra = populateMeta(&m, attrs)
return m
}
func (m DeploymentMeta) MarshalJSON() ([]byte, error) {
return marshalMeta(&m, m.Extra)
}
func (m *DeploymentMeta) UnmarshalJSON(data []byte) error {
raw, err := splitMeta(data)
if err != nil {
return err
}
m.Extra = populateMeta(m, raw)
return nil
}
func (DeploymentMeta) PrepareJSONSchema(s *jsonschema.Schema) error {
addStringAdditionalProps(s)
return nil
}

View File

@@ -6,6 +6,8 @@ import (
"github.com/SigNoz/signoz/pkg/errors"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/swaggest/jsonschema-go"
)
type Hosts struct {
@@ -17,16 +19,16 @@ type Hosts struct {
}
type HostRecord struct {
HostName string `json:"hostName" required:"true"`
Status HostStatus `json:"status" required:"true"`
ActiveHostCount int `json:"activeHostCount" required:"true"`
InactiveHostCount int `json:"inactiveHostCount" required:"true"`
CPU float64 `json:"cpu" required:"true"`
Memory float64 `json:"memory" required:"true"`
Wait float64 `json:"wait" required:"true"`
Load15 float64 `json:"load15" required:"true"`
DiskUsage float64 `json:"diskUsage" required:"true"`
Meta map[string]string `json:"meta" required:"true"`
HostName string `json:"hostName" required:"true"`
Status HostStatus `json:"status" required:"true"`
ActiveHostCount int `json:"activeHostCount" required:"true"`
InactiveHostCount int `json:"inactiveHostCount" required:"true"`
CPU float64 `json:"cpu" required:"true"`
Memory float64 `json:"memory" required:"true"`
Wait float64 `json:"wait" required:"true"`
Load15 float64 `json:"load15" required:"true"`
DiskUsage float64 `json:"diskUsage" required:"true"`
Meta HostMeta `json:"meta" required:"true"`
}
type PostableHosts struct {
@@ -113,3 +115,37 @@ func (req *PostableHosts) UnmarshalJSON(data []byte) error {
*req = PostableHosts(decoded)
return req.Validate()
}
// HostMeta carries the guaranteed host metadata keys as typed fields plus any
// dynamic group-by keys in Extra.
type HostMeta struct {
OSType string `json:"os.type" required:"true"`
HostName string `json:"host.name" required:"true"`
Extra map[string]string `json:"-"`
}
var HostMetaKeys = getMetaKeys(&HostMeta{})
func NewHostMeta(attrs map[string]string) HostMeta {
var m HostMeta
m.Extra = populateMeta(&m, attrs)
return m
}
func (m HostMeta) MarshalJSON() ([]byte, error) {
return marshalMeta(&m, m.Extra)
}
func (m *HostMeta) UnmarshalJSON(data []byte) error {
raw, err := splitMeta(data)
if err != nil {
return err
}
m.Extra = populateMeta(m, raw)
return nil
}
func (HostMeta) PrepareJSONSchema(s *jsonschema.Schema) error {
addStringAdditionalProps(s)
return nil
}

View File

@@ -6,6 +6,8 @@ import (
"github.com/SigNoz/signoz/pkg/errors"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/swaggest/jsonschema-go"
)
type Jobs struct {
@@ -29,7 +31,7 @@ type JobRecord struct {
FailedPods int `json:"failedPods" required:"true"`
SuccessfulPods int `json:"successfulPods" required:"true"`
PodCountsByStatus PodCountsByStatus `json:"podCountsByStatus" required:"true"`
Meta map[string]string `json:"meta" required:"true"`
Meta JobMeta `json:"meta" required:"true"`
}
// PostableJobs is the request body for the v2 jobs list API.
@@ -107,3 +109,38 @@ func (req *PostableJobs) UnmarshalJSON(data []byte) error {
*req = PostableJobs(decoded)
return req.Validate()
}
// JobMeta carries the guaranteed job metadata keys as typed fields plus any
// dynamic group-by keys in Extra.
type JobMeta struct {
JobName string `json:"k8s.job.name" required:"true"`
NamespaceName string `json:"k8s.namespace.name" required:"true"`
ClusterName string `json:"k8s.cluster.name" required:"true"`
Extra map[string]string `json:"-"`
}
var JobMetaKeys = getMetaKeys(&JobMeta{})
func NewJobMeta(attrs map[string]string) JobMeta {
var m JobMeta
m.Extra = populateMeta(&m, attrs)
return m
}
func (m JobMeta) MarshalJSON() ([]byte, error) {
return marshalMeta(&m, m.Extra)
}
func (m *JobMeta) UnmarshalJSON(data []byte) error {
raw, err := splitMeta(data)
if err != nil {
return err
}
m.Extra = populateMeta(m, raw)
return nil
}
func (JobMeta) PrepareJSONSchema(s *jsonschema.Schema) error {
addStringAdditionalProps(s)
return nil
}

View File

@@ -0,0 +1,112 @@
package inframonitoringtypes
import (
"encoding/json"
"maps"
"reflect"
"strings"
"github.com/swaggest/jsonschema-go"
)
// The meta field on every infra-monitoring v2 record carries a fixed set of
// guaranteed keys (surfaced as strongly-typed struct fields) plus any dynamic
// keys the caller introduces via group-by (kept in Extra). Each entity defines
// its own XMeta type; the helpers below give them a shared, wire-stable
// marshaling and schema contract:
//
// - MarshalJSON -> flattenMeta: known + Extra collapse into one flat object.
// - UnmarshalJSON -> splitMeta: decode the flat object, route known keys to
// fields (via the entity's NewXMeta), the rest to Extra.
// - PrepareJSONSchema -> addStringAdditionalProps: keep the reflected known
// properties and mark the object as an open map of string values.
//
// flattenMeta merges the guaranteed known keys and the open Extra map into a
// single flat JSON object, preserving the historical wire shape. known wins on
// collision. The output map is always non-nil, so an empty meta serializes as
// {} rather than null.
func flattenMeta(extra map[string]string, known map[string]string) ([]byte, error) {
out := make(map[string]string, len(extra)+len(known))
maps.Copy(out, extra)
maps.Copy(out, known)
return json.Marshal(out)
}
// splitMeta decodes a flat meta object into its raw string map. Callers pull
// their known keys out of the returned map; whatever remains becomes Extra.
func splitMeta(data []byte) (map[string]string, error) {
raw := map[string]string{}
if err := json.Unmarshal(data, &raw); err != nil {
return nil, err
}
return raw, nil
}
// metaField is one guaranteed meta key discovered from an XMeta struct's json
// tags (json:"-" fields like Extra are skipped).
type metaField struct {
index int
key string
}
// metaFieldsOf reflects the string fields of an XMeta struct (skipping json:"-"
// fields like Extra).
func metaFieldsOf(t reflect.Type) []metaField {
fields := make([]metaField, 0, t.NumField())
for i := range t.NumField() {
f := t.Field(i)
key, _, _ := strings.Cut(f.Tag.Get("json"), ",")
if key == "" || key == "-" {
continue
}
fields = append(fields, metaField{index: i, key: key})
}
return fields
}
// populateMeta routes src into the guaranteed fields of the XMeta pointed to by
// m (empty string when a key is absent) and returns the leftover keys (dynamic
// group-by keys) as Extra.
func populateMeta(m any, src map[string]string) map[string]string {
extra := map[string]string{}
maps.Copy(extra, src)
rv := reflect.ValueOf(m).Elem()
for _, f := range metaFieldsOf(rv.Type()) {
rv.Field(f.index).SetString(src[f.key])
delete(extra, f.key)
}
return extra
}
// marshalMeta flattens the guaranteed fields of the XMeta pointed to by m plus
// its Extra map into a single flat JSON object.
func marshalMeta(m any, extra map[string]string) ([]byte, error) {
rv := reflect.ValueOf(m).Elem()
known := make(map[string]string)
for _, f := range metaFieldsOf(rv.Type()) {
known[f.key] = rv.Field(f.index).String()
}
return flattenMeta(extra, known)
}
// getMetaKeys returns the guaranteed keys of an XMeta, in struct-field order. Used
// by implinframonitoring as the metadata fetch column list, keeping the key set
// defined once (on the struct).
func getMetaKeys(m any) []string {
rv := reflect.ValueOf(m).Elem()
fields := metaFieldsOf(rv.Type())
keys := make([]string, 0, len(fields))
for _, f := range fields {
keys = append(keys, f.key)
}
return keys
}
// addStringAdditionalProps marks an already-reflected meta object schema as an
// open map of string values. The known properties and their required list come
// from struct-tag reflection (this runs after, via the Preparer hook); this
// only attaches additionalProperties:{type:string} so callers may add arbitrary
// group-by keys.
func addStringAdditionalProps(s *jsonschema.Schema) {
s.WithAdditionalProperties(jsonschema.String.ToSchemaOrBool())
}

View File

@@ -0,0 +1,150 @@
package inframonitoringtypes
import (
"encoding/json"
"reflect"
"testing"
"github.com/stretchr/testify/require"
"github.com/swaggest/jsonschema-go"
)
// fullPodAttrs is a metadata map with every guaranteed pod key plus a dynamic
// group-by key, used across the round-trip cases.
func fullPodAttrs() map[string]string {
return map[string]string{
"k8s.pod.uid": "uid-1",
"k8s.pod.name": "pod-1",
"k8s.namespace.name": "ns-1",
"k8s.node.name": "node-1",
"k8s.deployment.name": "dep-1",
"k8s.statefulset.name": "",
"k8s.daemonset.name": "",
"k8s.job.name": "",
"k8s.cronjob.name": "",
"k8s.cluster.name": "cluster-1",
"k8s.pod.start_time": "2024-01-01T00:00:00Z",
"custom.groupby": "gv",
}
}
func TestPodMeta_RoundTripAndRouting(t *testing.T) {
attrs := fullPodAttrs()
m := NewPodMeta(attrs)
// known keys route to typed fields
require.Equal(t, "uid-1", m.PodUID)
require.Equal(t, "cluster-1", m.ClusterName)
require.Equal(t, "2024-01-01T00:00:00Z", m.PodStartTime)
// dynamic key routes to Extra, guaranteed keys do not
require.Equal(t, map[string]string{"custom.groupby": "gv"}, m.Extra)
// marshals to a single flat object equal to the input map
b, err := json.Marshal(m)
require.NoError(t, err)
var flat map[string]string
require.NoError(t, json.Unmarshal(b, &flat))
require.Equal(t, attrs, flat)
require.NotContains(t, string(b), "Extra")
// round-trip back into the struct is stable
var back PodMeta
require.NoError(t, json.Unmarshal(b, &back))
require.Equal(t, m, back)
}
func TestMeta_EmptyMarshalsToObjectNotNull(t *testing.T) {
b, err := json.Marshal(NewClusterMeta(nil))
require.NoError(t, err)
require.JSONEq(t, `{"k8s.cluster.name":""}`, string(b))
// a nil-Extra zero value still marshals its guaranteed keys, never null
b, err = json.Marshal(ClusterMeta{})
require.NoError(t, err)
require.JSONEq(t, `{"k8s.cluster.name":""}`, string(b))
}
func TestMeta_AbsentGuaranteedKeyEmitsEmptyString(t *testing.T) {
// os.type absent from attrs -> still present as "" (accepted behavior)
m := NewHostMeta(map[string]string{"host.name": "h1"})
require.Equal(t, "", m.OSType)
b, err := json.Marshal(m)
require.NoError(t, err)
require.JSONEq(t, `{"host.name":"h1","os.type":""}`, string(b))
}
func TestMeta_DynamicKeyDoesNotDuplicateKnownKey(t *testing.T) {
// a dynamic key colliding with a known key must not double-emit; the typed
// field wins and there is exactly one occurrence on the wire.
m := NewClusterMeta(map[string]string{"k8s.cluster.name": "c1"})
require.Empty(t, m.Extra)
require.Equal(t, "c1", m.ClusterName)
b, err := json.Marshal(m)
require.NoError(t, err)
require.JSONEq(t, `{"k8s.cluster.name":"c1"}`, string(b))
}
func TestMetaKeys_ExpectedSetAndOrder(t *testing.T) {
require.Equal(t, []string{"os.type", "host.name"}, HostMetaKeys)
require.Equal(t, []string{"k8s.node.uid", "k8s.cluster.name", "k8s.node.name"}, NodeMetaKeys)
require.Equal(t, []string{
"k8s.pod.uid", "k8s.pod.name", "k8s.namespace.name", "k8s.node.name",
"k8s.deployment.name", "k8s.statefulset.name", "k8s.daemonset.name",
"k8s.job.name", "k8s.cronjob.name", "k8s.cluster.name", "k8s.pod.start_time",
}, PodMetaKeys)
}
// TestMetaKeys_MatchStructTags guards against a field rename/reorder silently
// changing the fetch column list: every key must correspond to a json tag on
// the struct, and the two must be in the same order.
func TestMetaKeys_MatchStructTags(t *testing.T) {
cases := []struct {
keys []string
typ reflect.Type
}{
{HostMetaKeys, reflect.TypeOf(HostMeta{})},
{PodMetaKeys, reflect.TypeOf(PodMeta{})},
{ContainerMetaKeys, reflect.TypeOf(ContainerMeta{})},
{NodeMetaKeys, reflect.TypeOf(NodeMeta{})},
{NamespaceMetaKeys, reflect.TypeOf(NamespaceMeta{})},
{ClusterMetaKeys, reflect.TypeOf(ClusterMeta{})},
{DeploymentMetaKeys, reflect.TypeOf(DeploymentMeta{})},
{DaemonSetMetaKeys, reflect.TypeOf(DaemonSetMeta{})},
{StatefulSetMetaKeys, reflect.TypeOf(StatefulSetMeta{})},
{JobMetaKeys, reflect.TypeOf(JobMeta{})},
{VolumeMetaKeys, reflect.TypeOf(VolumeMeta{})},
}
for _, c := range cases {
t.Run(c.typ.Name(), func(t *testing.T) {
var tagKeys []string
for i := range c.typ.NumField() {
tag := c.typ.Field(i).Tag.Get("json")
if tag == "" || tag == "-" {
continue
}
tagKeys = append(tagKeys, tag)
}
require.Equal(t, tagKeys, c.keys)
})
}
}
// TestMeta_SchemaShape locks the OpenAPI contract the frontend depends on: known
// keys as properties + all required + additionalProperties:{type:string}.
func TestMeta_SchemaShape(t *testing.T) {
r := jsonschema.Reflector{}
s, err := r.Reflect(PodMeta{})
require.NoError(t, err)
require.Equal(t, PodMetaKeys, s.Required)
require.Len(t, s.Properties, len(PodMetaKeys))
for _, k := range PodMetaKeys {
prop, ok := s.Properties[k]
require.True(t, ok, "missing property %s", k)
require.NotNil(t, prop.TypeObject)
require.Equal(t, jsonschema.String.Type(), *prop.TypeObject.Type)
}
require.NotNil(t, s.AdditionalProperties)
require.NotNil(t, s.AdditionalProperties.TypeObject)
require.Equal(t, jsonschema.String.Type(), *s.AdditionalProperties.TypeObject.Type)
}

View File

@@ -6,6 +6,8 @@ import (
"github.com/SigNoz/signoz/pkg/errors"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/swaggest/jsonschema-go"
)
type Namespaces struct {
@@ -27,7 +29,7 @@ type NamespaceRecord struct {
Jobs int64 `json:"jobs" required:"true"`
StatefulSets int64 `json:"statefulSets" required:"true"`
} `json:"counts" required:"true"`
Meta map[string]string `json:"meta" required:"true"`
Meta NamespaceMeta `json:"meta" required:"true"`
}
// PostableNamespaces is the request body for the v2 namespaces list API.
@@ -105,3 +107,37 @@ func (req *PostableNamespaces) UnmarshalJSON(data []byte) error {
*req = PostableNamespaces(decoded)
return req.Validate()
}
// NamespaceMeta carries the guaranteed namespace metadata keys as typed fields
// plus any dynamic group-by keys in Extra.
type NamespaceMeta struct {
NamespaceName string `json:"k8s.namespace.name" required:"true"`
ClusterName string `json:"k8s.cluster.name" required:"true"`
Extra map[string]string `json:"-"`
}
var NamespaceMetaKeys = getMetaKeys(&NamespaceMeta{})
func NewNamespaceMeta(attrs map[string]string) NamespaceMeta {
var m NamespaceMeta
m.Extra = populateMeta(&m, attrs)
return m
}
func (m NamespaceMeta) MarshalJSON() ([]byte, error) {
return marshalMeta(&m, m.Extra)
}
func (m *NamespaceMeta) UnmarshalJSON(data []byte) error {
raw, err := splitMeta(data)
if err != nil {
return err
}
m.Extra = populateMeta(m, raw)
return nil
}
func (NamespaceMeta) PrepareJSONSchema(s *jsonschema.Schema) error {
addStringAdditionalProps(s)
return nil
}

View File

@@ -6,6 +6,8 @@ import (
"github.com/SigNoz/signoz/pkg/errors"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/swaggest/jsonschema-go"
)
type Nodes struct {
@@ -32,7 +34,7 @@ type NodeRecord struct {
NodeCPUAllocatable float64 `json:"nodeCPUAllocatable" required:"true"`
NodeMemory float64 `json:"nodeMemory" required:"true"`
NodeMemoryAllocatable float64 `json:"nodeMemoryAllocatable" required:"true"`
Meta map[string]string `json:"meta" required:"true"`
Meta NodeMeta `json:"meta" required:"true"`
}
// PostableNodes is the request body for the v2 nodes list API.
@@ -110,3 +112,38 @@ func (req *PostableNodes) UnmarshalJSON(data []byte) error {
*req = PostableNodes(decoded)
return req.Validate()
}
// NodeMeta carries the guaranteed node metadata keys as typed fields plus any
// dynamic group-by keys in Extra.
type NodeMeta struct {
NodeUID string `json:"k8s.node.uid" required:"true"`
ClusterName string `json:"k8s.cluster.name" required:"true"`
NodeName string `json:"k8s.node.name" required:"true"`
Extra map[string]string `json:"-"`
}
var NodeMetaKeys = getMetaKeys(&NodeMeta{})
func NewNodeMeta(attrs map[string]string) NodeMeta {
var m NodeMeta
m.Extra = populateMeta(&m, attrs)
return m
}
func (m NodeMeta) MarshalJSON() ([]byte, error) {
return marshalMeta(&m, m.Extra)
}
func (m *NodeMeta) UnmarshalJSON(data []byte) error {
raw, err := splitMeta(data)
if err != nil {
return err
}
m.Extra = populateMeta(m, raw)
return nil
}
func (NodeMeta) PrepareJSONSchema(s *jsonschema.Schema) error {
addStringAdditionalProps(s)
return nil
}

View File

@@ -6,6 +6,8 @@ import (
"github.com/SigNoz/signoz/pkg/errors"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/swaggest/jsonschema-go"
)
type Pods struct {
@@ -56,7 +58,7 @@ type PodRecord struct {
PodCountsByStatus PodCountsByStatus `json:"podCountsByStatus" required:"true"`
PodRestarts int64 `json:"podRestarts" required:"true"`
PodAge int64 `json:"podAge" required:"true"`
Meta map[string]string `json:"meta" required:"true"`
Meta PodMeta `json:"meta" required:"true"`
}
// PostablePods is the request body for the v2 pods list API.
@@ -134,3 +136,46 @@ func (req *PostablePods) UnmarshalJSON(data []byte) error {
*req = PostablePods(decoded)
return req.Validate()
}
// PodMeta carries the guaranteed pod metadata keys as typed fields plus any
// dynamic group-by keys in Extra.
type PodMeta struct {
PodUID string `json:"k8s.pod.uid" required:"true"`
PodName string `json:"k8s.pod.name" required:"true"`
NamespaceName string `json:"k8s.namespace.name" required:"true"`
NodeName string `json:"k8s.node.name" required:"true"`
DeploymentName string `json:"k8s.deployment.name" required:"true"`
StatefulSetName string `json:"k8s.statefulset.name" required:"true"`
DaemonSetName string `json:"k8s.daemonset.name" required:"true"`
JobName string `json:"k8s.job.name" required:"true"`
CronJobName string `json:"k8s.cronjob.name" required:"true"`
ClusterName string `json:"k8s.cluster.name" required:"true"`
PodStartTime string `json:"k8s.pod.start_time" required:"true"`
Extra map[string]string `json:"-"`
}
var PodMetaKeys = getMetaKeys(&PodMeta{})
func NewPodMeta(attrs map[string]string) PodMeta {
var m PodMeta
m.Extra = populateMeta(&m, attrs)
return m
}
func (m PodMeta) MarshalJSON() ([]byte, error) {
return marshalMeta(&m, m.Extra)
}
func (m *PodMeta) UnmarshalJSON(data []byte) error {
raw, err := splitMeta(data)
if err != nil {
return err
}
m.Extra = populateMeta(m, raw)
return nil
}
func (PodMeta) PrepareJSONSchema(s *jsonschema.Schema) error {
addStringAdditionalProps(s)
return nil
}

View File

@@ -6,6 +6,8 @@ import (
"github.com/SigNoz/signoz/pkg/errors"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/swaggest/jsonschema-go"
)
type StatefulSets struct {
@@ -27,7 +29,7 @@ type StatefulSetRecord struct {
DesiredPods int `json:"desiredPods" required:"true"`
CurrentPods int `json:"currentPods" required:"true"`
PodCountsByStatus PodCountsByStatus `json:"podCountsByStatus" required:"true"`
Meta map[string]string `json:"meta" required:"true"`
Meta StatefulSetMeta `json:"meta" required:"true"`
}
// PostableStatefulSets is the request body for the v2 statefulsets list API.
@@ -105,3 +107,38 @@ func (req *PostableStatefulSets) UnmarshalJSON(data []byte) error {
*req = PostableStatefulSets(decoded)
return req.Validate()
}
// StatefulSetMeta carries the guaranteed statefulset metadata keys as typed
// fields plus any dynamic group-by keys in Extra.
type StatefulSetMeta struct {
StatefulSetName string `json:"k8s.statefulset.name" required:"true"`
NamespaceName string `json:"k8s.namespace.name" required:"true"`
ClusterName string `json:"k8s.cluster.name" required:"true"`
Extra map[string]string `json:"-"`
}
var StatefulSetMetaKeys = getMetaKeys(&StatefulSetMeta{})
func NewStatefulSetMeta(attrs map[string]string) StatefulSetMeta {
var m StatefulSetMeta
m.Extra = populateMeta(&m, attrs)
return m
}
func (m StatefulSetMeta) MarshalJSON() ([]byte, error) {
return marshalMeta(&m, m.Extra)
}
func (m *StatefulSetMeta) UnmarshalJSON(data []byte) error {
raw, err := splitMeta(data)
if err != nil {
return err
}
m.Extra = populateMeta(m, raw)
return nil
}
func (StatefulSetMeta) PrepareJSONSchema(s *jsonschema.Schema) error {
addStringAdditionalProps(s)
return nil
}

View File

@@ -6,6 +6,8 @@ import (
"github.com/SigNoz/signoz/pkg/errors"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/swaggest/jsonschema-go"
)
type Volumes struct {
@@ -17,14 +19,14 @@ type Volumes struct {
}
type VolumeRecord struct {
PersistentVolumeClaimName string `json:"persistentVolumeClaimName" required:"true"`
VolumeAvailable float64 `json:"volumeAvailable" required:"true"`
VolumeCapacity float64 `json:"volumeCapacity" required:"true"`
VolumeUsage float64 `json:"volumeUsage" required:"true"`
VolumeInodes float64 `json:"volumeInodes" required:"true"`
VolumeInodesFree float64 `json:"volumeInodesFree" required:"true"`
VolumeInodesUsed float64 `json:"volumeInodesUsed" required:"true"`
Meta map[string]string `json:"meta" required:"true"`
PersistentVolumeClaimName string `json:"persistentVolumeClaimName" required:"true"`
VolumeAvailable float64 `json:"volumeAvailable" required:"true"`
VolumeCapacity float64 `json:"volumeCapacity" required:"true"`
VolumeUsage float64 `json:"volumeUsage" required:"true"`
VolumeInodes float64 `json:"volumeInodes" required:"true"`
VolumeInodesFree float64 `json:"volumeInodesFree" required:"true"`
VolumeInodesUsed float64 `json:"volumeInodesUsed" required:"true"`
Meta VolumeMeta `json:"meta" required:"true"`
}
// PostableVolumes is the request body for the v2 volumes (PVCs) list API.
@@ -102,3 +104,42 @@ func (req *PostableVolumes) UnmarshalJSON(data []byte) error {
*req = PostableVolumes(decoded)
return req.Validate()
}
// VolumeMeta carries the guaranteed volume (PVC) metadata keys as typed fields
// plus any dynamic group-by keys in Extra.
type VolumeMeta struct {
PVCName string `json:"k8s.persistentvolumeclaim.name" required:"true"`
PodUID string `json:"k8s.pod.uid" required:"true"`
PodName string `json:"k8s.pod.name" required:"true"`
NamespaceName string `json:"k8s.namespace.name" required:"true"`
NodeName string `json:"k8s.node.name" required:"true"`
StatefulSetName string `json:"k8s.statefulset.name" required:"true"`
ClusterName string `json:"k8s.cluster.name" required:"true"`
Extra map[string]string `json:"-"`
}
var VolumeMetaKeys = getMetaKeys(&VolumeMeta{})
func NewVolumeMeta(attrs map[string]string) VolumeMeta {
var m VolumeMeta
m.Extra = populateMeta(&m, attrs)
return m
}
func (m VolumeMeta) MarshalJSON() ([]byte, error) {
return marshalMeta(&m, m.Extra)
}
func (m *VolumeMeta) UnmarshalJSON(data []byte) error {
raw, err := splitMeta(data)
if err != nil {
return err
}
m.Extra = populateMeta(m, raw)
return nil
}
func (VolumeMeta) PrepareJSONSchema(s *jsonschema.Schema) error {
addStringAdditionalProps(s)
return nil
}