diff --git a/deployment/base/rbac/master-clusterrole.yaml b/deployment/base/rbac/master-clusterrole.yaml index 529f87e383..b87760d5ac 100644 --- a/deployment/base/rbac/master-clusterrole.yaml +++ b/deployment/base/rbac/master-clusterrole.yaml @@ -3,6 +3,13 @@ kind: ClusterRole metadata: name: nfd-master rules: +- apiGroups: + - "" + resources: + - namespaces + verbs: + - watch + - list - apiGroups: - "" resources: diff --git a/deployment/components/master-config/nfd-master.conf.example b/deployment/components/master-config/nfd-master.conf.example index 8aa0cb29ce..96dd6d130a 100644 --- a/deployment/components/master-config/nfd-master.conf.example +++ b/deployment/components/master-config/nfd-master.conf.example @@ -6,6 +6,21 @@ # enableTaints: false # labelWhiteList: "foo" # resyncPeriod: "2h" +# restrictions: +# disableLabels: true +# disableTaints: true +# disableExtendedResources: true +# disableAnnotations: true +# allowOverwrite: false +# denyNodeFeatureLabels: true +# nodeFeatureNamespaceSelector: +# matchLabels: +# kubernetes.io/metadata.name: "node-feature-discovery" +# matchExpressions: +# - key: "kubernetes.io/metadata.name" +# operator: "In" +# values: +# - "node-feature-discovery" # klog: # addDirHeader: false # alsologtostderr: false diff --git a/deployment/helm/node-feature-discovery/templates/clusterrole.yaml b/deployment/helm/node-feature-discovery/templates/clusterrole.yaml index 958f043fe4..0b76e9afa9 100644 --- a/deployment/helm/node-feature-discovery/templates/clusterrole.yaml +++ b/deployment/helm/node-feature-discovery/templates/clusterrole.yaml @@ -6,6 +6,13 @@ metadata: labels: {{- include "node-feature-discovery.labels" . | nindent 4 }} rules: +- apiGroups: + - "" + resources: + - namespaces + verbs: + - watch + - list - apiGroups: - "" resources: diff --git a/deployment/helm/node-feature-discovery/templates/master.yaml b/deployment/helm/node-feature-discovery/templates/master.yaml index c47086cc1f..d3d7b604a6 100644 --- a/deployment/helm/node-feature-discovery/templates/master.yaml +++ b/deployment/helm/node-feature-discovery/templates/master.yaml @@ -48,15 +48,44 @@ spec: image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} livenessProbe: - {{- toYaml .Values.master.livenessProbe | nindent 12 }} + grpc: + port: {{ .Values.master.healthPort | default "8082" }} + {{- with .Values.master.livenessProbe.initialDelaySeconds }} + initialDelaySeconds: {{ . }} + {{- end }} + {{- with .Values.master.livenessProbe.failureThreshold }} + failureThreshold: {{ . }} + {{- end }} + {{- with .Values.master.livenessProbe.periodSeconds }} + periodSeconds: {{ . }} + {{- end }} + {{- with .Values.master.livenessProbe.timeoutSeconds }} + timeoutSeconds: {{ . }} + {{- end }} readinessProbe: - {{- toYaml .Values.master.readinessProbe | nindent 12 }} + grpc: + port: {{ .Values.master.healthPort | default "8082" }} + {{- with .Values.master.readinessProbe.initialDelaySeconds }} + initialDelaySeconds: {{ . }} + {{- end }} + {{- with .Values.master.readinessProbe.failureThreshold }} + failureThreshold: {{ . }} + {{- end }} + {{- with .Values.master.readinessProbe.periodSeconds }} + periodSeconds: {{ . }} + {{- end }} + {{- with .Values.master.readinessProbe.timeoutSeconds }} + timeoutSeconds: {{ . }} + {{- end }} + {{- with .Values.master.readinessProbe.successThreshold }} + successThreshold: {{ . }} + {{- end }} ports: - containerPort: {{ .Values.master.port | default "8080" }} name: grpc - containerPort: {{ .Values.master.metricsPort | default "8081" }} name: metrics - - containerPort: {{ .Values.master.healthPort | default "8082" }} + - containerPort: {{ .Values.master.healthPort | default "8082" }} name: health env: - name: NODE_NAME @@ -116,7 +145,7 @@ spec: - "-feature-gates={{ $key }}={{ $value }}" {{- end }} - "-metrics={{ .Values.master.metricsPort | default "8081" }}" - - "-grpc-health={{ .Values.master.healthPort | default "8082" }}" + - "-grpc-health={{ .Values.master.healthPort | default "8082" }}" {{- with .Values.master.extraArgs }} {{- toYaml . | nindent 12 }} {{- end }} diff --git a/deployment/helm/node-feature-discovery/templates/topologyupdater.yaml b/deployment/helm/node-feature-discovery/templates/topologyupdater.yaml index 222e729806..da01b1e1eb 100644 --- a/deployment/helm/node-feature-discovery/templates/topologyupdater.yaml +++ b/deployment/helm/node-feature-discovery/templates/topologyupdater.yaml @@ -45,9 +45,38 @@ spec: image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: "{{ .Values.image.pullPolicy }}" livenessProbe: - {{- toYaml .Values.topologyUpdater.livenessProbe | nindent 10 }} + grpc: + port: {{ .Values.topologyUpdater.healthPort | default "8082" }} + {{- with .Values.topologyUpdater.livenessProbe.initialDelaySeconds }} + initialDelaySeconds: {{ . }} + {{- end }} + {{- with .Values.topologyUpdater.livenessProbe.failureThreshold }} + failureThreshold: {{ . }} + {{- end }} + {{- with .Values.topologyUpdater.livenessProbe.periodSeconds }} + periodSeconds: {{ . }} + {{- end }} + {{- with .Values.topologyUpdater.livenessProbe.timeoutSeconds }} + timeoutSeconds: {{ . }} + {{- end }} readinessProbe: - {{- toYaml .Values.topologyUpdater.readinessProbe | nindent 10 }} + grpc: + port: {{ .Values.topologyUpdater.healthPort | default "8082" }} + {{- with .Values.topologyUpdater.readinessProbe.initialDelaySeconds }} + initialDelaySeconds: {{ . }} + {{- end }} + {{- with .Values.topologyUpdater.readinessProbe.failureThreshold }} + failureThreshold: {{ . }} + {{- end }} + {{- with .Values.topologyUpdater.readinessProbe.periodSeconds }} + periodSeconds: {{ . }} + {{- end }} + {{- with .Values.topologyUpdater.readinessProbe.timeoutSeconds }} + timeoutSeconds: {{ . }} + {{- end }} + {{- with .Values.topologyUpdater.readinessProbe.successThreshold }} + successThreshold: {{ . }} + {{- end }} env: - name: NODE_NAME valueFrom: @@ -90,14 +119,14 @@ spec: - "-kubelet-state-dir=" {{- end }} - "-metrics={{ .Values.topologyUpdater.metricsPort | default "8081"}}" - - "-grpc-health={{ .Values.topologyUpdater.healthPort | default "8082" }}" + - "-grpc-health={{ .Values.topologyUpdater.healthPort | default "8082" }}" {{- with .Values.topologyUpdater.extraArgs }} {{- toYaml . | nindent 10 }} {{- end }} ports: - containerPort: {{ .Values.topologyUpdater.metricsPort | default "8081"}} name: metrics - - containerPort: {{ .Values.topologyUpdater.healthPort | default "8082" }} + - containerPort: {{ .Values.topologyUpdater.healthPort | default "8082" }} name: health volumeMounts: {{- if .Values.topologyUpdater.kubeletConfigPath | empty | not }} diff --git a/deployment/helm/node-feature-discovery/templates/worker.yaml b/deployment/helm/node-feature-discovery/templates/worker.yaml index 028b481ad3..c4fbc64678 100644 --- a/deployment/helm/node-feature-discovery/templates/worker.yaml +++ b/deployment/helm/node-feature-discovery/templates/worker.yaml @@ -47,9 +47,38 @@ spec: image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} livenessProbe: - {{- toYaml .Values.worker.livenessProbe | nindent 12 }} + grpc: + port: {{ .Values.worker.healthPort | default "8082" }} + {{- with .Values.worker.livenessProbe.initialDelaySeconds }} + initialDelaySeconds: {{ . }} + {{- end }} + {{- with .Values.worker.livenessProbe.failureThreshold }} + failureThreshold: {{ . }} + {{- end }} + {{- with .Values.worker.livenessProbe.periodSeconds }} + periodSeconds: {{ . }} + {{- end }} + {{- with .Values.worker.livenessProbe.timeoutSeconds }} + timeoutSeconds: {{ . }} + {{- end }} readinessProbe: - {{- toYaml .Values.worker.readinessProbe | nindent 12 }} + grpc: + port: {{ .Values.worker.healthPort | default "8082" }} + {{- with .Values.worker.readinessProbe.initialDelaySeconds }} + initialDelaySeconds: {{ . }} + {{- end }} + {{- with .Values.worker.readinessProbe.failureThreshold }} + failureThreshold: {{ . }} + {{- end }} + {{- with .Values.worker.readinessProbe.periodSeconds }} + periodSeconds: {{ . }} + {{- end }} + {{- with .Values.worker.readinessProbe.timeoutSeconds }} + timeoutSeconds: {{ . }} + {{- end }} + {{- with .Values.worker.readinessProbe.successThreshold }} + successThreshold: {{ . }} + {{- end }} env: - name: NODE_NAME valueFrom: @@ -84,14 +113,14 @@ spec: - "-feature-gates={{ $key }}={{ $value }}" {{- end }} - "-metrics={{ .Values.worker.metricsPort | default "8081"}}" - - "-grpc-health={{ .Values.worker.healthPort | default "8082" }}" + - "-grpc-health={{ .Values.worker.healthPort | default "8082" }}" {{- with .Values.gc.extraArgs }} {{- toYaml . | nindent 8 }} {{- end }} ports: - containerPort: {{ .Values.worker.metricsPort | default "8081"}} name: metrics - - containerPort: {{ .Values.worker.healthPort | default "8082" }} + - containerPort: {{ .Values.worker.healthPort | default "8082" }} name: health volumeMounts: - name: host-boot diff --git a/deployment/helm/node-feature-discovery/values.yaml b/deployment/helm/node-feature-discovery/values.yaml index 8efd982d1a..e4cb018d11 100644 --- a/deployment/helm/node-feature-discovery/values.yaml +++ b/deployment/helm/node-feature-discovery/values.yaml @@ -37,6 +37,21 @@ master: # enableTaints: false # labelWhiteList: "foo" # resyncPeriod: "2h" + # restrictions: + # disableLabels: true + # disableTaints: true + # disableExtendedResources: true + # disableAnnotations: true + # allowOverwrite: false + # denyNodeFeatureLabels: true + # nodeFeatureNamespaceSelector: + # matchLabels: + # kubernetes.io/metadata.name: "node-feature-discovery" + # matchExpressions: + # - key: "kubernetes.io/metadata.name" + # operator: "In" + # values: + # - "node-feature-discovery" # klog: # addDirHeader: false # alsologtostderr: false @@ -157,12 +172,15 @@ master: initialDelaySeconds: 10 # failureThreshold: 3 # periodSeconds: 10 + # timeoutSeconds: 1 readinessProbe: grpc: port: 8082 initialDelaySeconds: 5 failureThreshold: 10 # periodSeconds: 10 + # timeoutSeconds: 1 + # successThreshold: 1 worker: enable: true @@ -433,12 +451,15 @@ worker: initialDelaySeconds: 10 # failureThreshold: 3 # periodSeconds: 10 + # timeoutSeconds: 1 readinessProbe: grpc: port: 8082 initialDelaySeconds: 5 failureThreshold: 10 # periodSeconds: 10 + # timeoutSeconds: 1 + # successThreshold: 1 serviceAccount: # Specifies whether a service account should be created. @@ -527,12 +548,15 @@ topologyUpdater: initialDelaySeconds: 10 # failureThreshold: 3 # periodSeconds: 10 + # timeoutSeconds: 1 readinessProbe: grpc: port: 8082 initialDelaySeconds: 5 failureThreshold: 10 # periodSeconds: 10 + # timeoutSeconds: 1 + # successThreshold: 1 resources: limits: diff --git a/docs/deployment/helm.md b/docs/deployment/helm.md index 8d4064a680..9b387bcf0e 100644 --- a/docs/deployment/helm.md +++ b/docs/deployment/helm.md @@ -5,9 +5,11 @@ sort: 3 --- # Deployment with Helm + {: .no_toc} ## Table of contents + {: .no_toc .text-delta} 1. TOC @@ -71,7 +73,8 @@ To upgrade the `node-feature-discovery` deployment to {{ site.release }} via Hel ### From v0.7 and older -Please see the [uninstallation guide](https://kubernetes-sigs.github.io/node-feature-discovery/v0.7/get-started/deployment-and-usage.html#uninstallation). +Please see +the [uninstallation guide](https://kubernetes-sigs.github.io/node-feature-discovery/v0.7/get-started/deployment-and-usage.html#uninstallation). And then follow the standard [deployment instructions](#deployment). ### From v0.8 - v0.11 @@ -151,23 +154,23 @@ Chart parameters are available. | --------------------------------------------------- | ------ | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `crds.install` | bool | false | Toggle to install and upgrade CRDs from a subchart. Make sure to use it with `--skip-crds` to avoid conflicts. [More info about limitations on CRDs in Helm 3](https://helm.sh/docs/topics/charts/#limitations-on-crds) | | `crds.annotations` | object | {} | Annotations to be added to all CRDs | -| `image.repository` | string | `{{ site.container_image \| split: ":" \| first }}` | NFD image repository | -| `image.tag` | string | `{{ site.release }}` | NFD image tag | -| `image.pullPolicy` | string | `Always` | Image pull policy | -| `imagePullSecrets` | array | [] | ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. If specified, these secrets will be passed to individual puller implementations for them to use. For example, in the case of docker, only DockerConfig type secrets are honored. [More info](https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod). | -| `nameOverride` | string | | Override the name of the chart | -| `fullnameOverride` | string | | Override a default fully qualified app name | -| `tls.enable` | bool | false | Specifies whether to use TLS for communications between components. **NOTE**: this parameter is related to the deprecated gRPC API and will be removed with it in a future release. | -| `tls.certManager` | bool | false | If enabled, requires [cert-manager](https://cert-manager.io/docs/) to be installed and will automatically create the required TLS certificates. **NOTE**: this parameter is related to the deprecated gRPC API and will be removed with it in a future release | -| `tls.certManager.certManagerCertificate.issuerName` | string | | If specified, it will use a pre-existing issuer instead for the required TLS certificates. **NOTE**: this parameter is related to the deprecated gRPC API and will be removed with it in a future release. | +| `image.repository` | string | `{{ site.container_image \| split: ":" \| first }}` | NFD image repository | +| `image.tag` | string | `{{ site.release }}` | NFD image tag | +| `image.pullPolicy` | string | `Always` | Image pull policy | +| `imagePullSecrets` | array | [] | ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. [More info](https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod). | +| `nameOverride` | string | | Override the name of the chart | +| `fullnameOverride` | string | | Override a default fully qualified app name | +| `tls.enable` | bool | false | Specifies whether to use TLS for communications between components. **NOTE**: this parameter is related to the deprecated gRPC API and will be removed with it in a future release. | +| `tls.certManager` | bool | false | If enabled, requires [cert-manager](https://cert-manager.io/docs/) to be installed and will automatically create the required TLS certificates. **NOTE**: this parameter is related to the deprecated gRPC API and will be removed with it in a future release | +| `tls.certManager.certManagerCertificate.issuerName` | string | | If specified, it will use a pre-existing issuer instead for the required TLS certificates. **NOTE**: this parameter is related to the deprecated gRPC API and will be removed with it in a future release. | | `tls.certManager.certManagerCertificate.issuerKind` | string | | Specifies on what kind of issuer is used, can be either ClusterIssuer or Issuer (default). Requires `tls.certManager.certManagerCertificate.issuerName` to be set. **NOTE**: this parameter is related to the deprecated gRPC API and will be removed with it in a future release | -| `featureGates.NodeFeatureAPI` | bool | true | Enable the [NodeFeature](../usage/custom-resources.md#nodefeature) CRD API for communicating node features. This will automatically disable the gRPC communication. | -| `featureGates.NodeFeatureGroupAPI` | bool | false | Enable the [NodeFeatureGroup](../usage/custom-resources.md#nodefeaturegroup) CRD API. | -| `featureGates.DisableAutoPrefix` | bool | false | Enable [DisableAutoPrefix](../reference/feature-gates.md#disableautoprefix) feature gate. Disables automatic prefixing of unprefixed labels, annotations and extended resources. | -| `prometheus.enable` | bool | false | Specifies whether to expose metrics using prometheus operator | -| `prometheus.labels` | dict | {} | Specifies labels for use with the prometheus operator to control how it is selected | -| `prometheus.scrapeInterval` | string | 10s | Specifies the interval by which metrics are scraped | -| `priorityClassName` | string | | The name of the PriorityClass to be used for the NFD pods. | +| `featureGates.NodeFeatureAPI` | bool | true | Enable the [NodeFeature](../usage/custom-resources.md#nodefeature) CRD API for communicating node features. This will automatically disable the gRPC communication. | +| `featureGates.NodeFeatureGroupAPI` | bool | false | Enable the [NodeFeatureGroup](../usage/custom-resources.md#nodefeaturegroup) CRD API. | +| `featureGates.DisableAutoPrefix` | bool | false | Enable [DisableAutoPrefix](../reference/feature-gates.md#disableautoprefix) feature gate. Disables automatic prefixing of unprefixed labels, annotations and extended resources. | +| `prometheus.enable` | bool | false | Specifies whether to expose metrics using prometheus operator | +| `prometheus.labels` | dict | {} | Specifies labels for use with the prometheus operator to control how it is selected | +| `prometheus.scrapeInterval` | string | 10s | Specifies the interval by which metrics are scraped | +| `priorityClassName` | string | | The name of the PriorityClass to be used for the NFD pods. | Metrics are configured to be exposed using prometheus operator API's by default. If you want to expose metrics using the prometheus operator @@ -175,134 +178,167 @@ API's you need to install the prometheus operator in your cluster. ### Master pod parameters -| Name | Type | Default | Description | -| ----------------------------------- | ------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `master.*` | dict | | NFD master deployment configuration | -| `master.enable` | bool | true | Specifies whether nfd-master should be deployed | -| `master.hostNetwork` | bool | false | Specifies whether to enable or disable running the container in the host's network namespace | -| `master.port` | integer | | Specifies the TCP port that nfd-master listens for incoming requests. **NOTE**: this parameter is related to the deprecated gRPC API and will be removed with it in a future release | -| `master.metricsPort` | integer | 8081 | Port on which to expose metrics from components to prometheus operator | -| `master.healthPort` | integer | 8082 | Port on which to expose the grpc health endpoint | -| `master.instance` | string | | Instance name. Used to separate annotation namespaces for multiple parallel deployments | -| `master.resyncPeriod` | string | | NFD API controller resync period. | -| `master.extraLabelNs` | array | [] | List of allowed extra label namespaces | -| `master.resourceLabels` | array | [] | List of labels to be registered as extended resources | -| `master.enableTaints` | bool | false | Specifies whether to enable or disable node tainting | -| `master.crdController` | bool | null | Specifies whether the NFD CRD API controller is enabled. If not set, controller will be enabled if `master.instance` is empty. | -| `master.featureRulesController` | bool | null | DEPRECATED: use `master.crdController` instead | -| `master.replicaCount` | integer | 1 | Number of desired pods. This is a pointer to distinguish between explicit zero and not specified | -| `master.podSecurityContext` | dict | {} | [PodSecurityContext](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod) holds pod-level security attributes and common container settings | -| `master.securityContext` | dict | {} | Container [security settings](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container) | -| `master.serviceAccount.create` | bool | true | Specifies whether a service account should be created | -| `master.serviceAccount.annotations` | dict | {} | Annotations to add to the service account | -| `master.serviceAccount.name` | string | | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | -| `master.rbac.create` | bool | true | Specifies whether to create [RBAC][rbac] configuration for nfd-master | -| `master.service.type` | string | ClusterIP | NFD master service type. **NOTE**: this parameter is related to the deprecated gRPC API and will be removed with it in a future release | -| `master.service.port` | integer | 8080 | NFD master service port. **NOTE**: this parameter is related to the deprecated gRPC API and will be removed with it in a future release | -| `master.resources.limits` | dict | {memory: 4Gi} | NFD master pod [resources limits](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#requests-and-limits) | -| `master.resources.requests` | dict | {cpu: 100m, memory: 128Mi} | NFD master pod [resources requests](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#requests-and-limits). You may want to use the same value for `requests.memory` and `limits.memory`. The “requests” value affects scheduling to accommodate pods on nodes. If there is a large difference between “requests” and “limits” and nodes experience memory pressure, the kernel may invoke the OOM Killer, even if the memory does not exceed the “limits” threshold. This can cause unexpected pod evictions. Memory cannot be compressed and once allocated to a pod, it can only be reclaimed by killing the pod. [Natan Yellin 22/09/2022](https://home.robusta.dev/blog/kubernetes-memory-limit) that discusses this issue. | -| `master.tolerations` | dict | _Schedule to control-plane node_ | NFD master pod [tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) | -| `master.annotations` | dict | {} | NFD master pod [annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) | -| `master.affinity` | dict | | NFD master pod required [node affinity](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/) | -| `master.deploymentAnnotations` | dict | {} | NFD master deployment [annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) | -| `master.nfdApiParallelism` | integer | 10 | Specifies the maximum number of concurrent node updates. | -| `master.config` | dict | | NFD master [configuration](../reference/master-configuration-reference) | -| `master.extraArgs` | array | [] | Additional [command line arguments](../reference/master-commandline-reference.md) to pass to nfd-master | -| `master.extraEnvs` | array | [] | Additional environment variables to pass to nfd-master | -| `master.revisionHistoryLimit` | integer | | Specify how many old ReplicaSets for this Deployment you want to retain. [revisionHistoryLimit](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#revision-history-limit) | -| `master.livenessProbe` | dict | {"grpc":{"port":8082},"initialDelaySeconds":10} | NFD master pod [liveness probe](https://kubernetes.io/docs/concepts/configuration/liveness-readiness-startup-probes/#liveness-probe) | -| `master.readinessProbe` | dict | {"grpc":{"port":8082},"initialDelaySeconds":5,"failureThreshold": 10} | NFD master pod [readiness probe](https://kubernetes.io/docs/concepts/configuration/liveness-readiness-startup-probes/#readiness-probe)| +| Name | Type | Default | Description | +|---------------------------------------------|---------|----------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `master.*` | dict | | NFD master deployment configuration | +| `master.enable` | bool | true | Specifies whether nfd-master should be deployed | +| `master.hostNetwork` | bool | false | Specifies whether to enable or disable running the container in the host's network namespace | +| `master.port` | integer | | Specifies the TCP port that nfd-master listens for incoming requests. **NOTE**: this parameter is related to the deprecated gRPC API and will be removed with it in a future release | +| `master.metricsPort` | integer | 8081 | Port on which to expose metrics from components to prometheus operator | +| `master.healthPort` | integer | 8082 | Port on which to expose the grpc health endpoint, will be also used for the probes | +| `master.instance` | string | | Instance name. Used to separate annotation namespaces for multiple parallel deployments | +| `master.resyncPeriod` | string | | NFD API controller resync period. | +| `master.extraLabelNs` | array | [] | List of allowed extra label namespaces | +| `master.resourceLabels` | array | [] | List of labels to be registered as extended resources | +| `master.enableTaints` | bool | false | Specifies whether to enable or disable node tainting | +| `master.crdController` | bool | null | Specifies whether the NFD CRD API controller is enabled. If not set, controller will be enabled if `master.instance` is empty. | +| `master.featureRulesController` | bool | null | DEPRECATED: use `master.crdController` instead | +| `master.replicaCount` | integer | 1 | Number of desired pods. This is a pointer to distinguish between explicit zero and not specified | +| `master.podSecurityContext` | dict | {} | [PodSecurityContext](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod) holds pod-level security attributes and common container settings | +| `master.securityContext` | dict | {} | Container [security settings](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container) | +| `master.serviceAccount.create` | bool | true | Specifies whether a service account should be created | +| `master.serviceAccount.annotations` | dict | {} | Annotations to add to the service account | +| `master.serviceAccount.name` | string | | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | +| `master.rbac.create` | bool | true | Specifies whether to create [RBAC][rbac] configuration for nfd-master | +| `master.service.type` | string | ClusterIP | NFD master service type. **NOTE**: this parameter is related to the deprecated gRPC API and will be removed with it in a future release | +| `master.service.port` | integer | 8080 | NFD master service port. **NOTE**: this parameter is related to the deprecated gRPC API and will be removed with it in a future release | +| `master.resources.limits` | dict | {memory: 4Gi} | NFD master pod [resources limits](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#requests-and-limits) | +| `master.resources.requests` | dict | {cpu: 100m, memory: 128Mi} | NFD master pod [resources requests](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#requests-and-limits). See `[0]` for more info | +| `master.tolerations` | dict | _Schedule to control-plane node_ | NFD master pod [tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) | +| `master.annotations` | dict | {} | NFD master pod [annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) | +| `master.affinity` | dict | | NFD master pod required [node affinity](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/) | +| `master.deploymentAnnotations` | dict | {} | NFD master deployment [annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) | +| `master.nfdApiParallelism` | integer | 10 | Specifies the maximum number of concurrent node updates. | +| `master.config` | dict | | NFD master [configuration](../reference/master-configuration-reference) | +| `master.extraArgs` | array | [] | Additional [command line arguments](../reference/master-commandline-reference.md) to pass to nfd-master | +| `master.extraEnvs` | array | [] | Additional environment variables to pass to nfd-master | +| `master.revisionHistoryLimit` | integer | | Specify how many old ReplicaSets for this Deployment you want to retain. [revisionHistoryLimit](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#revision-history-limit) | +| `master.livenessProbe.initialDelaySeconds` | integer | 10 | Specifies the number of seconds after the container has started before liveness probes are initiated. | +| `master.livenessProbe.failureThreshold` | integer | 3 (by Kubernetes) | Specifies the number of consecutive failures of liveness probes before considering the pod as not ready. | +| `master.livenessProbe.periodSeconds` | integer | 10 (by Kubernetes) | Specifies how often (in seconds) to perform the liveness probe. | +| `master.livenessProbe.timeoutSeconds` | integer | 1 (by Kubernetes) | Specifies the number of seconds after which the probe times out. | +| `master.readinessProbe.initialDelaySeconds` | integer | 5 | Specifies the number of seconds after the container has started before readiness probes are initiated. | +| `master.readinessProbe.failureThreshold` | integer | 10 | Specifies the number of consecutive failures of readiness probes before considering the pod as not ready. | +| `master.readinessProbe.periodSeconds` | integer | 10 (by Kubernetes) | Specifies how often (in seconds) to perform the readiness probe. | +| `master.readinessProbe.timeoutSeconds` | integer | 1 (by Kubernetes) | Specifies the number of seconds after which the probe times out. | +| `master.readinessProbe.successThreshold` | integer | 1 (by Kubernetes) | Specifies the number of consecutive successes of readiness probes before considering the pod as ready. | + +> `[0]` Additional info for `master.resources.requests`: \ +> You may want to use the same value for `requests.memory` and `limits.memory`. +> The “requests” value affects scheduling to accommodate pods on nodes. +> If there is a large difference between “requests” and “limits” and nodes +> experience memory pressure, the kernel may invoke the OOM Killer, even if +> the memory does not exceed the “limits” threshold. +> This can cause unexpected pod evictions. Memory cannot be compressed and +> once allocated to a pod, it can only be reclaimed by killing the pod. +> [Natan Yellin 22/09/2022](https://home.robusta.dev/blog/kubernetes-memory-limit) +> that discusses this issue. ### Worker pod parameters -| Name | Type | Default | Description | -| ----------------------------------- | ------ | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `worker.*` | dict | | NFD worker daemonset configuration | -| `worker.enable` | bool | true | Specifies whether nfd-worker should be deployed | -| `worker.hostNetwork` | bool | false | Specifies whether to enable or disable running the container in the host's network namespace | -| `worker.metricsPort` | int | 8081 | Port on which to expose metrics from components to prometheus operator | -| `worker.healthPort` | int | 8082 | Port on which to expose the grpc health endpoint | -| `worker.config` | dict | | NFD worker [configuration](../reference/worker-configuration-reference) | -| `worker.podSecurityContext` | dict | {} | [PodSecurityContext](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod) holds pod-level security attributes and common container settins | -| `worker.securityContext` | dict | {} | Container [security settings](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container) | -| `worker.serviceAccount.create` | bool | true | Specifies whether a service account for nfd-worker should be created | -| `worker.serviceAccount.annotations` | dict | {} | Annotations to add to the service account for nfd-worker | -| `worker.serviceAccount.name` | string | | The name of the service account to use for nfd-worker. If not set and create is true, a name is generated using the fullname template (suffixed with `-worker`) | -| `worker.rbac.create` | bool | true | Specifies whether to create [RBAC][rbac] configuration for nfd-worker | -| `worker.mountUsrSrc` | bool | false | Specifies whether to allow users to mount the hostpath /user/src. Does not work on systems without /usr/src AND a read-only /usr | -| `worker.resources.limits` | dict | {memory: 512Mi} | NFD worker pod [resources limits](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#requests-and-limits) | -| `worker.resources.requests` | dict | {cpu: 5m, memory: 64Mi} | NFD worker pod [resources requests](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#requests-and-limits) | -| `worker.nodeSelector` | dict | {} | NFD worker pod [node selector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) | -| `worker.tolerations` | dict | {} | NFD worker pod [node tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) | -| `worker.priorityClassName` | string | | NFD worker pod [priority class](https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/) | -| `worker.annotations` | dict | {} | NFD worker pod [annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) | -| `worker.daemonsetAnnotations` | dict | {} | NFD worker daemonset [annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) | -| `worker.extraArgs` | array | [] | Additional [command line arguments](../reference/worker-commandline-reference.md) to pass to nfd-worker | -| `worker.extraEnvs` | array | [] | Additional environment variables to pass to nfd-worker | -| `worker.revisionHistoryLimit` | integer | | Specify how many old ControllerRevisions for this DaemonSet you want to retain. [revisionHistoryLimit](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/daemon-set-v1/ #DaemonSetSpec) | -| `worker.livenessProbe` | dict | {"grpc":{"port":8082},"initialDelaySeconds":10} | NFD worker pod [liveness probe](https://kubernetes.io/docs/concepts/configuration/liveness-readiness-startup-probes/#liveness-probe) | -| `worker.readinessProbe` | dict | {"grpc":{"port":8082},"initialDelaySeconds":5,"failureThreshold": 10} | NFD worker pod [readiness probe](https://kubernetes.io/docs/concepts/configuration/liveness-readiness-startup-probes/#readiness-probe)| +| Name | Type | Default | Description | +|---------------------------------------------|---------|-------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `worker.*` | dict | | NFD worker daemonset configuration | +| `worker.enable` | bool | true | Specifies whether nfd-worker should be deployed | +| `worker.hostNetwork` | bool | false | Specifies whether to enable or disable running the container in the host's network namespace | +| `worker.metricsPort` | int | 8081 | Port on which to expose metrics from components to prometheus operator | +| `worker.healthPort` | int | 8082 | Port on which to expose the grpc health endpoint, will be also used for the probes | +| `worker.config` | dict | | NFD worker [configuration](../reference/worker-configuration-reference) | +| `worker.podSecurityContext` | dict | {} | [PodSecurityContext](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod) holds pod-level security attributes and common container settins | +| `worker.securityContext` | dict | {} | Container [security settings](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container) | +| `worker.serviceAccount.create` | bool | true | Specifies whether a service account for nfd-worker should be created | +| `worker.serviceAccount.annotations` | dict | {} | Annotations to add to the service account for nfd-worker | +| `worker.serviceAccount.name` | string | | The name of the service account to use for nfd-worker. If not set and create is true, a name is generated using the fullname template (suffixed with `-worker`) | +| `worker.rbac.create` | bool | true | Specifies whether to create [RBAC][rbac] configuration for nfd-worker | +| `worker.mountUsrSrc` | bool | false | Specifies whether to allow users to mount the hostpath /user/src. Does not work on systems without /usr/src AND a read-only /usr | +| `worker.resources.limits` | dict | {memory: 512Mi} | NFD worker pod [resources limits](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#requests-and-limits) | +| `worker.resources.requests` | dict | {cpu: 5m, memory: 64Mi} | NFD worker pod [resources requests](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#requests-and-limits) | +| `worker.nodeSelector` | dict | {} | NFD worker pod [node selector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) | +| `worker.tolerations` | dict | {} | NFD worker pod [node tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) | +| `worker.priorityClassName` | string | | NFD worker pod [priority class](https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/) | +| `worker.annotations` | dict | {} | NFD worker pod [annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) | +| `worker.daemonsetAnnotations` | dict | {} | NFD worker daemonset [annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) | +| `worker.extraArgs` | array | [] | Additional [command line arguments](../reference/worker-commandline-reference.md) to pass to nfd-worker | +| `worker.extraEnvs` | array | [] | Additional environment variables to pass to nfd-worker | +| `worker.revisionHistoryLimit` | integer | | Specify how many old ControllerRevisions for this DaemonSet you want to retain. [revisionHistoryLimit](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/daemon-set-v1/ #DaemonSetSpec) | +| `worker.livenessProbe.initialDelaySeconds` | integer | 10 | Specifies the number of seconds after the container has started before liveness probes are initiated. | +| `worker.livenessProbe.failureThreshold` | integer | 3 (by Kubernetes) | Specifies the number of consecutive failures of liveness probes before considering the pod as not ready. | +| `worker.livenessProbe.periodSeconds` | integer | 10 (by Kubernetes) | Specifies how often (in seconds) to perform the liveness probe. | +| `worker.livenessProbe.timeoutSeconds` | integer | 1 (by Kubernetes) | Specifies the number of seconds after which the probe times out. | +| `worker.readinessProbe.initialDelaySeconds` | integer | 5 | Specifies the number of seconds after the container has started before readiness probes are initiated. | +| `worker.readinessProbe.failureThreshold` | integer | 10 | Specifies the number of consecutive failures of readiness probes before considering the pod as not ready. | +| `worker.readinessProbe.periodSeconds` | integer | 10 (by Kubernetes) | Specifies how often (in seconds) to perform the readiness probe. | +| `worker.readinessProbe.timeoutSeconds` | integer | 1 (by Kubernetes) | Specifies the number of seconds after which the probe times out. | +| `worker.readinessProbe.successThreshold` | integer | 1 (by Kubernetes) | Specifies the number of consecutive successes of readiness probes before considering the pod as ready. | ### Topology updater parameters -| Name | Type | Default | Description | -| --------------------------------------------- | ------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `topologyUpdater.*` | dict | | NFD Topology Updater configuration | -| `topologyUpdater.enable` | bool | false | Specifies whether the NFD Topology Updater should be created | -| `topologyUpdater.hostNetwork` | bool | false | Specifies whether to enable or disable running the container in the host's network namespace | -| `topologyUpdater.createCRDs` | bool | false | Specifies whether the NFD Topology Updater CRDs should be created | -| `topologyUpdater.serviceAccount.create` | bool | true | Specifies whether the service account for topology updater should be created | -| `topologyUpdater.serviceAccount.annotations` | dict | {} | Annotations to add to the service account for topology updater | -| `topologyUpdater.serviceAccount.name` | string | | The name of the service account for topology updater to use. If not set and create is true, a name is generated using the fullname template and `-topology-updater` suffix | -| `topologyUpdater.rbac.create` | bool | true | Specifies whether to create [RBAC][rbac] configuration for topology updater | -| `topologyUpdater.metricsPort` | integer | 8081 | Port on which to expose prometheus metrics | -| `topologyUpdater.healthPort` | integer | 8082 | Port on which to expose the grpc health endpoint | -| `topologyUpdater.kubeletConfigPath` | string | "" | Specifies the kubelet config host path | -| `topologyUpdater.kubeletPodResourcesSockPath` | string | "" | Specifies the kubelet sock path to read pod resources | -| `topologyUpdater.updateInterval` | string | 60s | Time to sleep between CR updates. Non-positive value implies no CR update. | -| `topologyUpdater.watchNamespace` | string | `*` | Namespace to watch pods, `*` for all namespaces | -| `topologyUpdater.podSecurityContext` | dict | {} | [PodSecurityContext](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod) holds pod-level security attributes and common container sett| -| `topologyUpdater.securityContext` | dict | {} | Container [security settings](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container) | -| `topologyUpdater.resources.limits` | dict | {memory: 60Mi} | NFD Topology Updater pod [resources limits](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#requests-and-limits) | -| `topologyUpdater.resources.requests` | dict | {cpu: 50m, memory: 40Mi} | NFD Topology Updater pod [resources requests](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#requests-and-limits) | -| `topologyUpdater.nodeSelector` | dict | {} | Topology updater pod [node selector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) | -| `topologyUpdater.tolerations` | dict | {} | Topology updater pod [node tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) | -| `topologyUpdater.annotations` | dict | {} | Topology updater pod [annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) | -| `topologyUpdater.daemonsetAnnotations` | dict | {} | Topology updater daemonset [annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) | -| `topologyUpdater.affinity` | dict | {} | Topology updater pod [affinity](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/) | -| `topologyUpdater.config` | dict | | [configuration](../reference/topology-updater-configuration-reference) | -| `topologyUpdater.podSetFingerprint` | bool | true | Enables compute and report of pod fingerprint in NRT objects. | -| `topologyUpdater.kubeletStateDir` | string | /var/lib/kubelet | Specifies kubelet state directory path for watching state and checkpoint files. Empty value disables kubelet state tracking. | -| `topologyUpdater.extraArgs` | array | [] | Additional [command line arguments](../reference/topology-updater-commandline-reference.md) to pass to nfd-topology-updater | -| `topologyUpdater.extraEnvs` | array | [] | Additional environment variables to pass to nfd-topology-updater | -| `topologyUpdater.revisionHistoryLimit` | integer | | Specify how many old ControllerRevisions for this DaemonSet you want to retain. [revisionHistoryLimit](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/daemon-set-v1/#DaemonSetSpec) | -| `topologyUpdater.livenessProbe` | dict | {"grpc":{"port":8082},"initialDelaySeconds":10} | Topology updater pod [liveness probe](https://kubernetes.io/docs/concepts/configuration/liveness-readiness-startup-probes/#liveness-probe) | -| `topologyUpdater.readinessProbe` | dict | {"grpc":{"port":8082},"initialDelaySeconds":5,"failureThreshold": 10} | Topology updater pod [readiness probe](https://kubernetes.io/docs/concepts/configuration/liveness-readiness-startup-probes/#readiness-probe)| +| Name | Type | Default | Description | +|------------------------------------------------------|---------|--------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `topologyUpdater.*` | dict | | NFD Topology Updater configuration | +| `topologyUpdater.enable` | bool | false | Specifies whether the NFD Topology Updater should be created | +| `topologyUpdater.hostNetwork` | bool | false | Specifies whether to enable or disable running the container in the host's network namespace | +| `topologyUpdater.createCRDs` | bool | false | Specifies whether the NFD Topology Updater CRDs should be created | +| `topologyUpdater.serviceAccount.create` | bool | true | Specifies whether the service account for topology updater should be created | +| `topologyUpdater.serviceAccount.annotations` | dict | {} | Annotations to add to the service account for topology updater | +| `topologyUpdater.serviceAccount.name` | string | | The name of the service account for topology updater to use. If not set and create is true, a name is generated using the fullname template and `-topology-updater` suffix | +| `topologyUpdater.rbac.create` | bool | true | Specifies whether to create [RBAC][rbac] configuration for topology updater | +| `topologyUpdater.metricsPort` | integer | 8081 | Port on which to expose prometheus metrics | +| `topologyUpdater.healthPort` | integer | 8082 | Port on which to expose the grpc health endpoint, will be also used for the probes | +| `topologyUpdater.kubeletConfigPath` | string | "" | Specifies the kubelet config host path | +| `topologyUpdater.kubeletPodResourcesSockPath` | string | "" | Specifies the kubelet sock path to read pod resources | +| `topologyUpdater.updateInterval` | string | 60s | Time to sleep between CR updates. Non-positive value implies no CR update. | +| `topologyUpdater.watchNamespace` | string | `*` | Namespace to watch pods, `*` for all namespaces | +| `topologyUpdater.podSecurityContext` | dict | {} | [PodSecurityContext](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod) holds pod-level security attributes and common container sett | +| `topologyUpdater.securityContext` | dict | {} | Container [security settings](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container) | +| `topologyUpdater.resources.limits` | dict | {memory: 60Mi} | NFD Topology Updater pod [resources limits](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#requests-and-limits) | +| `topologyUpdater.resources.requests` | dict | {cpu: 50m, memory: 40Mi} | NFD Topology Updater pod [resources requests](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#requests-and-limits) | +| `topologyUpdater.nodeSelector` | dict | {} | Topology updater pod [node selector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) | +| `topologyUpdater.tolerations` | dict | {} | Topology updater pod [node tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) | +| `topologyUpdater.annotations` | dict | {} | Topology updater pod [annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) | +| `topologyUpdater.daemonsetAnnotations` | dict | {} | Topology updater daemonset [annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) | +| `topologyUpdater.affinity` | dict | {} | Topology updater pod [affinity](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/) | +| `topologyUpdater.config` | dict | | [configuration](../reference/topology-updater-configuration-reference) | +| `topologyUpdater.podSetFingerprint` | bool | true | Enables compute and report of pod fingerprint in NRT objects. | +| `topologyUpdater.kubeletStateDir` | string | /var/lib/kubelet | Specifies kubelet state directory path for watching state and checkpoint files. Empty value disables kubelet state tracking. | +| `topologyUpdater.extraArgs` | array | [] | Additional [command line arguments](../reference/topology-updater-commandline-reference.md) to pass to nfd-topology-updater | +| `topologyUpdater.extraEnvs` | array | [] | Additional environment variables to pass to nfd-topology-updater | +| `topologyUpdater.revisionHistoryLimit` | integer | | Specify how many old ControllerRevisions for this DaemonSet you want to retain. [revisionHistoryLimit](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/daemon-set-v1/#DaemonSetSpec) | +| `topologyUpdater.livenessProbe.initialDelaySeconds` | integer | 10 | Specifies the number of seconds after the container has started before liveness probes are initiated. | +| `topologyUpdater.livenessProbe.failureThreshold` | integer | 3 (by Kubernetes) | Specifies the number of consecutive failures of liveness probes before considering the pod as not ready. | +| `topologyUpdater.livenessProbe.periodSeconds` | integer | 10 (by Kubernetes) | Specifies how often (in seconds) to perform the liveness probe. | +| `topologyUpdater.livenessProbe.timeoutSeconds` | integer | 1 (by Kubernetes) | Specifies the number of seconds after which the probe times out. | +| `topologyUpdater.readinessProbe.initialDelaySeconds` | integer | 5 | Specifies the number of seconds after the container has started before readiness probes are initiated. | +| `topologyUpdater.readinessProbe.failureThreshold` | integer | 10 | Specifies the number of consecutive failures of readiness probes before considering the pod as not ready. | +| `topologyUpdater.readinessProbe.periodSeconds` | integer | 10 (by Kubernetes) | Specifies how often (in seconds) to perform the readiness probe. | +| `topologyUpdater.readinessProbe.timeoutSeconds` | integer | 1 (by Kubernetes) | Specifies the number of seconds after which the probe times out. | +| `topologyUpdater.readinessProbe.successThreshold` | integer | 1 (by Kubernetes) | Specifies the number of consecutive successes of readiness probes before considering the pod as ready. | ### Garbage collector parameters -| Name | Type | Default | Description | -| ------------------------------------- | ------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `gc.*` | dict | | NFD Garbage Collector configuration | -| `gc.enable` | bool | true | Specifies whether the NFD Garbage Collector should be created | -| `gc.hostNetwork` | bool | false | Specifies whether to enable or disable running the container in the host's network namespace | -| `gc.serviceAccount.create` | bool | true | Specifies whether the service account for garbage collector should be created | -| `gc.serviceAccount.annotations` | dict | {} | Annotations to add to the service account for garbage collector | -| `gc.serviceAccount.name` | string | | The name of the service account for garbage collector to use. If not set and create is true, a name is generated using the fullname template and `-gc` suffix | -| `gc.rbac.create` | bool | true | Specifies whether to create [RBAC][rbac] configuration for garbage collector | -| `gc.interval` | string | 1h | Time between periodic garbage collector runs | -| `gc.podSecurityContext` | dict | {} | [PodSecurityContext](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod) holds pod-level security attributes and common container settings | -| `gc.resources.limits` | dict | {memory: 1Gi} | NFD Garbage Collector pod [resources limits](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#requests-and-limits) | -| `gc.resources.requests` | dict | {cpu: 10m, memory: 128Mi} | NFD Garbage Collector pod [resources requests](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#requests-and-limits) | -| `gc.metricsPort` | integer | 8081 | Port on which to serve Prometheus metrics | -| `gc.nodeSelector` | dict | {} | Garbage collector pod [node selector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) | -| `gc.tolerations` | dict | {} | Garbage collector pod [node tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) | -| `gc.annotations` | dict | {} | Garbage collector pod [annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) | -| `gc.deploymentAnnotations` | dict | {} | Garbage collector deployment [annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) | -| `gc.affinity` | dict | {} | Garbage collector pod [affinity](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/) | -| `gc.extraArgs` | array | [] | Additional [command line arguments](../reference/gc-commandline-reference.md) to pass to nfd-gc | -| `gc.extraEnvs` | array | [] | Additional environment variables to pass to nfd-gc | -| `gc.revisionHistoryLimit` | integer | | Specify how many old ReplicaSets for this Deployment you want to retain. [revisionHistoryLimit](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#revision-history-limit) | +| Name | Type | Default | Description | +|---------------------------------|---------|---------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `gc.*` | dict | | NFD Garbage Collector configuration | +| `gc.enable` | bool | true | Specifies whether the NFD Garbage Collector should be created | +| `gc.hostNetwork` | bool | false | Specifies whether to enable or disable running the container in the host's network namespace | +| `gc.serviceAccount.create` | bool | true | Specifies whether the service account for garbage collector should be created | +| `gc.serviceAccount.annotations` | dict | {} | Annotations to add to the service account for garbage collector | +| `gc.serviceAccount.name` | string | | The name of the service account for garbage collector to use. If not set and create is true, a name is generated using the fullname template and `-gc` suffix | +| `gc.rbac.create` | bool | true | Specifies whether to create [RBAC][rbac] configuration for garbage collector | +| `gc.interval` | string | 1h | Time between periodic garbage collector runs | +| `gc.podSecurityContext` | dict | {} | [PodSecurityContext](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod) holds pod-level security attributes and common container settings | +| `gc.resources.limits` | dict | {memory: 1Gi} | NFD Garbage Collector pod [resources limits](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#requests-and-limits) | +| `gc.resources.requests` | dict | {cpu: 10m, memory: 128Mi} | NFD Garbage Collector pod [resources requests](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#requests-and-limits) | +| `gc.metricsPort` | integer | 8081 | Port on which to serve Prometheus metrics | +| `gc.nodeSelector` | dict | {} | Garbage collector pod [node selector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) | +| `gc.tolerations` | dict | {} | Garbage collector pod [node tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) | +| `gc.annotations` | dict | {} | Garbage collector pod [annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) | +| `gc.deploymentAnnotations` | dict | {} | Garbage collector deployment [annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) | +| `gc.affinity` | dict | {} | Garbage collector pod [affinity](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/) | +| `gc.extraArgs` | array | [] | Additional [command line arguments](../reference/gc-commandline-reference.md) to pass to nfd-gc | +| `gc.extraEnvs` | array | [] | Additional environment variables to pass to nfd-gc | +| `gc.revisionHistoryLimit` | integer | | Specify how many old ReplicaSets for this Deployment you want to retain. [revisionHistoryLimit](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#revision-history-limit) | + [rbac]: https://kubernetes.io/docs/reference/access-authn-authz/rbac/ diff --git a/docs/reference/master-configuration-reference.md b/docs/reference/master-configuration-reference.md index 863cb2e135..b7a06fe0a4 100644 --- a/docs/reference/master-configuration-reference.md +++ b/docs/reference/master-configuration-reference.md @@ -338,3 +338,104 @@ Comma-separated list of `pattern=N` settings for file-filtered logging. Default: *empty* Run-time configurable: yes + +## restrictions (EXPERIMENTAL) + +The following options specify the restrictions that can be applied by the +nfd-master on the deployed Custom Resources in the cluster. + +### restrictions.nodeFeatureNamespaceSelector + +The `nodeFeatureNamespaceSelector` option specifies the NodeFeatures namespaces +to watch, which can be selected by using `metav1.LabelSelector` as a type for +this option. An empty value selects all namespaces to be watched. + +Default: *empty* + +Example: + +```yaml +restrictions: + nodeFeatureNamespaceSelector: + matchLabels: + kubernetes.io/metadata.name: "node-feature-discovery" + matchExpressions: + - key: "kubernetes.io/metadata.name" + operator: "In" + values: + - "node-feature-discovery" +``` + +### restrictions.disableLabels + +The `disableLabels` option controls whether to allow creation of node labels +from NodeFeature and NodeFeatureRule CRs or not. + +Default: false + +Example: + +```yaml +restrictions: + disableLabels: true +``` + +### restrictions.disableExtendedResources + +The `disableExtendedResources` option controls whether to allow creation of +node extended resources from NodeFeatureRule CR or not. + +Default: false + +Example: + +```yaml +restrictions: + disableExtendedResources: true +``` + +### restrictions.disableAnnotations + +he `disableAnnotations` option controls whether to allow creation of node annotations +from NodeFeatureRule CR or not. + +Default: false + +Example: + +```yaml +restrictions: + disableAnnotations: true +``` + +### restrictions.allowOverwrite + +The `allowOverwrite` option controls whether NFD is allowed to overwrite and +take over management of existing node labels, annotations, and extended resources. +Labels, annotations and extended resources created by NFD itself are not affected +(overwrite cannot be disabled). NFD tracks the labels, annotations and extended +resources that it manages with specific +[node annotations](../get-started/introduction.md#node-annotations). + +Default: true + +Example: + +```yaml +restrictions: + allowOverwrite: false +``` + +### restrictions.denyNodeFeatureLabels + +The `denyNodeFeatureLabels` option specifies whether to deny labels from 3rd party +NodeFeature objects or not. NodeFeature objects created by nfd-worker are not affected. + +Default: false + +Example: + +```yaml +restrictions: + denyNodeFeatureLabels: true +``` diff --git a/go.mod b/go.mod index 04f2de5247..838d2d50f1 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/klauspost/cpuid/v2 v2.2.8 github.com/onsi/ginkgo/v2 v2.20.2 github.com/onsi/gomega v1.34.2 - github.com/opencontainers/runc v1.1.14 + github.com/opencontainers/runc v1.1.15 github.com/prometheus/client_golang v1.18.0 github.com/smartystreets/goconvey v1.8.1 github.com/spf13/cobra v1.8.1 diff --git a/go.sum b/go.sum index 28404c15dc..373028b421 100644 --- a/go.sum +++ b/go.sum @@ -194,8 +194,8 @@ github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8= github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/runc v1.1.14 h1:rgSuzbmgz5DUJjeSnw337TxDbRuqjs6iqQck/2weR6w= -github.com/opencontainers/runc v1.1.14/go.mod h1:E4C2z+7BxR7GHXp0hAY53mek+x49X1LjPNeMTfRGvOA= +github.com/opencontainers/runc v1.1.15 h1:QMmSU2q1YUg3iOJX11phnaDi2A5/zhx4BR6h+XZ1DMA= +github.com/opencontainers/runc v1.1.15/go.mod h1:E4C2z+7BxR7GHXp0hAY53mek+x49X1LjPNeMTfRGvOA= github.com/opencontainers/runtime-spec v1.1.0-rc.2 h1:ucBtEms2tamYYW/SvGpvq9yUN0NEVL6oyLEwDcTSrk8= github.com/opencontainers/runtime-spec v1.1.0-rc.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU= diff --git a/pkg/nfd-master/namespace-lister.go b/pkg/nfd-master/namespace-lister.go new file mode 100644 index 0000000000..ea8b97a4c1 --- /dev/null +++ b/pkg/nfd-master/namespace-lister.go @@ -0,0 +1,58 @@ +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package nfdmaster + +import ( + "time" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/informers" + k8sclient "k8s.io/client-go/kubernetes" + v1lister "k8s.io/client-go/listers/core/v1" +) + +// NamespaceLister lists kubernetes namespaces. +type NamespaceLister struct { + namespaceLister v1lister.NamespaceLister + labelsSelector labels.Selector + stopChan chan struct{} +} + +func newNamespaceLister(k8sClient k8sclient.Interface, labelsSelector labels.Selector) *NamespaceLister { + factory := informers.NewSharedInformerFactory(k8sClient, time.Hour) + namespaceLister := factory.Core().V1().Namespaces().Lister() + + stopChan := make(chan struct{}) + factory.Start(stopChan) // runs in background + factory.WaitForCacheSync(stopChan) + + return &NamespaceLister{ + namespaceLister: namespaceLister, + labelsSelector: labelsSelector, + stopChan: stopChan, + } +} + +// list returns all kubernetes namespaces. +func (lister *NamespaceLister) list() ([]*corev1.Namespace, error) { + return lister.namespaceLister.List(lister.labelsSelector) +} + +// stop closes the channel used by the lister +func (lister *NamespaceLister) stop() { + close(lister.stopChan) +} diff --git a/pkg/nfd-master/nfd-api-controller.go b/pkg/nfd-master/nfd-api-controller.go index 29cba271ec..4127a8b036 100644 --- a/pkg/nfd-master/nfd-api-controller.go +++ b/pkg/nfd-master/nfd-api-controller.go @@ -22,6 +22,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" utilruntime "k8s.io/apimachinery/pkg/util/runtime" + k8sclient "k8s.io/client-go/kubernetes" restclient "k8s.io/client-go/rest" "k8s.io/client-go/tools/cache" "k8s.io/klog/v2" @@ -46,12 +47,16 @@ type nfdController struct { updateOneNodeChan chan string updateAllNodeFeatureGroupsChan chan struct{} updateNodeFeatureGroupChan chan string + + namespaceLister *NamespaceLister } type nfdApiControllerOptions struct { - DisableNodeFeature bool - DisableNodeFeatureGroup bool - ResyncPeriod time.Duration + DisableNodeFeature bool + DisableNodeFeatureGroup bool + ResyncPeriod time.Duration + K8sClient k8sclient.Interface + NodeFeatureNamespaceSelector *metav1.LabelSelector } func init() { @@ -67,8 +72,16 @@ func newNfdController(config *restclient.Config, nfdApiControllerOptions nfdApiC updateNodeFeatureGroupChan: make(chan string), } - nfdClient := nfdclientset.NewForConfigOrDie(config) + if nfdApiControllerOptions.NodeFeatureNamespaceSelector != nil { + labelMap, err := metav1.LabelSelectorAsSelector(nfdApiControllerOptions.NodeFeatureNamespaceSelector) + if err != nil { + klog.ErrorS(err, "failed to convert label selector to map", "selector", nfdApiControllerOptions.NodeFeatureNamespaceSelector) + return nil, err + } + c.namespaceLister = newNamespaceLister(nfdApiControllerOptions.K8sClient, labelMap) + } + nfdClient := nfdclientset.NewForConfigOrDie(config) klog.V(2).InfoS("initializing new NFD API controller", "options", utils.DelayedDumper(nfdApiControllerOptions)) informerFactory := nfdinformers.NewSharedInformerFactory(nfdClient, nfdApiControllerOptions.ResyncPeriod) @@ -89,7 +102,11 @@ func newNfdController(config *restclient.Config, nfdApiControllerOptions nfdApiC AddFunc: func(obj interface{}) { nfr := obj.(*nfdv1alpha1.NodeFeature) klog.V(2).InfoS("NodeFeature added", "nodefeature", klog.KObj(nfr)) - c.updateOneNode("NodeFeature", nfr) + if c.isNamespaceSelected(nfr.Namespace) { + c.updateOneNode("NodeFeature", nfr) + } else { + klog.V(2).InfoS("NodeFeature namespace is not selected, skipping", "nodefeature", klog.KObj(nfr)) + } if !nfdApiControllerOptions.DisableNodeFeatureGroup { c.updateAllNodeFeatureGroups() } @@ -187,6 +204,7 @@ func newNfdController(config *restclient.Config, nfdApiControllerOptions nfdApiC func (c *nfdController) stop() { close(c.stopChan) + c.namespaceLister.stop() } func getNodeNameForObj(obj metav1.Object) (string, error) { @@ -212,6 +230,28 @@ func (c *nfdController) updateOneNode(typ string, obj metav1.Object) { } } +func (c *nfdController) isNamespaceSelected(namespace string) bool { + // this means that the user didn't specify any namespace selector + // which means that we allow all namespaces + if c.namespaceLister == nil { + return true + } + + namespaces, err := c.namespaceLister.list() + if err != nil { + klog.ErrorS(err, "failed to query namespaces by the namespace lister") + return false + } + + for _, ns := range namespaces { + if ns.Name == namespace { + return true + } + } + + return false +} + func (c *nfdController) updateAllNodes() { select { case c.updateAllNodesChan <- struct{}{}: diff --git a/pkg/nfd-master/nfd-api-controller_test.go b/pkg/nfd-master/nfd-api-controller_test.go index 44153f41a0..a49c4939b3 100644 --- a/pkg/nfd-master/nfd-api-controller_test.go +++ b/pkg/nfd-master/nfd-api-controller_test.go @@ -20,8 +20,12 @@ import ( "testing" "github.com/stretchr/testify/assert" - + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/watch" + fakeclient "k8s.io/client-go/kubernetes/fake" + clienttesting "k8s.io/client-go/testing" + nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1" ) @@ -42,3 +46,66 @@ func TestGetNodeNameForObj(t *testing.T) { assert.Nil(t, err) assert.Equal(t, n, "node-1") } + +func newTestNamespace(name string) *corev1.Namespace { + return &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Labels: map[string]string{ + "name": name, + }, + }, + } +} + +func TestIsNamespaceSelected(t *testing.T) { + fakeCli := fakeclient.NewSimpleClientset(newTestNamespace("fake")) + fakeCli.PrependWatchReactor("*", func(action clienttesting.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := fakeCli.Tracker().Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + c := &nfdController{} + + testcases := []struct { + name string + objectNamespace string + nodeFeatureNamespaceSelector *metav1.LabelSelector + expectedResult bool + }{ + { + name: "namespace not selected", + objectNamespace: "random", + nodeFeatureNamespaceSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "name", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"fake"}, + }, + }, + }, + expectedResult: false, + }, + { + name: "namespace is selected", + objectNamespace: "fake", + nodeFeatureNamespaceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"name": "fake"}, + }, + expectedResult: true, + }, + } + + for _, tc := range testcases { + labelMap, _ := metav1.LabelSelectorAsSelector(tc.nodeFeatureNamespaceSelector) + c.namespaceLister = newNamespaceLister(fakeCli, labelMap) + res := c.isNamespaceSelected(tc.objectNamespace) + assert.Equal(t, res, tc.expectedResult) + } +} diff --git a/pkg/nfd-master/nfd-master-internal_test.go b/pkg/nfd-master/nfd-master-internal_test.go index c411728759..6f7f7b0db0 100644 --- a/pkg/nfd-master/nfd-master-internal_test.go +++ b/pkg/nfd-master/nfd-master-internal_test.go @@ -34,6 +34,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apimachinery/pkg/util/sets" fakeclient "k8s.io/client-go/kubernetes/fake" fakecorev1client "k8s.io/client-go/kubernetes/typed/core/v1/fake" clienttesting "k8s.io/client-go/testing" @@ -111,7 +112,7 @@ func withConfig(config *NFDConfig) NfdMasterOption { func newFakeMaster(opts ...NfdMasterOption) *nfdMaster { defaultOpts := []NfdMasterOption{ withNodeName(testNodeName), - withConfig(&NFDConfig{}), + withConfig(&NFDConfig{Restrictions: Restrictions{AllowOverwrite: true}}), WithKubernetesClient(fakeclient.NewSimpleClientset()), } m, err := NewNfdMaster(append(defaultOpts, opts...)...) @@ -508,15 +509,16 @@ func TestFilterLabels(t *testing.T) { func TestCreatePatches(t *testing.T) { Convey("When creating JSON patches", t, func() { existingItems := map[string]string{"key-1": "val-1", "key-2": "val-2", "key-3": "val-3"} + overwriteKeys := true jsonPath := "/root" - Convey("When when there are neither itmes to remoe nor to add or update", func() { - p := createPatches([]string{"foo", "bar"}, existingItems, map[string]string{}, jsonPath) + Convey("When there are neither itmes to remoe nor to add or update", func() { + p := createPatches(sets.New([]string{"foo", "bar"}...), existingItems, map[string]string{}, jsonPath, overwriteKeys) So(len(p), ShouldEqual, 0) }) - Convey("When when there are itmes to remoe but none to add or update", func() { - p := createPatches([]string{"key-2", "key-3", "foo"}, existingItems, map[string]string{}, jsonPath) + Convey("When there are itmes to remoe but none to add or update", func() { + p := createPatches(sets.New([]string{"key-2", "key-3", "foo"}...), existingItems, map[string]string{}, jsonPath, overwriteKeys) expected := []utils.JsonPatch{ utils.NewJsonPatch("remove", jsonPath, "key-2", ""), utils.NewJsonPatch("remove", jsonPath, "key-3", ""), @@ -524,9 +526,9 @@ func TestCreatePatches(t *testing.T) { So(sortJsonPatches(p), ShouldResemble, sortJsonPatches(expected)) }) - Convey("When when there are no itmes to remove but new items to add", func() { + Convey("When there are no itmes to remove but new items to add", func() { newItems := map[string]string{"new-key": "new-val", "key-1": "new-1"} - p := createPatches([]string{"key-1"}, existingItems, newItems, jsonPath) + p := createPatches(sets.New([]string{"key-1"}...), existingItems, newItems, jsonPath, overwriteKeys) expected := []utils.JsonPatch{ utils.NewJsonPatch("add", jsonPath, "new-key", newItems["new-key"]), utils.NewJsonPatch("replace", jsonPath, "key-1", newItems["key-1"]), @@ -534,9 +536,9 @@ func TestCreatePatches(t *testing.T) { So(sortJsonPatches(p), ShouldResemble, sortJsonPatches(expected)) }) - Convey("When when there are items to remove add and update", func() { + Convey("When there are items to remove add and update", func() { newItems := map[string]string{"new-key": "new-val", "key-2": "new-2", "key-4": "val-4"} - p := createPatches([]string{"key-1", "key-2", "key-3", "foo"}, existingItems, newItems, jsonPath) + p := createPatches(sets.New([]string{"key-1", "key-2", "key-3", "foo"}...), existingItems, newItems, jsonPath, overwriteKeys) expected := []utils.JsonPatch{ utils.NewJsonPatch("add", jsonPath, "new-key", newItems["new-key"]), utils.NewJsonPatch("add", jsonPath, "key-4", newItems["key-4"]), @@ -546,6 +548,17 @@ func TestCreatePatches(t *testing.T) { } So(sortJsonPatches(p), ShouldResemble, sortJsonPatches(expected)) }) + + Convey("When overwrite of keys is denied and there is already an existant key", func() { + overwriteKeys = false + newItems := map[string]string{"key-1": "new-2", "key-4": "val-4"} + p := createPatches(sets.New([]string{}...), existingItems, newItems, jsonPath, overwriteKeys) + expected := []utils.JsonPatch{ + utils.NewJsonPatch("add", jsonPath, "key-4", newItems["key-4"]), + utils.NewJsonPatch("replace", jsonPath, "key-1", newItems["key-1"]), + } + So(sortJsonPatches(p), ShouldResemble, sortJsonPatches(expected)) + }) }) } diff --git a/pkg/nfd-master/nfd-master.go b/pkg/nfd-master/nfd-master.go index 5babc12081..451d6b532e 100644 --- a/pkg/nfd-master/nfd-master.go +++ b/pkg/nfd-master/nfd-master.go @@ -45,14 +45,13 @@ import ( "k8s.io/apimachinery/pkg/labels" k8sLabels "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/sets" k8sclient "k8s.io/client-go/kubernetes" restclient "k8s.io/client-go/rest" "k8s.io/client-go/tools/leaderelection" "k8s.io/client-go/tools/leaderelection/resourcelock" "k8s.io/klog/v2" controller "k8s.io/kubernetes/pkg/controller" - klogutils "sigs.k8s.io/node-feature-discovery/pkg/utils/klog" - taintutils "k8s.io/kubernetes/pkg/util/taints" "sigs.k8s.io/yaml" @@ -63,6 +62,7 @@ import ( nfdfeatures "sigs.k8s.io/node-feature-discovery/pkg/features" pb "sigs.k8s.io/node-feature-discovery/pkg/labeler" "sigs.k8s.io/node-feature-discovery/pkg/utils" + klogutils "sigs.k8s.io/node-feature-discovery/pkg/utils/klog" "sigs.k8s.io/node-feature-discovery/pkg/version" ) @@ -75,6 +75,16 @@ type ExtendedResources map[string]string // Annotations are used for NFD-related node metadata type Annotations map[string]string +// Restrictions contains the restrictions on the NF and NFR Crs +type Restrictions struct { + NodeFeatureNamespaceSelector *metav1.LabelSelector + DisableLabels bool + DisableExtendedResources bool + DisableAnnotations bool + DenyNodeFeatureLabels bool + AllowOverwrite bool +} + // NFDConfig contains the configuration settings of NfdMaster. type NFDConfig struct { AutoDefaultNs bool @@ -88,6 +98,7 @@ type NFDConfig struct { LeaderElection LeaderElectionConfig NfdApiParallelism int Klog klogutils.KlogConfigOpts + Restrictions Restrictions } // LeaderElectionConfig contains the configuration for leader election @@ -273,6 +284,13 @@ func newDefaultConfig() *NFDConfig { RenewDeadline: utils.DurationVal{Duration: time.Duration(10) * time.Second}, }, Klog: make(map[string]string), + Restrictions: Restrictions{ + DisableLabels: false, + DisableExtendedResources: false, + DisableAnnotations: false, + AllowOverwrite: true, + DenyNodeFeatureLabels: false, + }, } } @@ -581,10 +599,10 @@ func (m *nfdMaster) updateMasterNode() error { } // Advertise NFD version as an annotation - p := createPatches([]string{m.instanceAnnotation(nfdv1alpha1.MasterVersionAnnotation)}, + p := createPatches(sets.New([]string{m.instanceAnnotation(nfdv1alpha1.MasterVersionAnnotation)}...), node.Annotations, nil, - "/metadata/annotations") + "/metadata/annotations", m.config.Restrictions.AllowOverwrite) err = patchNode(m.k8sClient, node.Name, p) if err != nil { @@ -625,6 +643,11 @@ func (m *nfdMaster) filterFeatureLabels(labels Labels, features *nfdv1alpha1.Fea } } + if len(outLabels) > 0 && m.config.Restrictions.DisableLabels { + klog.V(2).InfoS("node labels are disabled in configuration (restrictions.disableLabels=true)") + outLabels = Labels{} + } + return outLabels, extendedResources } @@ -690,6 +713,7 @@ func filterTaints(taints []corev1.Taint) []corev1.Taint { outTaints = append(outTaints, taint) } } + return outTaints } @@ -781,42 +805,62 @@ func (m *nfdMaster) getAndMergeNodeFeatures(nodeName string) (*nfdv1alpha1.NodeF return &nfdv1alpha1.NodeFeature{}, fmt.Errorf("failed to get NodeFeature resources for node %q: %w", nodeName, err) } + filteredObjs := []*nfdv1alpha1.NodeFeature{} + for _, obj := range objs { + if m.isNamespaceSelected(obj.Namespace) { + filteredObjs = append(filteredObjs, obj) + } + } + // Node without a running NFD-Worker - if len(objs) == 0 { + if len(filteredObjs) == 0 { return &nfdv1alpha1.NodeFeature{}, nil } // Sort our objects - sort.Slice(objs, func(i, j int) bool { + sort.Slice(filteredObjs, func(i, j int) bool { // Objects in our nfd namespace gets into the beginning of the list - if objs[i].Namespace == m.namespace && objs[j].Namespace != m.namespace { + if filteredObjs[i].Namespace == m.namespace && filteredObjs[j].Namespace != m.namespace { return true } - if objs[i].Namespace != m.namespace && objs[j].Namespace == m.namespace { + if filteredObjs[i].Namespace != m.namespace && filteredObjs[j].Namespace == m.namespace { return false } // After the nfd namespace, sort objects by their name - if objs[i].Name != objs[j].Name { - return objs[i].Name < objs[j].Name + if filteredObjs[i].Name != filteredObjs[j].Name { + return filteredObjs[i].Name < filteredObjs[j].Name } // Objects with the same name are sorted by their namespace - return objs[i].Namespace < objs[j].Namespace + return filteredObjs[i].Namespace < filteredObjs[j].Namespace }) - if len(objs) > 0 { + if len(filteredObjs) > 0 { // Merge in features // // NOTE: changing the rule api to support handle multiple objects instead // of merging would probably perform better with lot less data to copy. - features := objs[0].Spec.DeepCopy() + features := filteredObjs[0].Spec.DeepCopy() + + if m.config.Restrictions.DenyNodeFeatureLabels && m.isThirdPartyNodeFeature(*filteredObjs[0], nodeName, m.namespace) { + klog.V(2).InfoS("node feature labels are disabled in configuration (restrictions.denyNodeFeatureLabels=true)") + features.Labels = nil + } + if !nfdfeatures.NFDFeatureGate.Enabled(nfdfeatures.DisableAutoPrefix) && m.config.AutoDefaultNs { features.Labels = addNsToMapKeys(features.Labels, nfdv1alpha1.FeatureLabelNs) } - for _, o := range objs[1:] { + + for _, o := range filteredObjs[1:] { s := o.Spec.DeepCopy() + if m.config.Restrictions.DenyNodeFeatureLabels && m.isThirdPartyNodeFeature(*o, nodeName, m.namespace) { + klog.V(2).InfoS("node feature labels are disabled in configuration (restrictions.denyNodeFeatureLabels=true)") + s.Labels = nil + } + if !nfdfeatures.NFDFeatureGate.Enabled(nfdfeatures.DisableAutoPrefix) && m.config.AutoDefaultNs { s.Labels = addNsToMapKeys(s.Labels, nfdv1alpha1.FeatureLabelNs) } + s.MergeInto(features) } @@ -829,6 +873,11 @@ func (m *nfdMaster) getAndMergeNodeFeatures(nodeName string) (*nfdv1alpha1.NodeF return nodeFeatures, nil } +// isThirdPartyNodeFeature determines whether a node feature is a third party one or created by nfd-worker +func (m *nfdMaster) isThirdPartyNodeFeature(nodeFeature nfdv1alpha1.NodeFeature, nodeName, namespace string) bool { + return nodeFeature.Namespace != namespace || nodeFeature.Name != nodeName +} + func (m *nfdMaster) nfdAPIUpdateOneNode(cli k8sclient.Interface, node *corev1.Node) error { if m.nfdController == nil || m.nfdController.featureLister == nil { return nil @@ -995,6 +1044,11 @@ func (m *nfdMaster) refreshNodeFeatures(cli k8sclient.Interface, node *corev1.No maps.Copy(extendedResources, crExtendedResources) extendedResources = m.filterExtendedResources(features, extendedResources) + if len(extendedResources) > 0 && m.config.Restrictions.DisableExtendedResources { + klog.V(2).InfoS("extended resources are disabled in configuration (restrictions.disableExtendedResources=true)") + extendedResources = map[string]string{} + } + // Annotations annotations := m.filterFeatureAnnotations(crAnnotations) @@ -1021,8 +1075,8 @@ func (m *nfdMaster) refreshNodeFeatures(cli k8sclient.Interface, node *corev1.No // setTaints sets node taints and annotations based on the taints passed via // nodeFeatureRule custom resorce. If empty list of taints is passed, currently // NFD owned taints and annotations are removed from the node. -func setTaints(cli k8sclient.Interface, taints []corev1.Taint, node *corev1.Node) error { - // De-serialize the taints annotation into corev1.Taint type for comparison below. +func (m *nfdMaster) setTaints(cli k8sclient.Interface, taints []corev1.Taint, node *corev1.Node) error { + // De-serialize the taints annotation into corev1.Taint type for comparision below. var err error oldTaints := []corev1.Taint{} if val, ok := node.Annotations[nfdv1alpha1.NodeTaintsAnnotation]; ok { @@ -1078,7 +1132,11 @@ func setTaints(cli k8sclient.Interface, taints []corev1.Taint, node *corev1.Node newAnnotations[nfdv1alpha1.NodeTaintsAnnotation] = strings.Join(taintStrs, ",") } - patches := createPatches([]string{nfdv1alpha1.NodeTaintsAnnotation}, node.Annotations, newAnnotations, "/metadata/annotations") + patches := createPatches(sets.New([]string{nfdv1alpha1.NodeTaintsAnnotation}...), + node.Annotations, newAnnotations, + "/metadata/annotations", + m.config.Restrictions.AllowOverwrite, + ) if len(patches) > 0 { if err := patchNode(cli, node.Name, patches); err != nil { return fmt.Errorf("error while patching node object: %w", err) @@ -1218,7 +1276,7 @@ func (m *nfdMaster) updateNodeObject(cli k8sclient.Interface, node *corev1.Node, // Create JSON patches for changes in labels and annotations oldLabels := stringToNsNames(node.Annotations[m.instanceAnnotation(nfdv1alpha1.FeatureLabelsAnnotation)], nfdv1alpha1.FeatureLabelNs) oldAnnotations := stringToNsNames(node.Annotations[m.instanceAnnotation(nfdv1alpha1.FeatureAnnotationsTrackingAnnotation)], nfdv1alpha1.FeatureAnnotationNs) - patches := createPatches(oldLabels, node.Labels, labels, "/metadata/labels") + patches := createPatches(sets.New(oldLabels...), node.Labels, labels, "/metadata/labels", m.config.Restrictions.AllowOverwrite) oldAnnotations = append(oldAnnotations, []string{ m.instanceAnnotation(nfdv1alpha1.FeatureLabelsAnnotation), m.instanceAnnotation(nfdv1alpha1.ExtendedResourceAnnotation), @@ -1226,7 +1284,7 @@ func (m *nfdMaster) updateNodeObject(cli k8sclient.Interface, node *corev1.Node, // Clean up deprecated/stale nfd version annotations m.instanceAnnotation(nfdv1alpha1.MasterVersionAnnotation), m.instanceAnnotation(nfdv1alpha1.WorkerVersionAnnotation)}...) - patches = append(patches, createPatches(oldAnnotations, node.Annotations, annotations, "/metadata/annotations")...) + patches = append(patches, createPatches(sets.New(oldAnnotations...), node.Annotations, annotations, "/metadata/annotations", m.config.Restrictions.AllowOverwrite)...) // patch node status with extended resource changes statusPatches := m.createExtendedResourcePatches(node, extendedResources) @@ -1249,7 +1307,7 @@ func (m *nfdMaster) updateNodeObject(cli k8sclient.Interface, node *corev1.Node, } // Set taints - err = setTaints(cli, taints, node) + err = m.setTaints(cli, taints, node) if err != nil { return err } @@ -1258,11 +1316,11 @@ func (m *nfdMaster) updateNodeObject(cli k8sclient.Interface, node *corev1.Node, } // createPatches is a generic helper that returns json patch operations to perform -func createPatches(removeKeys []string, oldItems map[string]string, newItems map[string]string, jsonPath string) []utils.JsonPatch { +func createPatches(removeKeys sets.Set[string], oldItems map[string]string, newItems map[string]string, jsonPath string, overwrite bool) []utils.JsonPatch { patches := []utils.JsonPatch{} // Determine items to remove - for _, key := range removeKeys { + for key := range removeKeys { if _, ok := oldItems[key]; ok { if _, ok := newItems[key]; !ok { patches = append(patches, utils.NewJsonPatch("remove", jsonPath, key, "")) @@ -1273,7 +1331,7 @@ func createPatches(removeKeys []string, oldItems map[string]string, newItems map // Determine items to add or replace for key, newVal := range newItems { if oldVal, ok := oldItems[key]; ok { - if newVal != oldVal { + if newVal != oldVal && (!removeKeys.Has(key) || overwrite) { patches = append(patches, utils.NewJsonPatch("replace", jsonPath, key, newVal)) } } else { @@ -1475,8 +1533,10 @@ func (m *nfdMaster) startNfdApiController() error { } klog.InfoS("starting the nfd api controller") m.nfdController, err = newNfdController(kubeconfig, nfdApiControllerOptions{ - DisableNodeFeature: !nfdfeatures.NFDFeatureGate.Enabled(nfdfeatures.NodeFeatureAPI), - ResyncPeriod: m.config.ResyncPeriod.Duration, + DisableNodeFeature: !nfdfeatures.NFDFeatureGate.Enabled(nfdfeatures.NodeFeatureAPI), + ResyncPeriod: m.config.ResyncPeriod.Duration, + K8sClient: m.k8sClient, + NodeFeatureNamespaceSelector: m.config.Restrictions.NodeFeatureNamespaceSelector, }) if err != nil { return fmt.Errorf("failed to initialize CRD controller: %w", err) @@ -1537,6 +1597,12 @@ func (m *nfdMaster) filterFeatureAnnotations(annotations map[string]string) map[ outAnnotations[annotation] = value } + + if len(outAnnotations) > 0 && m.config.Restrictions.DisableAnnotations { + klog.V(2).InfoS("node annotations are disabled in configuration (restrictions.disableAnnotations=true)") + outAnnotations = map[string]string{} + } + return outAnnotations } diff --git a/source/pci/pci_test.go b/source/pci/pci_test.go index 778b961e63..5390a8a5d6 100644 --- a/source/pci/pci_test.go +++ b/source/pci/pci_test.go @@ -18,7 +18,6 @@ package pci import ( "path/filepath" - "runtime" "testing" "github.com/stretchr/testify/assert" @@ -27,13 +26,6 @@ import ( "sigs.k8s.io/node-feature-discovery/source" ) -var packagePath string - -func init() { - _, thisFile, _, _ := runtime.Caller(0) - packagePath = filepath.Dir(thisFile) -} - func TestSingletonPciSource(t *testing.T) { assert.Equal(t, src.Name(), Name) @@ -232,7 +224,8 @@ func TestPciSource(t *testing.T) { // Run test cases for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { - hostpath.SysfsDir = hostpath.HostDir(filepath.Join(packagePath, "testdata", tc.rootfs, "sys")) + mockSysfsPath := filepath.Join("..", "..", "testdata", "source", "pci", tc.rootfs, "sys") + hostpath.SysfsDir = hostpath.HostDir(mockSysfsPath) config := tc.config if config == nil { diff --git a/test/e2e/data/nodefeaturerule-6.yaml b/test/e2e/data/nodefeaturerule-6.yaml new file mode 100644 index 0000000000..d9dcb38367 --- /dev/null +++ b/test/e2e/data/nodefeaturerule-6.yaml @@ -0,0 +1,18 @@ +apiVersion: nfd.k8s-sigs.io/v1alpha1 +kind: NodeFeatureRule +metadata: + name: e2e-test-6 +spec: + rules: + - name: "e2e-restrictions-test-1" + taints: + - effect: PreferNoSchedule + key: "feature.node.kubernetes.io/fake-special-cpu" + value: "true" + labels: + e2e.feature.node.kubernetes.io/restricted-label-1: "true" + annotations: + e2e.feature.node.kubernetes.io/restricted-annoation-1: "yes" + extendedResources: + e2e.feature.node.kubernetes.io/restricted-er-1: "2" + matchFeatures: diff --git a/test/e2e/node_feature_discovery_test.go b/test/e2e/node_feature_discovery_test.go index 7edebee6d3..aea16051fe 100644 --- a/test/e2e/node_feature_discovery_test.go +++ b/test/e2e/node_feature_discovery_test.go @@ -28,7 +28,6 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - corev1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" extclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" @@ -994,6 +993,282 @@ resyncPeriod: "1s" Expect(err).NotTo(HaveOccurred()) }) }) + + Context("selected namespaces restriction is respected or not", Label("restrictions"), func() { + BeforeEach(func(ctx context.Context) { + extraMasterPodSpecOpts = []testpod.SpecOption{ + testpod.SpecWithConfigMap("nfd-master-conf", "/etc/kubernetes/node-feature-discovery"), + } + cm := testutils.NewConfigMap("nfd-master-conf", "nfd-master.conf", ` +restrictions: + nodeFeatureNamespaceSelector: + matchLabels: + e2etest: fake + +resyncPeriod: "1s" +`) + _, err := f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, cm, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + }) + It("Nothing should be created", func(ctx context.Context) { + // deploy node feature object + nodes, err := getNonControlPlaneNodes(ctx, f.ClientSet) + Expect(err).NotTo(HaveOccurred()) + + targetNodeName := nodes[0].Name + Expect(targetNodeName).ToNot(BeEmpty(), "No suitable worker node found") + + // label the namespace in which node feature object is created + // TODO(TessaIO): add a utility for this. + patches, err := json.Marshal( + []utils.JsonPatch{ + utils.NewJsonPatch( + "add", + "/metadata/labels", + "e2etest", + "fake", + ), + }, + ) + Expect(err).NotTo(HaveOccurred()) + + _, err = f.ClientSet.CoreV1().Namespaces().Patch(ctx, f.Namespace.Name, types.JSONPatchType, patches, metav1.PatchOptions{}) + Expect(err).NotTo(HaveOccurred()) + + // Apply Node Feature object + By("Creating NodeFeature object") + nodeFeatures, err := testutils.CreateOrUpdateNodeFeaturesFromFile(ctx, nfdClient, "nodefeature-1.yaml", f.Namespace.Name, targetNodeName) + Expect(err).NotTo(HaveOccurred()) + + By("Verifying node labels from NodeFeature object #1 are created") + // No labels should be created since the f.Namespace is not in the selected Namespaces + expectedLabels := map[string]k8sLabels{ + targetNodeName: { + nfdv1alpha1.FeatureLabelNs + "/e2e-nodefeature-test-1": "obj-1", + nfdv1alpha1.FeatureLabelNs + "/e2e-nodefeature-test-2": "obj-1", + nfdv1alpha1.FeatureLabelNs + "/fake-fakefeature3": "overridden", + }, + } + eventuallyNonControlPlaneNodes(ctx, f.ClientSet).Should(MatchLabels(expectedLabels, nodes)) + + // remove label the namespace in which node feature object is created + patches, err = json.Marshal( + []utils.JsonPatch{ + utils.NewJsonPatch( + "remove", + "/metadata/labels", + "e2etest", + "fake", + ), + }, + ) + Expect(err).NotTo(HaveOccurred()) + + _, err = f.ClientSet.CoreV1().Namespaces().Patch(ctx, f.Namespace.Name, types.JSONPatchType, patches, metav1.PatchOptions{}) + Expect(err).NotTo(HaveOccurred()) + By("Verifying node labels from NodeFeature object #1 are not created") + // No labels should be created since the f.Namespace is not in the selected Namespaces + expectedLabels = map[string]k8sLabels{ + targetNodeName: {}, + } + eventuallyNonControlPlaneNodes(ctx, f.ClientSet).Should(MatchLabels(expectedLabels, nodes)) + + By("Deleting NodeFeature object") + err = nfdClient.NfdV1alpha1().NodeFeatures(f.Namespace.Name).Delete(ctx, nodeFeatures[0], metav1.DeleteOptions{}) + Expect(err).NotTo(HaveOccurred()) + }) + }) + + Context("disable labels restrictions should be respected", Label("restrictions"), func() { + BeforeEach(func(ctx context.Context) { + extraMasterPodSpecOpts = []testpod.SpecOption{ + testpod.SpecWithConfigMap("nfd-master-conf", "/etc/kubernetes/node-feature-discovery"), + testpod.SpecWithContainerExtraArgs("-enable-taints"), + } + cm := testutils.NewConfigMap("nfd-master-conf", "nfd-master.conf", ` +restrictions: + disableLabels: true +`) + _, err := f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, cm, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + }) + It("No labels should be created", func(ctx context.Context) { + // deploy node feature object + nodes, err := getNonControlPlaneNodes(ctx, f.ClientSet) + Expect(err).NotTo(HaveOccurred()) + + // Add features from NodeFeatureRule #6 + By("Creating NodeFeatureRules #6") + Expect(testutils.CreateNodeFeatureRulesFromFile(ctx, nfdClient, "nodefeaturerule-6.yaml")).NotTo(HaveOccurred()) + + By("Verifying node taints, annotations, ERs and labels from NodeFeatureRules #6") + expectedTaints := map[string][]corev1.Taint{ + "*": { + { + Key: "feature.node.kubernetes.io/fake-special-cpu", + Value: "true", + Effect: "PreferNoSchedule", + }, + }, + } + eventuallyNonControlPlaneNodes(ctx, f.ClientSet).Should(MatchTaints(expectedTaints, nodes)) + + expectedAnnotations := map[string]k8sAnnotations{ + "*": { + "e2e.feature.node.kubernetes.io/restricted-annoation-1": "yes", + "nfd.node.kubernetes.io/feature-annotations": "e2e.feature.node.kubernetes.io/restricted-annoation-1", + "nfd.node.kubernetes.io/extended-resources": "e2e.feature.node.kubernetes.io/restricted-er-1", + "nfd.node.kubernetes.io/taints": "feature.node.kubernetes.io/fake-special-cpu=true:PreferNoSchedule", + }, + } + eventuallyNonControlPlaneNodes(ctx, f.ClientSet).Should(MatchAnnotations(expectedAnnotations, nodes)) + + expectedCapacity := map[string]corev1.ResourceList{ + "*": { + "e2e.feature.node.kubernetes.io/restricted-er-1": resourcev1.MustParse("2"), + }, + } + eventuallyNonControlPlaneNodes(ctx, f.ClientSet).WithTimeout(1 * time.Minute).Should(MatchCapacity(expectedCapacity, nodes)) + + expectedLabels := map[string]k8sLabels{ + "*": {}, + } + eventuallyNonControlPlaneNodes(ctx, f.ClientSet).Should(MatchLabels(expectedLabels, nodes)) + + By("Deleting NodeFeatureRule #6") + err = nfdClient.NfdV1alpha1().NodeFeatureRules().Delete(ctx, "e2e-test-6", metav1.DeleteOptions{}) + Expect(err).NotTo(HaveOccurred()) + }) + }) + + Context("disable extended resources restriction should be respected", Label("restrictions"), func() { + BeforeEach(func(ctx context.Context) { + extraMasterPodSpecOpts = []testpod.SpecOption{ + testpod.SpecWithConfigMap("nfd-master-conf", "/etc/kubernetes/node-feature-discovery"), + } + cm := testutils.NewConfigMap("nfd-master-conf", "nfd-master.conf", ` +restrictions: + disableExtendedResources: true +`) + _, err := f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, cm, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + }) + It("Extended resources should not be created and Labels should be created", func(ctx context.Context) { + // deploy node feature object + nodes, err := getNonControlPlaneNodes(ctx, f.ClientSet) + Expect(err).NotTo(HaveOccurred()) + + targetNodeName := nodes[0].Name + Expect(targetNodeName).ToNot(BeEmpty(), "No suitable worker node found") + + expectedAnnotations := map[string]k8sAnnotations{ + "*": { + "e2e.feature.node.kubernetes.io/restricted-annoation-1": "yes", + "nfd.node.kubernetes.io/feature-annotations": "e2e.feature.node.kubernetes.io/restricted-annoation-1", + "nfd.node.kubernetes.io/feature-labels": "e2e.feature.node.kubernetes.io/restricted-label-1", + }, + } + expectedCapacity := map[string]corev1.ResourceList{ + "*": {}, + } + + expectedLabels := map[string]k8sLabels{ + "*": { + "e2e.feature.node.kubernetes.io/restricted-label-1": "true", + }, + } + + By("Creating NodeFeatureRules #6") + Expect(testutils.CreateNodeFeatureRulesFromFile(ctx, nfdClient, "nodefeaturerule-6.yaml")).NotTo(HaveOccurred()) + + By("Verifying node labels from NodeFeatureRules #6") + eventuallyNonControlPlaneNodes(ctx, f.ClientSet).Should(MatchLabels(expectedLabels, nodes)) + + By("Verifying node annotations from NodeFeatureRules #6") + eventuallyNonControlPlaneNodes(ctx, f.ClientSet).Should(MatchAnnotations(expectedAnnotations, nodes)) + + By("Verifying node status capacity from NodeFeatureRules #6") + eventuallyNonControlPlaneNodes(ctx, f.ClientSet).WithTimeout(1 * time.Minute).Should(MatchCapacity(expectedCapacity, nodes)) + + By("Deleting NodeFeatureRules #6") + err = nfdClient.NfdV1alpha1().NodeFeatureRules().Delete(ctx, "e2e-test-6", metav1.DeleteOptions{}) + Expect(err).NotTo(HaveOccurred()) + + By("Verify that labels from nfd-worker are garbage-collected") + expectedLabels = map[string]k8sLabels{ + "*": {}, + } + eventuallyNonControlPlaneNodes(ctx, f.ClientSet).WithTimeout(1 * time.Minute).Should(MatchLabels(expectedLabels, nodes)) + }) + }) + + Context("deny node feature labels restriction should be respected", Label("restrictions"), func() { + BeforeEach(func(ctx context.Context) { + extraMasterPodSpecOpts = []testpod.SpecOption{ + testpod.SpecWithConfigMap("nfd-master-conf", "/etc/kubernetes/node-feature-discovery"), + } + cm := testutils.NewConfigMap("nfd-master-conf", "nfd-master.conf", ` +restrictions: + denyNodeFeatureLabels: true +`) + _, err := f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, cm, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + }) + It("No feature labels should be created", func(ctx context.Context) { + // deploy node feature object + nodes, err := getNonControlPlaneNodes(ctx, f.ClientSet) + Expect(err).NotTo(HaveOccurred()) + + targetNodeName := nodes[0].Name + Expect(targetNodeName).ToNot(BeEmpty(), "No suitable worker node found") + + // Apply Node Feature object + By("Creating NodeFeature object") + nodeFeatures, err := testutils.CreateOrUpdateNodeFeaturesFromFile(ctx, nfdClient, "nodefeature-1.yaml", f.Namespace.Name, targetNodeName) + Expect(err).NotTo(HaveOccurred()) + + // Add features from NodeFeatureRule #6 + By("Creating NodeFeatureRules #6") + Expect(testutils.CreateNodeFeatureRulesFromFile(ctx, nfdClient, "nodefeaturerule-6.yaml")).NotTo(HaveOccurred()) + + By("Verifying node taints and labels from NodeFeatureRules #6") + expectedTaints := map[string][]corev1.Taint{ + "*": {}, + } + eventuallyNonControlPlaneNodes(ctx, f.ClientSet).Should(MatchTaints(expectedTaints, nodes)) + + expectedAnnotations := map[string]k8sAnnotations{ + "*": { + "e2e.feature.node.kubernetes.io/restricted-annoation-1": "yes", + "nfd.node.kubernetes.io/feature-annotations": "e2e.feature.node.kubernetes.io/restricted-annoation-1", + "nfd.node.kubernetes.io/extended-resources": "e2e.feature.node.kubernetes.io/restricted-er-1", + "nfd.node.kubernetes.io/feature-labels": "e2e.feature.node.kubernetes.io/restricted-label-1", + }, + } + eventuallyNonControlPlaneNodes(ctx, f.ClientSet).Should(MatchAnnotations(expectedAnnotations, nodes)) + + expectedCapacity := map[string]corev1.ResourceList{ + "*": { + "e2e.feature.node.kubernetes.io/restricted-er-1": resourcev1.MustParse("2"), + }, + } + eventuallyNonControlPlaneNodes(ctx, f.ClientSet).WithTimeout(1 * time.Minute).Should(MatchCapacity(expectedCapacity, nodes)) + + // TODO(TessaIO): we need one more test where we deploy nfd-worker that would create + // a non 3rd-party NF that shouldn't be ignored by this restriction + By("Verifying node labels from NodeFeature object #6 are not created") + expectedLabels := map[string]k8sLabels{ + "*": { + "e2e.feature.node.kubernetes.io/restricted-label-1": "true", + }, + } + eventuallyNonControlPlaneNodes(ctx, f.ClientSet).Should(MatchLabels(expectedLabels, nodes)) + + By("Deleting NodeFeature object") + err = nfdClient.NfdV1alpha1().NodeFeatures(f.Namespace.Name).Delete(ctx, nodeFeatures[0], metav1.DeleteOptions{}) + Expect(err).NotTo(HaveOccurred()) + }) + }) }) }) diff --git a/test/e2e/utils/rbac.go b/test/e2e/utils/rbac.go index 67470e331d..5e57fe4ecb 100644 --- a/test/e2e/utils/rbac.go +++ b/test/e2e/utils/rbac.go @@ -176,6 +176,11 @@ func createClusterRoleMaster(ctx context.Context, cs clientset.Interface) (*rbac Name: "nfd-master-e2e", }, Rules: []rbacv1.PolicyRule{ + { + APIGroups: []string{""}, + Resources: []string{"namespaces"}, + Verbs: []string{"list", "watch"}, + }, { APIGroups: []string{""}, Resources: []string{"nodes", "nodes/status"}, diff --git a/testdata/README.md b/testdata/README.md new file mode 100644 index 0000000000..ff08cb1de6 --- /dev/null +++ b/testdata/README.md @@ -0,0 +1,3 @@ +Some of the test data in this folder contains colon characters which causes "go get" commands to fail with "invalid char ':'". +The empty go.mod file is a workaround to prevent this error. This effectively makes this folder its own go module, so it will be +ignored when "go get" is executed. diff --git a/testdata/go.mod b/testdata/go.mod new file mode 100644 index 0000000000..effa259575 --- /dev/null +++ b/testdata/go.mod @@ -0,0 +1,3 @@ +// This empty go.mod file ensures that the testdata folder is not included +// in the top-level module. This prevents issues such as unsupported characters +// in path names. diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/ari_enabled b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/ari_enabled similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/ari_enabled rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/ari_enabled diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/broken_parity_status b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/broken_parity_status similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/broken_parity_status rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/broken_parity_status diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/class b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/class similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/class rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/class diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/config b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/config similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/config rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/config diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/consistent_dma_mask_bits b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/consistent_dma_mask_bits similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/consistent_dma_mask_bits rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/consistent_dma_mask_bits diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/current_link_speed b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/current_link_speed similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/current_link_speed rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/current_link_speed diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/current_link_width b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/current_link_width similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/current_link_width rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/current_link_width diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/d3cold_allowed b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/d3cold_allowed similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/d3cold_allowed rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/d3cold_allowed diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/device b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/device similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/device rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/device diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/dma_mask_bits b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/dma_mask_bits similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/dma_mask_bits rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/dma_mask_bits diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/driver_override b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/driver_override similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/driver_override rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/driver_override diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/enable b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/enable similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/enable rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/enable diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/irq b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/irq similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/irq rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/irq diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/local_cpulist b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/local_cpulist similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/local_cpulist rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/local_cpulist diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/local_cpus b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/local_cpus similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/local_cpus rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/local_cpus diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/max_link_speed b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/max_link_speed similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/max_link_speed rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/max_link_speed diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/max_link_width b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/max_link_width similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/max_link_width rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/max_link_width diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/modalias b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/modalias similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/modalias rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/modalias diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/msi_bus b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/msi_bus similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/msi_bus rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/msi_bus diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/numa_node b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/numa_node similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/numa_node rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/numa_node diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/pools b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/pools similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/pools rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/pools diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/power_state b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/power_state similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/power_state rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/power_state diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/revision b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/revision similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/revision rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/revision diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/subsystem_device b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/subsystem_device similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/subsystem_device rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/subsystem_device diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/subsystem_vendor b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/subsystem_vendor similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/subsystem_vendor rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/subsystem_vendor diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/vendor b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/vendor similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:04.0/vendor rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:04.0/vendor diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/ari_enabled b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/ari_enabled similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/ari_enabled rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/ari_enabled diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/broken_parity_status b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/broken_parity_status similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/broken_parity_status rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/broken_parity_status diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/class b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/class similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/class rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/class diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/config b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/config similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/config rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/config diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/consistent_dma_mask_bits b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/consistent_dma_mask_bits similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/consistent_dma_mask_bits rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/consistent_dma_mask_bits diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/d3cold_allowed b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/d3cold_allowed similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/d3cold_allowed rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/d3cold_allowed diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/device b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/device similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/device rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/device diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/dma_mask_bits b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/dma_mask_bits similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/dma_mask_bits rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/dma_mask_bits diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/driver_override b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/driver_override similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/driver_override rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/driver_override diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/enable b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/enable similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/enable rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/enable diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/irq b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/irq similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/irq rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/irq diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/local_cpulist b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/local_cpulist similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/local_cpulist rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/local_cpulist diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/local_cpus b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/local_cpus similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/local_cpus rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/local_cpus diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/modalias b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/modalias similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/modalias rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/modalias diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/msi_bus b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/msi_bus similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/msi_bus rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/msi_bus diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/numa_node b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/numa_node similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/numa_node rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/numa_node diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/power_state b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/power_state similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/power_state rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/power_state diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/revision b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/revision similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/revision rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/revision diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/subsystem_device b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/subsystem_device similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/subsystem_device rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/subsystem_device diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/subsystem_vendor b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/subsystem_vendor similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/subsystem_vendor rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/subsystem_vendor diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/vendor b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/vendor similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/vendor rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/vendor diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/waiting_for_supplier b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/waiting_for_supplier similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.1/waiting_for_supplier rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.1/waiting_for_supplier diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/ari_enabled b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/ari_enabled similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/ari_enabled rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/ari_enabled diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/broken_parity_status b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/broken_parity_status similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/broken_parity_status rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/broken_parity_status diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/class b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/class similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/class rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/class diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/config b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/config similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/config rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/config diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/consistent_dma_mask_bits b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/consistent_dma_mask_bits similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/consistent_dma_mask_bits rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/consistent_dma_mask_bits diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/d3cold_allowed b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/d3cold_allowed similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/d3cold_allowed rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/d3cold_allowed diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/device b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/device similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/device rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/device diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/dma_mask_bits b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/dma_mask_bits similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/dma_mask_bits rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/dma_mask_bits diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/driver_override b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/driver_override similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/driver_override rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/driver_override diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/enable b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/enable similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/enable rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/enable diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/index b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/index similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/index rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/index diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/irq b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/irq similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/irq rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/irq diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/label b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/label similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/label rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/label diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/local_cpulist b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/local_cpulist similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/local_cpulist rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/local_cpulist diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/local_cpus b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/local_cpus similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/local_cpus rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/local_cpus diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/modalias b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/modalias similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/modalias rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/modalias diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/msi_bus b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/msi_bus similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/msi_bus rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/msi_bus diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/numa_node b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/numa_node similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/numa_node rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/numa_node diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/power_state b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/power_state similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/power_state rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/power_state diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/remapped_nvme b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/remapped_nvme similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/remapped_nvme rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/remapped_nvme diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/revision b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/revision similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/revision rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/revision diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/subsystem_device b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/subsystem_device similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/subsystem_device rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/subsystem_device diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/subsystem_vendor b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/subsystem_vendor similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/subsystem_vendor rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/subsystem_vendor diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/vendor b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/vendor similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:11.5/vendor rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:11.5/vendor diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/ari_enabled b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/ari_enabled similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/ari_enabled rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/ari_enabled diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/broken_parity_status b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/broken_parity_status similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/broken_parity_status rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/broken_parity_status diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/class b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/class similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/class rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/class diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/config b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/config similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/config rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/config diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/consistent_dma_mask_bits b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/consistent_dma_mask_bits similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/consistent_dma_mask_bits rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/consistent_dma_mask_bits diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/d3cold_allowed b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/d3cold_allowed similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/d3cold_allowed rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/d3cold_allowed diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/device b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/device similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/device rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/device diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/dma_mask_bits b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/dma_mask_bits similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/dma_mask_bits rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/dma_mask_bits diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/driver_override b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/driver_override similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/driver_override rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/driver_override diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/enable b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/enable similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/enable rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/enable diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/irq b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/irq similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/irq rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/irq diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/local_cpulist b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/local_cpulist similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/local_cpulist rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/local_cpulist diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/local_cpus b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/local_cpus similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/local_cpus rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/local_cpus diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/modalias b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/modalias similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/modalias rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/modalias diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/msi_bus b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/msi_bus similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/msi_bus rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/msi_bus diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/numa_node b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/numa_node similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/numa_node rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/numa_node diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/power_state b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/power_state similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/power_state rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/power_state diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/revision b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/revision similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/revision rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/revision diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/subsystem_device b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/subsystem_device similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/subsystem_device rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/subsystem_device diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/subsystem_vendor b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/subsystem_vendor similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/subsystem_vendor rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/subsystem_vendor diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/vendor b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/vendor similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:14.2/vendor rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:14.2/vendor diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/ari_enabled b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/ari_enabled similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/ari_enabled rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/ari_enabled diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/broken_parity_status b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/broken_parity_status similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/broken_parity_status rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/broken_parity_status diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/class b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/class similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/class rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/class diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/config b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/config similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/config rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/config diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/consistent_dma_mask_bits b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/consistent_dma_mask_bits similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/consistent_dma_mask_bits rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/consistent_dma_mask_bits diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/d3cold_allowed b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/d3cold_allowed similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/d3cold_allowed rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/d3cold_allowed diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/device b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/device similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/device rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/device diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/dma_mask_bits b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/dma_mask_bits similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/dma_mask_bits rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/dma_mask_bits diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/driver_override b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/driver_override similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/driver_override rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/driver_override diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/enable b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/enable similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/enable rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/enable diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/irq b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/irq similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/irq rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/irq diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/local_cpulist b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/local_cpulist similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/local_cpulist rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/local_cpulist diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/local_cpus b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/local_cpus similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/local_cpus rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/local_cpus diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/modalias b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/modalias similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/modalias rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/modalias diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/msi_bus b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/msi_bus similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/msi_bus rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/msi_bus diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/numa_node b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/numa_node similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/numa_node rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/numa_node diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/power_state b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/power_state similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/power_state rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/power_state diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/revision b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/revision similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/revision rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/revision diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/subsystem_device b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/subsystem_device similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/subsystem_device rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/subsystem_device diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/subsystem_vendor b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/subsystem_vendor similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/subsystem_vendor rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/subsystem_vendor diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/vendor b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/vendor similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/vendor rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/vendor diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/waiting_for_supplier b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/waiting_for_supplier similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:16.0/waiting_for_supplier rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:16.0/waiting_for_supplier diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/ari_enabled b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/ari_enabled similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/ari_enabled rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/ari_enabled diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/broken_parity_status b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/broken_parity_status similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/broken_parity_status rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/broken_parity_status diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/class b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/class similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/class rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/class diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/config b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/config similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/config rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/config diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/consistent_dma_mask_bits b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/consistent_dma_mask_bits similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/consistent_dma_mask_bits rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/consistent_dma_mask_bits diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/current_link_speed b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/current_link_speed similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/current_link_speed rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/current_link_speed diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/current_link_width b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/current_link_width similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/current_link_width rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/current_link_width diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/d3cold_allowed b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/d3cold_allowed similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/d3cold_allowed rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/d3cold_allowed diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/device b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/device similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/device rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/device diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/dma_mask_bits b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/dma_mask_bits similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/dma_mask_bits rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/dma_mask_bits diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/driver_override b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/driver_override similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/driver_override rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/driver_override diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/enable b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/enable similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/enable rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/enable diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/irq b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/irq similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/irq rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/irq diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/local_cpulist b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/local_cpulist similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/local_cpulist rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/local_cpulist diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/local_cpus b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/local_cpus similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/local_cpus rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/local_cpus diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/max_link_speed b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/max_link_speed similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/max_link_speed rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/max_link_speed diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/max_link_width b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/max_link_width similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/max_link_width rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/max_link_width diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/modalias b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/modalias similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/modalias rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/modalias diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/msi_bus b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/msi_bus similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/msi_bus rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/msi_bus diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/numa_node b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/numa_node similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/numa_node rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/numa_node diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/power_state b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/power_state similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/power_state rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/power_state diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/reset_method b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/reset_method similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/reset_method rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/reset_method diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/revision b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/revision similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/revision rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/revision diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/secondary_bus_number b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/secondary_bus_number similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/secondary_bus_number rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/secondary_bus_number diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/subordinate_bus_number b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/subordinate_bus_number similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/subordinate_bus_number rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/subordinate_bus_number diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/subsystem_device b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/subsystem_device similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/subsystem_device rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/subsystem_device diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/subsystem_vendor b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/subsystem_vendor similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/subsystem_vendor rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/subsystem_vendor diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/vendor b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/vendor similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/vendor rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1c.0/vendor diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.2/REAME b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.2/REAME similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.2/REAME rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.2/REAME diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.2/class b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.2/class similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.2/class rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.2/class diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/ari_enabled b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/ari_enabled similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/ari_enabled rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/ari_enabled diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/broken_parity_status b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/broken_parity_status similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/broken_parity_status rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/broken_parity_status diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/class b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/class similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/class rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/class diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/config b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/config similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/config rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/config diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/consistent_dma_mask_bits b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/consistent_dma_mask_bits similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/consistent_dma_mask_bits rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/consistent_dma_mask_bits diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/d3cold_allowed b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/d3cold_allowed similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/d3cold_allowed rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/d3cold_allowed diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/device b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/device similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/device rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/device diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/dma_mask_bits b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/dma_mask_bits similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/dma_mask_bits rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/dma_mask_bits diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/driver_override b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/driver_override similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/driver_override rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/driver_override diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/enable b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/enable similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/enable rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/enable diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/irq b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/irq similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/irq rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/irq diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/local_cpulist b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/local_cpulist similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/local_cpulist rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/local_cpulist diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/local_cpus b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/local_cpus similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/local_cpus rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/local_cpus diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/modalias b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/modalias similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/modalias rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/modalias diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/msi_bus b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/msi_bus similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/msi_bus rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/msi_bus diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/numa_node b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/numa_node similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/numa_node rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/numa_node diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/power_state b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/power_state similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/power_state rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/power_state diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/revision b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/revision similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/revision rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/revision diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/subsystem_device b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/subsystem_device similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/subsystem_device rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/subsystem_device diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/subsystem_vendor b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/subsystem_vendor similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/subsystem_vendor rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/subsystem_vendor diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/vendor b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/vendor similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/vendor rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/vendor diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/waiting_for_supplier b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/waiting_for_supplier similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/waiting_for_supplier rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:00:1f.5/waiting_for_supplier diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/ari_enabled b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/ari_enabled similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/ari_enabled rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/ari_enabled diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/boot_vga b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/boot_vga similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/boot_vga rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/boot_vga diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/broken_parity_status b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/broken_parity_status similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/broken_parity_status rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/broken_parity_status diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/class b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/class similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/class rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/class diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/config b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/config similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/config rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/config diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/consistent_dma_mask_bits b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/consistent_dma_mask_bits similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/consistent_dma_mask_bits rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/consistent_dma_mask_bits diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/d3cold_allowed b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/d3cold_allowed similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/d3cold_allowed rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/d3cold_allowed diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/device b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/device similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/device rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/device diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/dma_mask_bits b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/dma_mask_bits similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/dma_mask_bits rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/dma_mask_bits diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/driver_override b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/driver_override similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/driver_override rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/driver_override diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/enable b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/enable similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/enable rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/enable diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/index b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/index similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/index rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/index diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/irq b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/irq similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/irq rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/irq diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/label b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/label similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/label rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/label diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/local_cpulist b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/local_cpulist similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/local_cpulist rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/local_cpulist diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/local_cpus b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/local_cpus similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/local_cpus rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/local_cpus diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/modalias b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/modalias similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/modalias rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/modalias diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/msi_bus b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/msi_bus similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/msi_bus rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/msi_bus diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/numa_node b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/numa_node similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/numa_node rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/numa_node diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/power_state b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/power_state similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/power_state rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/power_state diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/reset_method b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/reset_method similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/reset_method rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/reset_method diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/revision b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/revision similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/revision rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/revision diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/subsystem_device b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/subsystem_device similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/subsystem_device rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/subsystem_device diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/subsystem_vendor b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/subsystem_vendor similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/subsystem_vendor rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/subsystem_vendor diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/vendor b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/vendor similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:02:00.0/vendor rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:02:00.0/vendor diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/ari_enabled b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/ari_enabled similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/ari_enabled rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/ari_enabled diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/broken_parity_status b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/broken_parity_status similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/broken_parity_status rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/broken_parity_status diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/class b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/class similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/class rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/class diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/config b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/config similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/config rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/config diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/consistent_dma_mask_bits b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/consistent_dma_mask_bits similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/consistent_dma_mask_bits rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/consistent_dma_mask_bits diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/current_link_speed b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/current_link_speed similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/current_link_speed rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/current_link_speed diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/current_link_width b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/current_link_width similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/current_link_width rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/current_link_width diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/d3cold_allowed b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/d3cold_allowed similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/d3cold_allowed rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/d3cold_allowed diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/device b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/device similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/device rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/device diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/dma_mask_bits b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/dma_mask_bits similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/dma_mask_bits rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/dma_mask_bits diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/driver_override b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/driver_override similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/driver_override rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/driver_override diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/enable b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/enable similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/enable rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/enable diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/iommu/intel-iommu/version b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/iommu/intel-iommu/version similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/iommu/intel-iommu/version rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/iommu/intel-iommu/version diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/iommu_group/type b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/iommu_group/type similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/iommu_group/type rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/iommu_group/type diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/irq b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/irq similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/irq rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/irq diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/local_cpulist b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/local_cpulist similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/local_cpulist rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/local_cpulist diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/local_cpus b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/local_cpus similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/local_cpus rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/local_cpus diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/max_link_speed b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/max_link_speed similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/max_link_speed rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/max_link_speed diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/max_link_width b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/max_link_width similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/max_link_width rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/max_link_width diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/modalias b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/modalias similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/modalias rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/modalias diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/msi_bus b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/msi_bus similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/msi_bus rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/msi_bus diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/numa_node b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/numa_node similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/numa_node rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/numa_node diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/power_state b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/power_state similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/power_state rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/power_state diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/reset_method b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/reset_method similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/reset_method rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/reset_method diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/revision b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/revision similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/revision rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/revision diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_drivers_autoprobe b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_drivers_autoprobe similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_drivers_autoprobe rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_drivers_autoprobe diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_numvfs b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_numvfs similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_numvfs rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_numvfs diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_offset b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_offset similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_offset rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_offset diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_stride b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_stride similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_stride rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_stride diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_totalvfs b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_totalvfs similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_totalvfs rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_totalvfs diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_vf_device b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_vf_device similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_vf_device rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_vf_device diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_vf_total_msix b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_vf_total_msix similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_vf_total_msix rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/sriov_vf_total_msix diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/subsystem_device b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/subsystem_device similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/subsystem_device rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/subsystem_device diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/subsystem_vendor b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/subsystem_vendor similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/subsystem_vendor rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/subsystem_vendor diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/vendor b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/vendor similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/vendor rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3b:00.0/vendor diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/ari_enabled b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/ari_enabled similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/ari_enabled rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/ari_enabled diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/broken_parity_status b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/broken_parity_status similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/broken_parity_status rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/broken_parity_status diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/class b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/class similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/class rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/class diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/config b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/config similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/config rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/config diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/consistent_dma_mask_bits b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/consistent_dma_mask_bits similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/consistent_dma_mask_bits rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/consistent_dma_mask_bits diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/current_link_speed b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/current_link_speed similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/current_link_speed rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/current_link_speed diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/current_link_width b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/current_link_width similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/current_link_width rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/current_link_width diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/d3cold_allowed b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/d3cold_allowed similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/d3cold_allowed rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/d3cold_allowed diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/device b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/device similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/device rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/device diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/dma_mask_bits b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/dma_mask_bits similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/dma_mask_bits rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/dma_mask_bits diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/driver_override b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/driver_override similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/driver_override rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/driver_override diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/enable b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/enable similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/enable rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/enable diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/index b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/index similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/index rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/index diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/irq b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/irq similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/irq rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/irq diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/label b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/label similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/label rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/label diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/local_cpulist b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/local_cpulist similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/local_cpulist rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/local_cpulist diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/local_cpus b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/local_cpus similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/local_cpus rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/local_cpus diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/max_link_speed b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/max_link_speed similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/max_link_speed rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/max_link_speed diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/max_link_width b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/max_link_width similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/max_link_width rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/max_link_width diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/modalias b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/modalias similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/modalias rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/modalias diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/msi_bus b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/msi_bus similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/msi_bus rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/msi_bus diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/numa_node b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/numa_node similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/numa_node rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/numa_node diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/power_state b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/power_state similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/power_state rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/power_state diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/reset_method b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/reset_method similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/reset_method rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/reset_method diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/revision b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/revision similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/revision rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/revision diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_drivers_autoprobe b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_drivers_autoprobe similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_drivers_autoprobe rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_drivers_autoprobe diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_numvfs b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_numvfs similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_numvfs rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_numvfs diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_offset b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_offset similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_offset rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_offset diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_stride b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_stride similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_stride rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_stride diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_totalvfs b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_totalvfs similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_totalvfs rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_totalvfs diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_vf_device b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_vf_device similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_vf_device rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_vf_device diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_vf_total_msix b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_vf_total_msix similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_vf_total_msix rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/sriov_vf_total_msix diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/subsystem_device b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/subsystem_device similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/subsystem_device rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/subsystem_device diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/subsystem_vendor b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/subsystem_vendor similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/subsystem_vendor rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/subsystem_vendor diff --git a/source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/vendor b/testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/vendor similarity index 100% rename from source/pci/testdata/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/vendor rename to testdata/source/pci/rootfs-1/sys/bus/pci/devices/0000:3f:00.0/vendor