diff --git a/.github/workflows/ci-image-scanning.yaml b/.github/workflows/ci-image-scanning.yaml index 741529b957d8..24e51df3214b 100644 --- a/.github/workflows/ci-image-scanning.yaml +++ b/.github/workflows/ci-image-scanning.yaml @@ -32,6 +32,10 @@ jobs: steps: - name: checkout code uses: actions/checkout@v4 + - name: install Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod - name: Build an image from Dockerfile run: | export VERSION="latest" diff --git a/.github/workflows/ci-schedule-compatibility.yaml b/.github/workflows/ci-schedule-compatibility.yaml index bc67d091c829..33e54a18ee2c 100644 --- a/.github/workflows/ci-schedule-compatibility.yaml +++ b/.github/workflows/ci-schedule-compatibility.yaml @@ -4,6 +4,9 @@ on: # Run this workflow "At 20:00 UTC on Sunday and Saturday" - cron: '0 20 * * 0,6' +permissions: + contents: read # Required by actions/checkout to fetch the repository contents. + jobs: e2e: name: e2e test diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6ca5462ad790..4f38aea07d48 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,6 +12,8 @@ on: concurrency: group: ${{ github.workflow }}-${{ github.actor }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true +permissions: + contents: read # for actions/checkout to fetch code jobs: golangci: name: lint diff --git a/.github/workflows/cli.yaml b/.github/workflows/cli.yaml index 0dc525494dbf..f1e5e6fabdd8 100644 --- a/.github/workflows/cli.yaml +++ b/.github/workflows/cli.yaml @@ -12,6 +12,8 @@ on: concurrency: group: ${{ github.workflow }}-${{ github.actor }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true +permissions: + contents: read # Required to check out the code jobs: init: name: init @@ -34,9 +36,7 @@ jobs: uses: actions/setup-go@v5 with: go-version-file: go.mod - - uses: helm/kind-action@v1.10.0 - with: - version: "v0.22.0" + - name: run karmadactl init test run: | export CLUSTER_VERSION=kindest/node:${{ matrix.k8s }} @@ -48,11 +48,18 @@ jobs: export KUBECONFIG=${HOME}/karmada/karmada-apiserver.config GO111MODULE=on go install github.com/onsi/ginkgo/v2/ginkgo ginkgo -v --race --trace -p --focus="[BasicPropagation] propagation testing deployment propagation testing" ./test/e2e/ - - uses: chainguard-dev/actions/kind-diag@main - # Only upload logs on failure. - if: ${{ failure() }} + - name: export logs + if: always() + run: | + export ARTIFACTS_PATH=${{ github.workspace }}/karmadactl-test-logs/${{ matrix.k8s }}/ + mkdir -p $ARTIFACTS_PATH + + mkdir -p $ARTIFACTS_PATH/karmada-host + kind export logs --name=karmada-host $ARTIFACTS_PATH/karmada-host + - name: upload logs + if: always() + uses: actions/upload-artifact@v4 with: - cluster-resources: nodes,namespaces, - namespace-resources: configmaps,pods,svc - artifact-name: logs-${{ matrix.k8s}} + name: karmadactl_test_logs_${{ matrix.k8s }} + path: ${{ github.workspace }}/karmadactl-test-logs/${{ matrix.k8s }}/ diff --git a/.github/workflows/dockerhub-latest-chart.yml b/.github/workflows/dockerhub-latest-chart.yml index 6b6a7ca7ae07..7bbd8bfcac89 100644 --- a/.github/workflows/dockerhub-latest-chart.yml +++ b/.github/workflows/dockerhub-latest-chart.yml @@ -22,6 +22,10 @@ jobs: # 0 indicates all history for all branches and tags. # for `git describe --tags` in Makefile. fetch-depth: 0 + - name: install Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod - name: login to DockerHub uses: docker/login-action@v3 with: diff --git a/.github/workflows/dockerhub-latest-image.yml b/.github/workflows/dockerhub-latest-image.yml index 76c6dcbd012c..1190b7276514 100644 --- a/.github/workflows/dockerhub-latest-image.yml +++ b/.github/workflows/dockerhub-latest-image.yml @@ -42,7 +42,7 @@ jobs: with: go-version-file: go.mod - name: Install Cosign - uses: sigstore/cosign-installer@v3.5.0 + uses: sigstore/cosign-installer@v3.6.0 with: cosign-release: 'v2.2.3' - name: install QEMU diff --git a/.github/workflows/dockerhub-released-chart.yml b/.github/workflows/dockerhub-released-chart.yml index 0b1d1096f29f..bd8fe2c19d7a 100644 --- a/.github/workflows/dockerhub-released-chart.yml +++ b/.github/workflows/dockerhub-released-chart.yml @@ -17,6 +17,10 @@ jobs: # 0 indicates all history for all branches and tags. # for `git describe --tags` in Makefile. fetch-depth: 0 + - name: install Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod - name: login to DockerHub uses: docker/login-action@v3 with: diff --git a/.github/workflows/dockerhub-released-image.yml b/.github/workflows/dockerhub-released-image.yml index 2384499ecfd3..2b9076b4f917 100644 --- a/.github/workflows/dockerhub-released-image.yml +++ b/.github/workflows/dockerhub-released-image.yml @@ -38,7 +38,7 @@ jobs: with: go-version-file: go.mod - name: Install Cosign - uses: sigstore/cosign-installer@v3.5.0 + uses: sigstore/cosign-installer@v3.6.0 with: cosign-release: 'v2.2.3' - name: install QEMU diff --git a/.github/workflows/lint-chart.yaml b/.github/workflows/lint-chart.yaml index 5e9276a8ba28..11d23b41a60b 100644 --- a/.github/workflows/lint-chart.yaml +++ b/.github/workflows/lint-chart.yaml @@ -3,6 +3,7 @@ name: Chart Lint env: HELM_VERSION: v3.11.2 + KUSTOMIZE_VERSION: 5.4.3 KIND_VERSION: v0.22.0 KIND_NODE_IMAGE: kindest/node:v1.29.0 K8S_VERSION: v1.29.0 @@ -29,18 +30,47 @@ jobs: with: fetch-depth: 0 + - name: install Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + - name: Set up Helm uses: azure/setup-helm@v4 with: version: ${{ env.HELM_VERSION }} + - name: Set up Kustomize + uses: syntaqx/setup-kustomize@v1 + with: + kustomize-version: ${{ env.KUSTOMIZE_VERSION }} + - name: Run chart-testing (template) run: | - helm template --set components={"search,descheduler,schedulerEstimator"} --dependency-update ./charts/karmada --debug > /dev/null - helm template --set components={"search,descheduler,schedulerEstimator"},certs.mode=custom --dependency-update ./charts/karmada --debug > /dev/null - helm template --set components={"search,descheduler,schedulerEstimator"},installMode=component --dependency-update ./charts/karmada --debug > /dev/null - helm template --set installMode=agent --dependency-update ./charts/karmada --debug > /dev/null - helm template --dependency-update ./charts/karmada-operator --debug > /dev/null + cat < post-render.sh + #!/bin/sh + # save helm stdout to file, kustomize will read this + cat > all.yaml + kustomize build + EOF + + chmod +x post-render.sh + + cat < kustomization.yaml + resources: + - all.yaml + EOF + + helm template --set components={"search,descheduler,schedulerEstimator"} --dependency-update ./charts/karmada \ + --post-renderer ./post-render.sh --debug > /dev/null + helm template --set components={"search,descheduler,schedulerEstimator"},certs.mode=custom --dependency-update \ + ./charts/karmada --post-renderer ./post-render.sh --debug > /dev/null + helm template --set components={"search,descheduler,schedulerEstimator"},installMode=component --dependency-update \ + ./charts/karmada --post-renderer ./post-render.sh --debug > /dev/null + helm template --set installMode=agent --dependency-update ./charts/karmada --post-renderer ./post-render.sh --debug > /dev/null + helm template --dependency-update ./charts/karmada-operator --post-renderer ./post-render.sh --debug > /dev/null + + rm post-render.sh all.yaml kustomization.yaml # Python is required because `ct lint` runs Yamale (https://github.com/23andMe/Yamale) and # yamllint (https://github.com/adrienverge/yamllint) which require Python diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 48dda9e8de1c..30506de306f7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,10 +33,11 @@ jobs: GOOS: ${{ matrix.os }} GOARCH: ${{ matrix.arch }} run: make release-${{ matrix.target }} - - name: Making helm charts - env: - VERSION: ${{ github.ref_name }} - run: make package-chart + - name: upload cli + uses: actions/upload-artifact@v4 + with: + name: cli-${{ matrix.target }}-${{ matrix.os }}-${{ matrix.arch }}.tgz + path: _output/release/${{ matrix.target }}-${{ matrix.os }}-${{ matrix.arch }}.tgz - name: Uploading assets... if: ${{ !env.ACT }} uses: softprops/action-gh-release@v2 @@ -44,10 +45,43 @@ jobs: files: | _output/release/${{ matrix.target }}-${{ matrix.os }}-${{ matrix.arch }}.tgz _output/release/${{ matrix.target }}-${{ matrix.os }}-${{ matrix.arch }}.tgz.sha256 + generate-subject-for-cli-provenance: + needs: [release-assests] + runs-on: ubuntu-22.04 + outputs: + hashes: ${{ steps.hash.outputs.hashes }} + steps: + - name: download cli + uses: actions/download-artifact@v4 + with: + path: _output/release + pattern: cli-* + merge-multiple: true + - name: generate cli hash + id: hash + run: | + cd _output/release + # sha256sum generates sha256 hash for cli. + # base64 -w0 encodes to base64 and outputs on a single line. + echo "hashes=$(sha256sum *.tgz|base64 -w0)" >> "$GITHUB_OUTPUT" + cli-provenance: + needs: [generate-subject-for-cli-provenance] + permissions: + actions: read # for detecting the Github Actions environment + id-token: write # Needed for provenance signing and ID + contents: write # Needed for release uploads + # Must be referenced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0 + with: + base64-subjects: "${{ needs.generate-subject-for-cli-provenance.outputs.hashes }}" + provenance-name: "karmada-cli.intoto.jsonl" + upload-assets: true release-crds-assests: permissions: contents: write # for softprops/action-gh-release to create GitHub release name: release crds + outputs: + hashes: ${{ steps.hash.outputs.hashes }} runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 @@ -61,15 +95,35 @@ jobs: cwd: ./charts/karmada/ files: crds outPath: crds.tar.gz + - name: generate crds hash + id: hash + run: | + # sha256sum generates sha256 hash for crds. + # base64 -w0 encodes to base64 and outputs on a single line. + echo "hashes=$(sha256sum crds.tar.gz | base64 -w0)" >> "$GITHUB_OUTPUT" - name: Uploading crd assets... uses: softprops/action-gh-release@v2 with: files: | crds.tar.gz + crds-provenance: + needs: [release-crds-assests] + permissions: + actions: read # for detecting the Github Actions environment + id-token: write # Needed for provenance signing and ID + contents: write # Needed for release uploads + # Must be referenced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0 + with: + base64-subjects: "${{ needs.release-crds-assests.outputs.hashes }}" + provenance-name: "karmada-crds.intoto.jsonl" + upload-assets: true release-charts: permissions: contents: write # for softprops/action-gh-release to create GitHub release name: Release charts + outputs: + hashes: ${{ steps.hash.outputs.hashes }} runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 @@ -86,10 +140,29 @@ jobs: _output/charts/karmada-chart-${{ github.ref_name }}.tgz.sha256 _output/charts/karmada-operator-chart-${{ github.ref_name }}.tgz _output/charts/karmada-operator-chart-${{ github.ref_name }}.tgz.sha256 + - name: generate charts hash + id: hash + run: | + cd _output/charts + echo "hashes=$(sha256sum *.tgz|base64 -w0)" >> "$GITHUB_OUTPUT" + charts-provenance: + needs: [release-charts] + permissions: + actions: read # for detecting the Github Actions environment + id-token: write # Needed for provenance signing and ID + contents: write # Needed for release uploads + # Must be referenced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0 + with: + base64-subjects: "${{ needs.release-charts.outputs.hashes }}" + provenance-name: "karmada-charts.intoto.jsonl" + upload-assets: true sbom-assests: permissions: contents: write # for softprops/action-gh-release to create GitHub release name: Release sbom + outputs: + hashes: ${{ steps.sbom-hash.outputs.hashes}} runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 @@ -103,11 +176,30 @@ jobs: - name: Tar the sbom files run: | tar -zcf sbom.tar.gz *.spdx + - name: Generate SBOM hash + shell: bash + id: sbom-hash + run: | + # sha256sum generates sha256 hash for sbom. + # base64 -w0 encodes to base64 and outputs on a single line. + echo "hashes=$(sha256sum sbom.tar.gz | base64 -w0)" >> "$GITHUB_OUTPUT" - name: Uploading sbom assets... uses: softprops/action-gh-release@v2 with: files: | sbom.tar.gz + sbom-provenance: + needs: [sbom-assests] + permissions: + actions: read # for detecting the Github Actions environment + id-token: write # Needed for provenance signing and ID + contents: write # Needed for release uploads + # Must be referenced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0 + with: + base64-subjects: "${{ needs.sbom-assests.outputs.hashes }}" + provenance-name: "karmada-sbom.intoto.jsonl" + upload-assets: true update-krew-index: needs: release-assests name: Update krew-index diff --git a/.go-version b/.go-version index 2a0ba77cc5e3..013173af5e9b 100644 --- a/.go-version +++ b/.go-version @@ -1 +1 @@ -1.22.4 +1.22.6 diff --git a/README.md b/README.md index d4770e60914d..b9279e7e5206 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ This guide will cover: - Propagate an application by using `karmada`. ### Prerequisites -- [Go](https://golang.org/) version v1.22.4+ +- [Go](https://golang.org/) version follows [go.mod](https://github.com/karmada-io/karmada/blob/master/go.mod#L3) - [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) version v1.19+ - [kind](https://kind.sigs.k8s.io/) version v0.14.0+ diff --git a/artifacts/deploy/karmada-controller-manager.yaml b/artifacts/deploy/karmada-controller-manager.yaml index 5771b1d4ad3c..a2562c520e2e 100644 --- a/artifacts/deploy/karmada-controller-manager.yaml +++ b/artifacts/deploy/karmada-controller-manager.yaml @@ -26,12 +26,11 @@ spec: command: - /bin/karmada-controller-manager - --kubeconfig=/etc/kubeconfig - - --bind-address=0.0.0.0 - --cluster-status-update-frequency=10s - - --secure-port=10357 - --failover-eviction-timeout=30s - --controllers=*,hpaScaleTargetMarker,deploymentReplicasSyncer - --feature-gates=PropagationPolicyPreemption=true,MultiClusterService=true + - --health-probe-bind-address=0.0.0.0:10357 - --v=4 livenessProbe: httpGet: diff --git a/artifacts/deploy/karmada-descheduler.yaml b/artifacts/deploy/karmada-descheduler.yaml index 53d0d189bd7c..8a52826a0368 100644 --- a/artifacts/deploy/karmada-descheduler.yaml +++ b/artifacts/deploy/karmada-descheduler.yaml @@ -26,7 +26,8 @@ spec: command: - /bin/karmada-descheduler - --kubeconfig=/etc/kubeconfig - - --bind-address=0.0.0.0 + - --metrics-bind-address=0.0.0.0:10358 + - --health-probe-bind-address=0.0.0.0:10358 - --scheduler-estimator-ca-file=/etc/karmada/pki/ca.crt - --scheduler-estimator-cert-file=/etc/karmada/pki/karmada.crt - --scheduler-estimator-key-file=/etc/karmada/pki/karmada.key diff --git a/artifacts/deploy/karmada-scheduler-estimator.yaml b/artifacts/deploy/karmada-scheduler-estimator.yaml index 85d6111f5aae..8b6a7110d483 100644 --- a/artifacts/deploy/karmada-scheduler-estimator.yaml +++ b/artifacts/deploy/karmada-scheduler-estimator.yaml @@ -30,6 +30,8 @@ spec: - --grpc-auth-cert-file=/etc/karmada/pki/karmada.crt - --grpc-auth-key-file=/etc/karmada/pki/karmada.key - --grpc-client-ca-file=/etc/karmada/pki/ca.crt + - --metrics-bind-address=0.0.0.0:10351 + - --health-probe-bind-address=0.0.0.0:10351 livenessProbe: httpGet: path: /healthz diff --git a/artifacts/deploy/karmada-scheduler.yaml b/artifacts/deploy/karmada-scheduler.yaml index f863fba55a3a..5affd87b1172 100644 --- a/artifacts/deploy/karmada-scheduler.yaml +++ b/artifacts/deploy/karmada-scheduler.yaml @@ -36,7 +36,8 @@ spec: - /bin/karmada-scheduler - --kubeconfig=/etc/kubeconfig - --bind-address=0.0.0.0 - - --secure-port=10351 + - --metrics-bind-address=0.0.0.0:10351 + - --health-probe-bind-address=0.0.0.0:10351 - --enable-scheduler-estimator=true - --scheduler-estimator-ca-file=/etc/karmada/pki/ca.crt - --scheduler-estimator-cert-file=/etc/karmada/pki/karmada.crt diff --git a/charts/karmada-operator/crds/operator.karmada.io_karmadas.yaml b/charts/karmada-operator/crds/operator.karmada.io_karmadas.yaml index 8da390cc121e..9a04701a8dbe 100644 --- a/charts/karmada-operator/crds/operator.karmada.io_karmadas.yaml +++ b/charts/karmada-operator/crds/operator.karmada.io_karmadas.yaml @@ -1733,6 +1733,34 @@ spec: type: object type: object type: object + crdTarball: + description: |- + CRDTarball specifies the source from which the Karmada CRD tarball should be downloaded, along with the download policy to use. + If not set, the operator will download the tarball from a GitHub release. + By default, it will download the tarball of the same version as the operator itself. + For instance, if the operator's version is v1.10.0, the tarball will be downloaded from the following location: + https://github.com/karmada-io/karmada/releases/download/v1.10.0/crds.tar.gz + By default, the operator will only attempt to download the tarball if it's not yet present in the local cache. + properties: + crdDownloadPolicy: + default: IfNotPresent + description: |- + CRDDownloadPolicy specifies a policy that should be used to download the CRD tarball. + Valid values are "Always" and "IfNotPresent". + Defaults to "IfNotPresent". + enum: + - Always + - IfNotPresent + type: string + httpSource: + description: HTTPSource specifies how to download the CRD tarball + via either HTTP or HTTPS protocol. + properties: + url: + description: URL specifies the URL of the CRD tarball resource. + type: string + type: object + type: object featureGates: additionalProperties: type: boolean diff --git a/charts/karmada/README.md b/charts/karmada/README.md index c8944c02c3cb..8907634e8991 100644 --- a/charts/karmada/README.md +++ b/charts/karmada/README.md @@ -259,7 +259,7 @@ helm install karmada-scheduler-estimator -n karmada-system ./charts/karmada | `agent.affinity` | Affinity of the agent | `{}` | | `agent.tolerations` | Tolerations of the agent | `[]` | | `agent.strategy` | Strategy of the agent | `{"type": "RollingUpdate", "rollingUpdate": {"maxUnavailable": "0", "maxSurge": "50%"} }` | -| `scheduler.labels` | Labels of the schedeler deployment | `{"app": "karmada-scheduler"}` | +| `scheduler.labels` | Labels of the scheduler deployment | `{"app": "karmada-scheduler"}` | | `scheduler.replicaCount` | Target replicas of the scheduler | `1` | | `scheduler.podLabels` | Labels of the scheduler pods | `{}` | | `scheduler.podAnnotations` | Annotations of the scheduler pods | `{}` | diff --git a/charts/karmada/_crds/bases/policy/policy.karmada.io_clusterpropagationpolicies.yaml b/charts/karmada/_crds/bases/policy/policy.karmada.io_clusterpropagationpolicies.yaml index 250a56b35776..c1ac7c57262e 100644 --- a/charts/karmada/_crds/bases/policy/policy.karmada.io_clusterpropagationpolicies.yaml +++ b/charts/karmada/_crds/bases/policy/policy.karmada.io_clusterpropagationpolicies.yaml @@ -164,6 +164,10 @@ spec: cluster from which the application is migrated. Valid options are "Immediately", "Graciously" and "Never". Defaults to "Graciously". + enum: + - Immediately + - Graciously + - Never type: string required: - decisionConditions diff --git a/charts/karmada/_crds/bases/policy/policy.karmada.io_propagationpolicies.yaml b/charts/karmada/_crds/bases/policy/policy.karmada.io_propagationpolicies.yaml index 7e69586fcd28..1415e24325dd 100644 --- a/charts/karmada/_crds/bases/policy/policy.karmada.io_propagationpolicies.yaml +++ b/charts/karmada/_crds/bases/policy/policy.karmada.io_propagationpolicies.yaml @@ -161,6 +161,10 @@ spec: cluster from which the application is migrated. Valid options are "Immediately", "Graciously" and "Never". Defaults to "Graciously". + enum: + - Immediately + - Graciously + - Never type: string required: - decisionConditions diff --git a/charts/karmada/_crds/bases/work/work.karmada.io_clusterresourcebindings.yaml b/charts/karmada/_crds/bases/work/work.karmada.io_clusterresourcebindings.yaml index 8263b2e225f1..7895411a95a2 100644 --- a/charts/karmada/_crds/bases/work/work.karmada.io_clusterresourcebindings.yaml +++ b/charts/karmada/_crds/bases/work/work.karmada.io_clusterresourcebindings.yaml @@ -335,6 +335,10 @@ spec: cluster from which the application is migrated. Valid options are "Immediately", "Graciously" and "Never". Defaults to "Graciously". + enum: + - Immediately + - Graciously + - Never type: string required: - decisionConditions diff --git a/charts/karmada/_crds/bases/work/work.karmada.io_resourcebindings.yaml b/charts/karmada/_crds/bases/work/work.karmada.io_resourcebindings.yaml index 7e2dd2eeade4..f69531f230bd 100644 --- a/charts/karmada/_crds/bases/work/work.karmada.io_resourcebindings.yaml +++ b/charts/karmada/_crds/bases/work/work.karmada.io_resourcebindings.yaml @@ -335,6 +335,10 @@ spec: cluster from which the application is migrated. Valid options are "Immediately", "Graciously" and "Never". Defaults to "Graciously". + enum: + - Immediately + - Graciously + - Never type: string required: - decisionConditions diff --git a/charts/karmada/templates/_helpers.tpl b/charts/karmada/templates/_helpers.tpl index 2d129b7cea09..546b2a149931 100644 --- a/charts/karmada/templates/_helpers.tpl +++ b/charts/karmada/templates/_helpers.tpl @@ -586,40 +586,31 @@ Return the proper Docker Image Registry Secret Names {{- end }} {{- end -}} -{{- define "karmada.init-sa-secret.volume" -}} -{{- $name := include "karmada.name" . -}} -- name: init-sa-secret - secret: - secretName: {{ $name }}-hook-job -{{- end -}} - -{{- define "karmada.init-sa-secret.volumeMount" -}} -- name: init-sa-secret - mountPath: /opt/mount -{{- end -}} - -{{- define "karmada.initContainer.build-kubeconfig" -}} -TOKEN=$(cat /opt/mount/token) -kubectl config set-cluster karmada-host --server=https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT} --certificate-authority=/opt/mount/ca.crt -kubectl config set-credentials default --token=$TOKEN -kubectl config set-context karmada-host-context --cluster=karmada-host --user=default --namespace=default -kubectl config use-context karmada-host-context -{{- end -}} - {{- define "karmada.initContainer.waitEtcd" -}} - name: wait - image: {{ include "karmada.kubectl.image" . }} + image: {{ include "karmada.cfssl.image" . }} imagePullPolicy: {{ .Values.kubectl.image.pullPolicy }} command: - /bin/sh - -c - | bash <<'EOF' - {{- include "karmada.initContainer.build-kubeconfig" . | nindent 6 }} - kubectl rollout status statefulset etcd -n {{ include "karmada.namespace" . }} + set -ex + while true; do + ETCD_ENDPOINT=${ETCD_CLIENT_SERVICE_HOST}":"${ETCD_CLIENT_SERVICE_PORT} + + # check etcd connectivity by executing curl. + # if etcd is ready, the response of curl would be `curl: (52) Empty reply from server`, with return code 52. + # if not, the response of curl would be like `curl: (7) Failed to connect to .....`, with other return code. + if curl --connect-timeout 2 ${ETCD_ENDPOINT} || [ $? -eq 52 ]; then + break + fi + + echo "failed to connect to "${ETCD_ENDPOINT} + sleep 2 + done + echo "successfully connect to "${ETCD_ENDPOINT} EOF - volumeMounts: - {{- include "karmada.init-sa-secret.volumeMount" .| nindent 4 }} {{- end -}} {{- define "karmada.initContainer.waitStaticResource" -}} @@ -631,9 +622,18 @@ kubectl config use-context karmada-host-context - -c - | bash <<'EOF' - {{- include "karmada.initContainer.build-kubeconfig" . | nindent 6 }} - kubectl wait --for=condition=complete job {{ include "karmada.name" . }}-static-resource -n {{ include "karmada.namespace" . }} + set -ex + + # here are three cases: + # case first installation: no `cm/karmada-version` at first, so when you get it, it means `karmada-static-resource-job` finished. + # case restart: already has `cm/karmada-version`, which means `karmada-static-resource-job` already finished. + # case upgrading: already has `cm/karmada-version`, but it may be old version, we should wait until `.data.karmadaVersion` equal to current `.Values.karmadaImageVersion`. + while [[ $(kubectl --kubeconfig /etc/kubeconfig get configmap karmada-version -n {{ .Values.systemNamespace }} -o jsonpath='{.data.karmadaVersion}') != {{ .Values.karmadaImageVersion }} ]]; do + echo "wait for karmada-static-resource-job finished"; sleep 2 + done + + echo "karmada-static-resource-job successfully completed since expected configmap value was found" EOF volumeMounts: - {{- include "karmada.init-sa-secret.volumeMount" .| nindent 4 }} + {{- include "karmada.kubeconfig.volumeMount" .| nindent 4 }} {{- end -}} diff --git a/charts/karmada/templates/_karmada_apiservice.tpl b/charts/karmada/templates/_karmada_apiservice.tpl index 74b35ff8dd53..1166a2ffd17d 100644 --- a/charts/karmada/templates/_karmada_apiservice.tpl +++ b/charts/karmada/templates/_karmada_apiservice.tpl @@ -32,6 +32,8 @@ metadata: spec: type: ExternalName externalName: {{ $name }}-aggregated-apiserver.{{ include "karmada.namespace" . }}.svc.{{ .Values.clusterDomain }} +{{- end }} +{{- if has "metricsAdapter" .Values.components }} --- apiVersion: apiregistration.k8s.io/v1 kind: APIService diff --git a/charts/karmada/templates/karmada-aggregated-apiserver.yaml b/charts/karmada/templates/karmada-aggregated-apiserver.yaml index cc5e45fdaa35..d353cc8b33d1 100644 --- a/charts/karmada/templates/karmada-aggregated-apiserver.yaml +++ b/charts/karmada/templates/karmada-aggregated-apiserver.yaml @@ -98,7 +98,6 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} volumes: - {{- include "karmada.init-sa-secret.volume" . | nindent 8 }} {{- include "karmada.kubeconfig.volume" . | nindent 8 }} - name: apiserver-cert secret: diff --git a/charts/karmada/templates/karmada-apiserver.yaml b/charts/karmada/templates/karmada-apiserver.yaml index 4c561ec240fd..0be9002dc5ce 100644 --- a/charts/karmada/templates/karmada-apiserver.yaml +++ b/charts/karmada/templates/karmada-apiserver.yaml @@ -63,7 +63,7 @@ spec: - --service-account-issuer=https://kubernetes.default.svc.{{ .Values.clusterDomain }} - --service-account-key-file=/etc/kubernetes/pki/karmada.key - --service-account-signing-key-file=/etc/kubernetes/pki/karmada.key - - --service-cluster-ip-range=10.96.0.0/12 + - --service-cluster-ip-range={{ .Values.apiServer.serviceClusterIPRange }} - --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt - --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key - --requestheader-allowed-names=front-proxy-client @@ -137,7 +137,6 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} volumes: - {{- include "karmada.init-sa-secret.volume" . | nindent 8 }} - name: apiserver-cert secret: secretName: {{ $name }}-cert diff --git a/charts/karmada/templates/karmada-controller-manager.yaml b/charts/karmada/templates/karmada-controller-manager.yaml index 75d524b243dd..88b816f63165 100644 --- a/charts/karmada/templates/karmada-controller-manager.yaml +++ b/charts/karmada/templates/karmada-controller-manager.yaml @@ -42,7 +42,6 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} volumes: - {{- include "karmada.init-sa-secret.volume" . | nindent 8 }} {{- include "karmada.kubeconfig.volume" . | nindent 8 }} initContainers: {{- include "karmada.initContainer.waitStaticResource" . | nindent 8 }} diff --git a/charts/karmada/templates/karmada-descheduler.yaml b/charts/karmada/templates/karmada-descheduler.yaml index e3b8c08a18ad..577e05e57b5e 100644 --- a/charts/karmada/templates/karmada-descheduler.yaml +++ b/charts/karmada/templates/karmada-descheduler.yaml @@ -50,9 +50,10 @@ spec: command: - /bin/karmada-descheduler - --kubeconfig=/etc/kubeconfig - - --bind-address=0.0.0.0 + - --metrics-bind-address=0.0.0.0:10358 + - --health-probe-bind-address=0.0.0.0:10358 - --leader-elect-resource-namespace={{ $systemNamespace }} - - --scheduler-estimator-ca-file=/etc/karmada/pki/ca.crt + - --scheduler-estimator-ca-file=/etc/karmada/pki/server-ca.crt - --scheduler-estimator-cert-file=/etc/karmada/pki/karmada.crt - --scheduler-estimator-key-file=/etc/karmada/pki/karmada.key - --v=4 @@ -77,7 +78,6 @@ spec: resources: {{- toYaml .Values.descheduler.resources | nindent 12 }} volumes: - {{- include "karmada.init-sa-secret.volume" . | nindent 8 }} {{- include "karmada.descheduler.kubeconfig.volume" . | nindent 8 }} {{- include "karmada.scheduler.cert.volume" . | nindent 8 }} diff --git a/charts/karmada/templates/karmada-metrics-adapter.yaml b/charts/karmada/templates/karmada-metrics-adapter.yaml index 16bc12bb5dd7..4c13ea825d38 100644 --- a/charts/karmada/templates/karmada-metrics-adapter.yaml +++ b/charts/karmada/templates/karmada-metrics-adapter.yaml @@ -83,7 +83,6 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} volumes: - {{- include "karmada.init-sa-secret.volume" . | nindent 8 }} {{- include "karmada.kubeconfig.volume" . | nindent 8 }} - name: apiserver-cert secret: diff --git a/charts/karmada/templates/karmada-scheduler-estimator.yaml b/charts/karmada/templates/karmada-scheduler-estimator.yaml index 1fa7f18a9ca4..facf105c13fc 100644 --- a/charts/karmada/templates/karmada-scheduler-estimator.yaml +++ b/charts/karmada/templates/karmada-scheduler-estimator.yaml @@ -17,7 +17,7 @@ spec: replicas: {{ $member.replicaCount }} selector: matchLabels: - app: karmada-scheduler-estimator-{{ $clusterName }} + cluster: {{ $clusterName }} {{- include "karmada.schedulerEstimator.labels" $ | nindent 6 }} {{- with $.Values.schedulerEstimator.strategy }} strategy: @@ -30,7 +30,7 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} labels: - app: karmada-scheduler-estimator-{{ $clusterName }} + cluster: {{ $clusterName }} {{- include "karmada.schedulerEstimator.labels" $ | nindent 8 }} {{- include "karmada.schedulerEstimator.podLabels" $ | nindent 8 }} spec: @@ -50,7 +50,9 @@ spec: - --cluster-name={{ $clusterName }} - --grpc-auth-cert-file=/etc/karmada/pki/karmada.crt - --grpc-auth-key-file=/etc/karmada/pki/karmada.key - - --grpc-client-ca-file=/etc/karmada/pki/ca.crt + - --grpc-client-ca-file=/etc/karmada/pki/server-ca.crt + - --metrics-bind-address=0.0.0.0:10351 + - --health-probe-bind-address=0.0.0.0:10351 {{- with (include "karmada.schedulerEstimator.featureGates" (dict "featureGatesArg" $.Values.schedulerEstimator.featureGates)) }} - {{ . }} {{- end}} @@ -91,7 +93,7 @@ metadata: cluster: {{ $clusterName }} spec: selector: - app: karmada-scheduler-estimator-{{ $clusterName }} + cluster: {{ $clusterName }} {{- include "karmada.schedulerEstimator.labels" $ | nindent 4 }} ports: - protocol: TCP @@ -138,7 +140,7 @@ metadata: spec: selector: matchLabels: - app: karmada-scheduler-estimator-{{ $clusterName }} + cluster: {{ $clusterName }} {{- include "karmada.schedulerEstimator.labels" $ | nindent 6 }} {{ toYaml $.Values.schedulerEstimator.podDisruptionBudget | nindent 2 }} {{- end -}} diff --git a/charts/karmada/templates/karmada-scheduler.yaml b/charts/karmada/templates/karmada-scheduler.yaml index c4000429187b..acfc67511d1a 100644 --- a/charts/karmada/templates/karmada-scheduler.yaml +++ b/charts/karmada/templates/karmada-scheduler.yaml @@ -53,7 +53,7 @@ spec: - --bind-address=0.0.0.0 - --secure-port=10351 - --leader-elect-resource-namespace={{ $systemNamespace }} - - --scheduler-estimator-ca-file=/etc/karmada/pki/ca.crt + - --scheduler-estimator-ca-file=/etc/karmada/pki/server-ca.crt - --scheduler-estimator-cert-file=/etc/karmada/pki/karmada.crt - --scheduler-estimator-key-file=/etc/karmada/pki/karmada.key livenessProbe: @@ -76,7 +76,6 @@ spec: resources: {{- toYaml .Values.scheduler.resources | nindent 12 }} volumes: - {{- include "karmada.init-sa-secret.volume" . | nindent 8 }} {{- include "karmada.kubeconfig.volume" . | nindent 8 }} {{- include "karmada.scheduler.cert.volume" . | nindent 8 }} diff --git a/charts/karmada/templates/karmada-search.yaml b/charts/karmada/templates/karmada-search.yaml index bb4c91fa9824..76c9f72611a4 100644 --- a/charts/karmada/templates/karmada-search.yaml +++ b/charts/karmada/templates/karmada-search.yaml @@ -92,7 +92,6 @@ spec: resources: {{- toYaml .Values.apiServer.resources | nindent 12 }} volumes: - {{- include "karmada.init-sa-secret.volume" . | nindent 8 }} {{- include "karmada.search.kubeconfig.volume" . | nindent 8 }} {{- include "karmada.search.etcd.cert.volume" . | nindent 8 }} --- diff --git a/charts/karmada/templates/karmada-static-resource-job.yaml b/charts/karmada/templates/karmada-static-resource-job.yaml index 1d2ea6179910..a1bf6cf605ab 100644 --- a/charts/karmada/templates/karmada-static-resource-job.yaml +++ b/charts/karmada/templates/karmada-static-resource-job.yaml @@ -11,6 +11,9 @@ metadata: spec: parallelism: 1 completions: 1 + {{- if semverCompare ">=1.23.0-0" .Capabilities.KubeVersion.GitVersion }} + ttlSecondsAfterFinished: {{ .Values.staticResourceJob.ttlSecondsAfterFinished }} + {{- end }} template: metadata: name: {{ $name }} @@ -42,6 +45,17 @@ spec: kubectl apply -k /crds --kubeconfig /etc/kubeconfig kubectl apply -f /static-resources/system-namespace.yaml --kubeconfig /etc/kubeconfig kubectl apply -f /static-resources/ --kubeconfig /etc/kubeconfig + + kubectl --kubeconfig /etc/kubeconfig apply -f - < 0 ]]; do + # The `post-install hook job` may be applied before all karmada components are ready that rely on `static-resource job`. + # So, we have to postpone the deletion of the `static-resource job` until all karmada components are up and running. + while [[ $(kubectl get pods -n {{ $namespace }} --field-selector=status.phase!=Running,status.phase!=Succeeded -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' | grep -v static-resource | wc -l) > 0 ]]; + do echo "waiting for all pods of karmada control plane ready..."; sleep 1; done kubectl delete job {{ $name }}-static-resource -n {{ $namespace }} - kubectl delete secret {{ $name }}-hook-job -n {{ $namespace }} EOF {{- end }} +{{- end }} diff --git a/charts/karmada/templates/pre-install-job.yaml b/charts/karmada/templates/pre-install-job.yaml index cc8fe785f67a..4862252cdae6 100644 --- a/charts/karmada/templates/pre-install-job.yaml +++ b/charts/karmada/templates/pre-install-job.yaml @@ -459,21 +459,6 @@ metadata: {{- include "karmada.preInstallJob.labels" . | nindent 4 }} {{- end }} --- -apiVersion: v1 -kind: Secret -metadata: - name: {{ $name }}-hook-job - namespace: {{ $namespace }} - annotations: - "kubernetes.io/service-account.name": {{ $name }}-hook-job - "helm.sh/hook": pre-install - "helm.sh/hook-weight": "1" - {{- if "karmada.preInstallJob.labels" }} - labels: - {{- include "karmada.preInstallJob.labels" . | nindent 4 }} - {{- end }} -type: kubernetes.io/service-account-token ---- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: diff --git a/charts/karmada/values.yaml b/charts/karmada/values.yaml index 21140ec05161..22fe45f5b2bb 100644 --- a/charts/karmada/values.yaml +++ b/charts/karmada/values.yaml @@ -102,6 +102,9 @@ preInstallJob: staticResourceJob: tolerations: [] nodeSelector: {} + ## Set a TTL for the static-resource Job, the Job will be automatically cleaned up after this time. + ## This only works on Kubernetes version 1.23 or higher. + ttlSecondsAfterFinished: 10 ## post-install job config postInstallJob: @@ -421,6 +424,7 @@ apiServer: ## will take effect when 'apiServer.serviceType' is 'NodePort'. ## If no port is specified, the nodePort will be automatically assigned. nodePort: 0 + serviceClusterIPRange: "10.96.0.0/12" maxRequestsInflight: 1500 maxMutatingRequestsInflight: 500 ## @param apiserver.strategy strategy of the apiserver @@ -606,6 +610,8 @@ kubeControllerManager: controllers: namespace,garbagecollector,serviceaccount-token,ttl-after-finished,bootstrapsigner,tokencleaner,csrapproving,csrcleaner,csrsigning,clusterrole-aggregation ## @param apiServer.podDisruptionBudget podDisruptionBudget: *podDisruptionBudget + serviceClusterIPRange: "10.96.0.0/12" + clusterCIDR: "10.244.0.0/16" ## etcd config etcd: diff --git a/cmd/controller-manager/app/controllermanager.go b/cmd/controller-manager/app/controllermanager.go index fb7ceab1ece8..134634b0b80b 100644 --- a/cmd/controller-manager/app/controllermanager.go +++ b/cmd/controller-manager/app/controllermanager.go @@ -19,8 +19,6 @@ package app import ( "context" "flag" - "net" - "strconv" "time" "github.com/spf13/cobra" @@ -102,6 +100,10 @@ func NewControllerManagerCommand(ctx context.Context) *cobra.Command { The controllers watch Karmada objects and then talk to the underlying clusters' API servers to create regular Kubernetes resources.`, RunE: func(_ *cobra.Command, _ []string) error { + // complete options + if err := opts.Complete(); err != nil { + return err + } // validate options if errs := opts.Validate(); len(errs) != 0 { return errs.ToAggregate() @@ -156,7 +158,7 @@ func Run(ctx context.Context, opts *options.Options) error { RenewDeadline: &opts.LeaderElection.RenewDeadline.Duration, RetryPeriod: &opts.LeaderElection.RetryPeriod.Duration, LeaderElectionResourceLock: opts.LeaderElection.ResourceLock, - HealthProbeBindAddress: net.JoinHostPort(opts.BindAddress, strconv.Itoa(opts.SecurePort)), + HealthProbeBindAddress: opts.HealthProbeBindAddress, LivenessEndpointName: "/healthz", Metrics: metricsserver.Options{BindAddress: opts.MetricsBindAddress}, MapperProvider: restmapper.MapperProvider, diff --git a/cmd/controller-manager/app/options/options.go b/cmd/controller-manager/app/options/options.go index dbe53e9185b3..a22dcd206e04 100644 --- a/cmd/controller-manager/app/options/options.go +++ b/cmd/controller-manager/app/options/options.go @@ -18,7 +18,9 @@ package options import ( "fmt" + "net" "regexp" + "strconv" "strings" "time" @@ -56,9 +58,11 @@ type Options struct { // LeaderElection defines the configuration of leader election client. LeaderElection componentbaseconfig.LeaderElectionConfiguration // BindAddress is the IP address on which to listen for the --secure-port port. + // Deprecated: Use HealthProbeBindAddress instead. This will be removed in release 1.12+. BindAddress string // SecurePort is the port that the the server serves at. // Note: We hope support https in the future once controller-runtime provides the functionality. + // Deprecated: Use HealthProbeBindAddress instead. This will be removed in release 1.12+. SecurePort int // ClusterStatusUpdateFrequency is the frequency that controller computes and report cluster status. // It must work with ClusterMonitorGracePeriod(--cluster-monitor-grace-period) in karmada-controller-manager. @@ -112,6 +116,11 @@ type Options struct { // It can be set to "0" to disable the metrics serving. // Defaults to ":8080". MetricsBindAddress string + // HealthProbeBindAddress is the TCP address that the controller should bind to + // for serving health probes + // It can be set to "0" to disable serving the health probe. + // Defaults to ":10357". + HealthProbeBindAddress string // ConcurrentClusterSyncs is the number of cluster objects that are // allowed to sync concurrently. ConcurrentClusterSyncs int @@ -172,6 +181,10 @@ func (o *Options) AddFlags(flags *pflag.FlagSet, allControllers, disabledByDefau "The IP address on which to listen for the --secure-port port.") flags.IntVar(&o.SecurePort, "secure-port", defaultPort, "The secure port on which to serve HTTPS.") + // nolint: errcheck + flags.MarkDeprecated("bind-address", "This flag is deprecated and will be removed in release 1.12+. Use --health-probe-bind-address instead.") + // nolint: errcheck + flags.MarkDeprecated("secure-port", "This flag is deprecated and will be removed in release 1.12+. Use --health-probe-bind-address instead.") flags.DurationVar(&o.ClusterStatusUpdateFrequency.Duration, "cluster-status-update-frequency", 10*time.Second, "Specifies how often karmada-controller-manager posts cluster status to karmada-apiserver.") flags.BoolVar(&o.LeaderElection.LeaderElect, "leader-elect", true, "Start a leader election client and gain leadership before executing the main loop. Enable this when running replicated components for high availability.") @@ -219,6 +232,7 @@ func (o *Options) AddFlags(flags *pflag.FlagSet, allControllers, disabledByDefau flags.DurationVar(&o.ClusterCacheSyncTimeout.Duration, "cluster-cache-sync-timeout", util.CacheSyncTimeout, "Timeout period waiting for cluster cache to sync.") flags.DurationVar(&o.ResyncPeriod.Duration, "resync-period", 0, "Base frequency the informers are resynced.") flags.StringVar(&o.MetricsBindAddress, "metrics-bind-address", ":8080", "The TCP address that the controller should bind to for serving prometheus metrics(e.g. 127.0.0.1:8080, :8080). It can be set to \"0\" to disable the metrics serving.") + flags.StringVar(&o.HealthProbeBindAddress, "health-probe-bind-address", "", "The TCP address that the controller should bind to for serving health probes(e.g. 127.0.0.1:10357, :10357). It can be set to \"0\" to disable serving the health probe. Defaults to 0.0.0.0:10357.") flags.IntVar(&o.ConcurrentClusterSyncs, "concurrent-cluster-syncs", 5, "The number of Clusters that are allowed to sync concurrently.") flags.IntVar(&o.ConcurrentClusterResourceBindingSyncs, "concurrent-clusterresourcebinding-syncs", 5, "The number of ClusterResourceBindings that are allowed to sync concurrently.") flags.IntVar(&o.ConcurrentResourceBindingSyncs, "concurrent-resourcebinding-syncs", 5, "The number of ResourceBindings that are allowed to sync concurrently.") @@ -247,3 +261,11 @@ func (o *Options) SkippedNamespacesRegexps() []*regexp.Regexp { } return skippedPropagatingNamespaces } + +// Complete ensures that options are valid and marshals them if necessary. +func (o *Options) Complete() error { + if len(o.HealthProbeBindAddress) == 0 { + o.HealthProbeBindAddress = net.JoinHostPort(o.BindAddress, strconv.Itoa(o.SecurePort)) + } + return nil +} diff --git a/cmd/controller-manager/app/options/validation.go b/cmd/controller-manager/app/options/validation.go index c60b2fc14cf8..01115493aa99 100644 --- a/cmd/controller-manager/app/options/validation.go +++ b/cmd/controller-manager/app/options/validation.go @@ -34,9 +34,6 @@ func (o *Options) Validate() field.ErrorList { if err := skippedResourceConfig.Parse(o.SkippedPropagatingAPIs); err != nil { errs = append(errs, field.Invalid(newPath.Child("SkippedPropagatingAPIs"), o.SkippedPropagatingAPIs, "Invalid API string")) } - if o.SecurePort < 0 || o.SecurePort > 65535 { - errs = append(errs, field.Invalid(newPath.Child("SecurePort"), o.SecurePort, "must be between 0 and 65535 inclusive")) - } if o.ClusterStatusUpdateFrequency.Duration <= 0 { errs = append(errs, field.Invalid(newPath.Child("ClusterStatusUpdateFrequency"), o.ClusterStatusUpdateFrequency, "must be greater than 0")) } diff --git a/cmd/controller-manager/app/options/validation_test.go b/cmd/controller-manager/app/options/validation_test.go index 2060cf687a15..f1d3df5133e2 100644 --- a/cmd/controller-manager/app/options/validation_test.go +++ b/cmd/controller-manager/app/options/validation_test.go @@ -31,7 +31,6 @@ type ModifyOptions func(option *Options) func New(modifyOptions ModifyOptions) Options { option := Options{ SkippedPropagatingAPIs: "cluster.karmada.io;policy.karmada.io;work.karmada.io", - SecurePort: 8090, ClusterStatusUpdateFrequency: metav1.Duration{Duration: 10 * time.Second}, ClusterLeaseDuration: metav1.Duration{Duration: 10 * time.Second}, ClusterMonitorPeriod: metav1.Duration{Duration: 10 * time.Second}, @@ -67,12 +66,6 @@ func TestValidateControllerManagerConfiguration(t *testing.T) { }), expectedErrs: field.ErrorList{field.Invalid(newPath.Child("SkippedPropagatingAPIs"), "a/b/c/d?", "Invalid API string")}, }, - "invalid SecurePort": { - opt: New(func(options *Options) { - options.SecurePort = -10 - }), - expectedErrs: field.ErrorList{field.Invalid(newPath.Child("SecurePort"), -10, "must be between 0 and 65535 inclusive")}, - }, "invalid ClusterStatusUpdateFrequency": { opt: New(func(options *Options) { options.ClusterStatusUpdateFrequency.Duration = -10 * time.Second diff --git a/cmd/descheduler/app/descheduler.go b/cmd/descheduler/app/descheduler.go index 17183732e16f..b93c4c4be239 100644 --- a/cmd/descheduler/app/descheduler.go +++ b/cmd/descheduler/app/descheduler.go @@ -19,10 +19,8 @@ package app import ( "context" "fmt" - "net" "net/http" "os" - "strconv" "time" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -87,6 +85,11 @@ func NewDeschedulerCommand(stopChan <-chan struct{}) *cobra.Command { if they are failed to be scheduled for a period of time. It relies on karmada-scheduler-estimator to get replica status.`, RunE: func(_ *cobra.Command, _ []string) error { + // complete options + if err := opts.Complete(); err != nil { + return err + } + // validate options if errs := opts.Validate(); len(errs) != 0 { return errs.ToAggregate() @@ -127,7 +130,7 @@ karmada-scheduler-estimator to get replica status.`, func run(opts *options.Options, stopChan <-chan struct{}) error { klog.Infof("karmada-descheduler version: %s", version.Get()) klog.Infof("Please make sure the karmada-scheduler-estimator of all member clusters has been deployed") - go serveHealthzAndMetrics(net.JoinHostPort(opts.BindAddress, strconv.Itoa(opts.SecurePort))) + serveHealthzAndMetrics(opts.HealthProbeBindAddress, opts.MetricsBindAddress) profileflag.ListenAndServe(opts.ProfileOpts) @@ -191,26 +194,64 @@ func run(opts *options.Options, stopChan <-chan struct{}) error { return nil } -func serveHealthzAndMetrics(address string) { +func serveHealthzAndMetrics(healthProbeBindAddress, metricsBindAddress string) { + if healthProbeBindAddress == metricsBindAddress { + if healthProbeBindAddress != "0" { + go serveCombined(healthProbeBindAddress) + } + } else { + if healthProbeBindAddress != "0" { + go serveHealthz(healthProbeBindAddress) + } + if metricsBindAddress != "0" { + go serveMetrics(metricsBindAddress) + } + } +} + +func serveCombined(address string) { mux := http.NewServeMux() - mux.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte("ok")) - }) + mux.HandleFunc("/healthz", healthzHandler) + mux.Handle("/metrics", metricsHandler()) + + serveHTTP(address, mux, "healthz and metrics") +} + +func serveHealthz(address string) { + mux := http.NewServeMux() + mux.HandleFunc("/healthz", healthzHandler) + serveHTTP(address, mux, "healthz") +} + +func serveMetrics(address string) { + mux := http.NewServeMux() + mux.Handle("/metrics", metricsHandler()) + serveHTTP(address, mux, "metrics") +} - mux.Handle("/metrics", promhttp.HandlerFor(ctrlmetrics.Registry, promhttp.HandlerOpts{ +func healthzHandler(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte("ok")) +} + +func metricsHandler() http.Handler { + return promhttp.HandlerFor(ctrlmetrics.Registry, promhttp.HandlerOpts{ ErrorHandling: promhttp.HTTPErrorOnError, - })) + }) +} - httpServer := http.Server{ +func serveHTTP(address string, handler http.Handler, name string) { + httpServer := &http.Server{ Addr: address, - Handler: mux, + Handler: handler, ReadHeaderTimeout: ReadHeaderTimeout, WriteTimeout: WriteTimeout, ReadTimeout: ReadTimeout, } + + klog.Infof("Starting %s server on %s", name, address) if err := httpServer.ListenAndServe(); err != nil { - klog.Errorf("Failed to serve healthz and metrics: %v", err) + klog.Errorf("Failed to serve %s on %s: %v", name, address, err) os.Exit(1) } } diff --git a/cmd/descheduler/app/descheduler_test.go b/cmd/descheduler/app/descheduler_test.go new file mode 100644 index 000000000000..5d787f7d781c --- /dev/null +++ b/cmd/descheduler/app/descheduler_test.go @@ -0,0 +1,128 @@ +/* +Copyright 2024 The Karmada 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 app + +import ( + "net/http" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/karmada-io/karmada/cmd/descheduler/app/options" +) + +func TestNewDeschedulerCommand(t *testing.T) { + stopCh := make(chan struct{}) + cmd := NewDeschedulerCommand(stopCh) + + assert.NotNil(t, cmd) + assert.Equal(t, "karmada-descheduler", cmd.Use) + assert.NotEmpty(t, cmd.Long) +} + +func TestDeschedulerCommandFlagParsing(t *testing.T) { + testCases := []struct { + name string + args []string + expectError bool + }{ + {"Default flags", []string{}, false}, + {"With custom health probe bind address", []string{"--health-probe-bind-address=127.0.0.1:8080"}, false}, + {"With custom metrics bind address", []string{"--metrics-bind-address=127.0.0.1:8081"}, false}, + {"With leader election enabled", []string{"--leader-elect=true"}, false}, + {"With invalid flag", []string{"--invalid-flag=value"}, true}, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + stopCh := make(chan struct{}) + cmd := NewDeschedulerCommand(stopCh) + cmd.SetArgs(tc.args) + err := cmd.ParseFlags(tc.args) + if tc.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} + +func TestServeHealthzAndMetrics(t *testing.T) { + healthAddress := "127.0.0.1:8082" + metricsAddress := "127.0.0.1:8083" + + go serveHealthzAndMetrics(healthAddress, metricsAddress) + + // For servers to start + time.Sleep(100 * time.Millisecond) + + t.Run("Healthz endpoint", func(t *testing.T) { + resp, err := http.Get("http://" + healthAddress + "/healthz") + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + }) + + t.Run("Metrics endpoint", func(t *testing.T) { + resp, err := http.Get("http://" + metricsAddress + "/metrics") + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + }) +} + +func TestDeschedulerOptionsValidation(t *testing.T) { + testCases := []struct { + name string + setupOpts func(*options.Options) + expectError bool + }{ + { + name: "Default options", + setupOpts: func(_ *options.Options) { + // Default options are valid + }, + expectError: false, + }, + { + name: "Invalid descheduling interval", + setupOpts: func(o *options.Options) { + o.DeschedulingInterval.Duration = -1 * time.Second + }, + expectError: true, + }, + { + name: "Invalid unschedulable threshold", + setupOpts: func(o *options.Options) { + o.UnschedulableThreshold.Duration = -1 * time.Second + }, + expectError: true, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + opts := options.NewOptions() + tc.setupOpts(opts) + errs := opts.Validate() + if tc.expectError { + assert.NotEmpty(t, errs) + } else { + assert.Empty(t, errs) + } + }) + } +} diff --git a/cmd/descheduler/app/options/options.go b/cmd/descheduler/app/options/options.go index 67e8a54d4e34..79e8a11a6633 100644 --- a/cmd/descheduler/app/options/options.go +++ b/cmd/descheduler/app/options/options.go @@ -17,6 +17,8 @@ limitations under the License. package options import ( + "net" + "strconv" "time" "github.com/spf13/pflag" @@ -48,8 +50,10 @@ type Options struct { KubeConfig string Master string // BindAddress is the IP address on which to listen for the --secure-port port. + // Deprecated: To specify the TCP address for serving health probes, use HealthProbeBindAddress instead. To specify the TCP address for serving prometheus metrics, use MetricsBindAddress instead. This will be removed in release 1.12+. BindAddress string // SecurePort is the port that the server serves at. + // Deprecated: To specify the TCP address for serving health probes, use HealthProbeBindAddress instead. To specify the TCP address for serving prometheus metrics, use MetricsBindAddress instead. This will be removed in release 1.12+. SecurePort int KubeAPIQPS float32 @@ -75,6 +79,16 @@ type Options struct { // UnschedulableThreshold specifies the period of pod unschedulable condition. UnschedulableThreshold metav1.Duration ProfileOpts profileflag.Options + // MetricsBindAddress is the TCP address that the server should bind to + // for serving prometheus metrics. + // It can be set to "0" to disable the metrics serving. + // Defaults to ":10358". + MetricsBindAddress string + // HealthProbeBindAddress is the TCP address that the server should bind to + // for serving health probes + // It can be set to "0" to disable serving the health probe. + // Defaults to ":10358". + HealthProbeBindAddress string } // NewOptions builds a default descheduler options. @@ -103,6 +117,10 @@ func (o *Options) AddFlags(fs *pflag.FlagSet) { fs.StringVar(&o.Master, "master", o.Master, "The address of the Kubernetes API server. Overrides any value in KubeConfig. Only required if out-of-cluster.") fs.StringVar(&o.BindAddress, "bind-address", defaultBindAddress, "The IP address on which to listen for the --secure-port port.") fs.IntVar(&o.SecurePort, "secure-port", defaultPort, "The secure port on which to serve HTTPS.") + // nolint: errcheck + fs.MarkDeprecated("bind-address", "This flag is deprecated and will be removed in release 1.12+. Use --health-probe-bind-address and --metrics-bind-address instead. Note: In release 1.12+, these two addresses cannot be the same.") + // nolint: errcheck + fs.MarkDeprecated("secure-port", "This flag is deprecated and will be removed in release 1.12+. Use --health-probe-bind-address and --metrics-bind-address instead. Note: In release 1.12+, these two addresses cannot be the same.") fs.Float32Var(&o.KubeAPIQPS, "kube-api-qps", 40.0, "QPS to use while talking with karmada-apiserver.") fs.IntVar(&o.KubeAPIBurst, "kube-api-burst", 60, "Burst to use while talking with karmada-apiserver.") fs.DurationVar(&o.SchedulerEstimatorTimeout.Duration, "scheduler-estimator-timeout", 3*time.Second, "Specifies the timeout period of calling the scheduler estimator service.") @@ -114,5 +132,18 @@ func (o *Options) AddFlags(fs *pflag.FlagSet) { fs.StringVar(&o.SchedulerEstimatorServicePrefix, "scheduler-estimator-service-prefix", "karmada-scheduler-estimator", "The prefix of scheduler estimator service name") fs.DurationVar(&o.DeschedulingInterval.Duration, "descheduling-interval", defaultDeschedulingInterval, "Time interval between two consecutive descheduler executions. Setting this value instructs the descheduler to run in a continuous loop at the interval specified.") fs.DurationVar(&o.UnschedulableThreshold.Duration, "unschedulable-threshold", defaultUnschedulableThreshold, "The period of pod unschedulable condition. This value is considered as a classification standard of unschedulable replicas.") + fs.StringVar(&o.MetricsBindAddress, "metrics-bind-address", "", "The TCP address that the server should bind to for serving prometheus metrics(e.g. 127.0.0.1:10358, :10358). It can be set to \"0\" to disable the metrics serving. Defaults to 0.0.0.0:10358.") + fs.StringVar(&o.HealthProbeBindAddress, "health-probe-bind-address", "", "The TCP address that the server should bind to for serving health probes(e.g. 127.0.0.1:10358, :10358). It can be set to \"0\" to disable serving the health probe. Defaults to 0.0.0.0:10358.") o.ProfileOpts.AddFlags(fs) } + +// Complete ensures that options are valid and marshals them if necessary. +func (o *Options) Complete() error { + if len(o.HealthProbeBindAddress) == 0 { + o.HealthProbeBindAddress = net.JoinHostPort(o.BindAddress, strconv.Itoa(o.SecurePort)) + } + if len(o.MetricsBindAddress) == 0 { + o.MetricsBindAddress = net.JoinHostPort(o.BindAddress, strconv.Itoa(o.SecurePort)) + } + return nil +} diff --git a/cmd/descheduler/app/options/validation.go b/cmd/descheduler/app/options/validation.go index 81bf557e0d08..92e0c8dd5d3d 100644 --- a/cmd/descheduler/app/options/validation.go +++ b/cmd/descheduler/app/options/validation.go @@ -17,8 +17,6 @@ limitations under the License. package options import ( - "net" - "k8s.io/apimachinery/pkg/util/validation/field" ) @@ -27,14 +25,6 @@ func (o *Options) Validate() field.ErrorList { errs := field.ErrorList{} newPath := field.NewPath("Options") - if net.ParseIP(o.BindAddress) == nil { - errs = append(errs, field.Invalid(newPath.Child("BindAddress"), o.BindAddress, "not a valid textual representation of an IP address")) - } - - if o.SecurePort < 0 || o.SecurePort > 65535 { - errs = append(errs, field.Invalid(newPath.Child("SecurePort"), o.SecurePort, "must be a valid port between 0 and 65535 inclusive")) - } - if o.SchedulerEstimatorPort < 0 || o.SchedulerEstimatorPort > 65535 { errs = append(errs, field.Invalid(newPath.Child("SchedulerEstimatorPort"), o.SchedulerEstimatorPort, "must be a valid port between 0 and 65535 inclusive")) } diff --git a/cmd/descheduler/app/options/validation_test.go b/cmd/descheduler/app/options/validation_test.go index 28c5ec126c8c..076bf44b10d6 100644 --- a/cmd/descheduler/app/options/validation_test.go +++ b/cmd/descheduler/app/options/validation_test.go @@ -34,8 +34,6 @@ func New(modifyOptions ModifyOptions) Options { LeaderElection: componentbaseconfig.LeaderElectionConfiguration{ LeaderElect: false, }, - BindAddress: "127.0.0.1", - SecurePort: 9000, KubeAPIQPS: 40, KubeAPIBurst: 30, SchedulerEstimatorTimeout: metav1.Duration{Duration: 1 * time.Second}, @@ -78,18 +76,6 @@ func TestValidateKarmadaDescheduler(t *testing.T) { opt Options expectedErrs field.ErrorList }{ - "invalid BindAddress": { - opt: New(func(option *Options) { - option.BindAddress = "127.0.0.1:8080" - }), - expectedErrs: field.ErrorList{field.Invalid(newPath.Child("BindAddress"), "127.0.0.1:8080", "not a valid textual representation of an IP address")}, - }, - "invalid SecurePort": { - opt: New(func(option *Options) { - option.SecurePort = 90000 - }), - expectedErrs: field.ErrorList{field.Invalid(newPath.Child("SecurePort"), 90000, "must be a valid port between 0 and 65535 inclusive")}, - }, "invalid SchedulerEstimatorPort": { opt: New(func(option *Options) { option.SchedulerEstimatorPort = 90000 diff --git a/cmd/scheduler-estimator/app/options/options.go b/cmd/scheduler-estimator/app/options/options.go index 1d6ee5d26435..1293c655cc5d 100644 --- a/cmd/scheduler-estimator/app/options/options.go +++ b/cmd/scheduler-estimator/app/options/options.go @@ -17,6 +17,9 @@ limitations under the License. package options import ( + "net" + "strconv" + "github.com/spf13/pflag" "github.com/karmada-io/karmada/pkg/features" @@ -35,8 +38,10 @@ type Options struct { Master string ClusterName string // BindAddress is the IP address on which to listen for the --secure-port port. + // Deprecated: To specify the TCP address for serving health probes, use HealthProbeBindAddress instead. To specify the TCP address for serving prometheus metrics, use MetricsBindAddress instead. This will be removed in release 1.12+. BindAddress string // SecurePort is the port that the server serves at. + // Deprecated: To specify the TCP address for serving health probes, use HealthProbeBindAddress instead. To specify the TCP address for serving prometheus metrics, use MetricsBindAddress instead. This will be removed in release 1.12+. SecurePort int // ServerPort is the port that the server gRPC serves at. ServerPort int @@ -55,6 +60,16 @@ type Options struct { // Parallelism defines the amount of parallelism in algorithms for estimating. Must be greater than 0. Defaults to 16. Parallelism int ProfileOpts profileflag.Options + // MetricsBindAddress is the TCP address that the server should bind to + // for serving prometheus metrics. + // It can be set to "0" to disable the metrics serving. + // Defaults to ":10351". + MetricsBindAddress string + // HealthProbeBindAddress is the TCP address that the server should bind to + // for serving health probes + // It can be set to "0" to disable serving the health probe. + // Defaults to ":10351". + HealthProbeBindAddress string } // NewOptions builds an empty options. @@ -80,7 +95,24 @@ func (o *Options) AddFlags(fs *pflag.FlagSet) { fs.Float32Var(&o.ClusterAPIQPS, "kube-api-qps", 20.0, "QPS to use while talking with apiserver.") fs.IntVar(&o.ClusterAPIBurst, "kube-api-burst", 30, "Burst to use while talking with apiserver.") fs.IntVar(&o.Parallelism, "parallelism", o.Parallelism, "Parallelism defines the amount of parallelism in algorithms for estimating. Must be greater than 0. Defaults to 16.") + // nolint: errcheck + fs.MarkDeprecated("bind-address", "This flag is deprecated and will be removed in release 1.12+. Use --health-probe-bind-address and --metrics-bind-address instead. Note: In release 1.12+, these two addresses cannot be the same.") + // nolint: errcheck + fs.MarkDeprecated("secure-port", "This flag is deprecated and will be removed in release 1.12+. Use --health-probe-bind-address and --metrics-bind-address instead. Note: In release 1.12+, these two addresses cannot be the same.") + fs.StringVar(&o.MetricsBindAddress, "metrics-bind-address", "", "The TCP address that the server should bind to for serving prometheus metrics(e.g. 127.0.0.1:10351, :10351). It can be set to \"0\" to disable the metrics serving. Defaults to 0.0.0.0:10351.") + fs.StringVar(&o.HealthProbeBindAddress, "health-probe-bind-address", "", "The TCP address that the server should bind to for serving health probes(e.g. 127.0.0.1:10351, :10351). It can be set to \"0\" to disable serving the health probe. Defaults to 0.0.0.0:10351.") features.FeatureGate.AddFlag(fs) o.ProfileOpts.AddFlags(fs) } + +// Complete ensures that options are valid and marshals them if necessary. +func (o *Options) Complete() error { + if len(o.HealthProbeBindAddress) == 0 { + o.HealthProbeBindAddress = net.JoinHostPort(o.BindAddress, strconv.Itoa(o.SecurePort)) + } + if len(o.MetricsBindAddress) == 0 { + o.MetricsBindAddress = net.JoinHostPort(o.BindAddress, strconv.Itoa(o.SecurePort)) + } + return nil +} diff --git a/cmd/scheduler-estimator/app/options/validation.go b/cmd/scheduler-estimator/app/options/validation.go index 806a938b2438..69f5e66007b7 100644 --- a/cmd/scheduler-estimator/app/options/validation.go +++ b/cmd/scheduler-estimator/app/options/validation.go @@ -17,8 +17,6 @@ limitations under the License. package options import ( - "net" - "k8s.io/apimachinery/pkg/util/validation/field" ) @@ -31,17 +29,9 @@ func (o *Options) Validate() field.ErrorList { errs = append(errs, field.Invalid(newPath.Child("ClusterName"), o.ClusterName, "clusterName cannot be empty")) } - if net.ParseIP(o.BindAddress) == nil { - errs = append(errs, field.Invalid(newPath.Child("BindAddress"), o.BindAddress, "not a valid textual representation of an IP address")) - } - if o.ServerPort < 0 || o.ServerPort > 65535 { errs = append(errs, field.Invalid(newPath.Child("ServerPort"), o.ServerPort, "must be a valid port between 0 and 65535 inclusive")) } - if o.SecurePort < 0 || o.SecurePort > 65535 { - errs = append(errs, field.Invalid(newPath.Child("SecurePort"), o.SecurePort, "must be a valid port between 0 and 65535 inclusive")) - } - return errs } diff --git a/cmd/scheduler-estimator/app/options/validation_test.go b/cmd/scheduler-estimator/app/options/validation_test.go index c9cf0845d16b..b4cc15747d0d 100644 --- a/cmd/scheduler-estimator/app/options/validation_test.go +++ b/cmd/scheduler-estimator/app/options/validation_test.go @@ -29,8 +29,6 @@ type ModifyOptions func(option *Options) func New(modifyOptions ModifyOptions) Options { option := Options{ ClusterName: "testCluster", - BindAddress: "0.0.0.0", - SecurePort: 10100, ServerPort: 8088, } @@ -61,18 +59,6 @@ func TestValidateKarmadaSchedulerEstimator(t *testing.T) { }), expectedErrs: field.ErrorList{field.Invalid(newPath.Child("ClusterName"), "", "clusterName cannot be empty")}, }, - "invalid BindAddress": { - opt: New(func(option *Options) { - option.BindAddress = "127.0.0.1:8082" - }), - expectedErrs: field.ErrorList{field.Invalid(newPath.Child("BindAddress"), "127.0.0.1:8082", "not a valid textual representation of an IP address")}, - }, - "invalid SecurePort": { - opt: New(func(option *Options) { - option.SecurePort = 908188 - }), - expectedErrs: field.ErrorList{field.Invalid(newPath.Child("SecurePort"), 908188, "must be a valid port between 0 and 65535 inclusive")}, - }, "invalid ServerPort": { opt: New(func(option *Options) { option.ServerPort = 80888 diff --git a/cmd/scheduler-estimator/app/scheduler-estimator.go b/cmd/scheduler-estimator/app/scheduler-estimator.go index 4697a5130152..7614e2753f6b 100644 --- a/cmd/scheduler-estimator/app/scheduler-estimator.go +++ b/cmd/scheduler-estimator/app/scheduler-estimator.go @@ -19,10 +19,8 @@ package app import ( "context" "fmt" - "net" "net/http" "os" - "strconv" "time" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -83,6 +81,11 @@ func NewSchedulerEstimatorCommand(ctx context.Context) *cobra.Command { Long: `The karmada-scheduler-estimator runs an accurate scheduler estimator of a cluster. It provides the scheduler with more accurate cluster resource information.`, RunE: func(_ *cobra.Command, _ []string) error { + // complete options + if err := opts.Complete(); err != nil { + return err + } + // validate options if errs := opts.Validate(); len(errs) != 0 { return errs.ToAggregate() @@ -114,7 +117,7 @@ provides the scheduler with more accurate cluster resource information.`, func run(ctx context.Context, opts *options.Options) error { klog.Infof("karmada-scheduler-estimator version: %s", version.Get()) - go serveHealthzAndMetrics(net.JoinHostPort(opts.BindAddress, strconv.Itoa(opts.SecurePort))) + serveHealthzAndMetrics(opts.HealthProbeBindAddress, opts.MetricsBindAddress) profileflag.ListenAndServe(opts.ProfileOpts) @@ -143,26 +146,64 @@ func run(ctx context.Context, opts *options.Options) error { return nil } -func serveHealthzAndMetrics(address string) { +func serveHealthzAndMetrics(healthProbeBindAddress, metricsBindAddress string) { + if healthProbeBindAddress == metricsBindAddress { + if healthProbeBindAddress != "0" { + go serveCombined(healthProbeBindAddress) + } + } else { + if healthProbeBindAddress != "0" { + go serveHealthz(healthProbeBindAddress) + } + if metricsBindAddress != "0" { + go serveMetrics(metricsBindAddress) + } + } +} + +func serveCombined(address string) { mux := http.NewServeMux() - mux.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte("ok")) - }) + mux.HandleFunc("/healthz", healthzHandler) + mux.Handle("/metrics", metricsHandler()) + + serveHTTP(address, mux, "healthz and metrics") +} + +func serveHealthz(address string) { + mux := http.NewServeMux() + mux.HandleFunc("/healthz", healthzHandler) + serveHTTP(address, mux, "healthz") +} + +func serveMetrics(address string) { + mux := http.NewServeMux() + mux.Handle("/metrics", metricsHandler()) + serveHTTP(address, mux, "metrics") +} - mux.Handle("/metrics", promhttp.HandlerFor(ctrlmetrics.Registry, promhttp.HandlerOpts{ +func healthzHandler(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte("ok")) +} + +func metricsHandler() http.Handler { + return promhttp.HandlerFor(ctrlmetrics.Registry, promhttp.HandlerOpts{ ErrorHandling: promhttp.HTTPErrorOnError, - })) + }) +} - httpServer := http.Server{ +func serveHTTP(address string, handler http.Handler, name string) { + httpServer := &http.Server{ Addr: address, - Handler: mux, + Handler: handler, ReadHeaderTimeout: ReadHeaderTimeout, WriteTimeout: WriteTimeout, ReadTimeout: ReadTimeout, } + + klog.Infof("Starting %s server on %s", name, address) if err := httpServer.ListenAndServe(); err != nil { - klog.Errorf("Failed to serve healthz and metrics: %v", err) + klog.Errorf("Failed to serve %s on %s: %v", name, address, err) os.Exit(1) } } diff --git a/cmd/scheduler/app/options/options.go b/cmd/scheduler/app/options/options.go index ac994775253c..1923dd346bb2 100644 --- a/cmd/scheduler/app/options/options.go +++ b/cmd/scheduler/app/options/options.go @@ -52,10 +52,24 @@ type Options struct { KubeConfig string Master string // BindAddress is the IP address on which to listen for the --secure-port port. + // Deprecated: To specify the TCP address for serving health probes, use HealthProbeBindAddress instead. To specify the TCP address for serving prometheus metrics, use MetricsBindAddress instead. This will be removed in release 1.12+. BindAddress string // SecurePort is the port that the server serves at. + // Deprecated: To specify the TCP address for serving health probes, use HealthProbeBindAddress instead. To specify the TCP address for serving prometheus metrics, use MetricsBindAddress instead. This will be removed in release 1.12+. SecurePort int + // MetricsBindAddress is the TCP address that the controller should bind to + // for serving prometheus metrics. + // It can be set to "0" to disable the metrics serving. + // Defaults to ":10351". + MetricsBindAddress string + + // HealthProbeBindAddress is the TCP address that the controller should bind to + // for serving health probes + // It can be set to "0" or "" to disable serving the health probe. + // Defaults to ":10351". + HealthProbeBindAddress string + // KubeAPIQPS is the QPS to use while talking with karmada-apiserver. KubeAPIQPS float32 // KubeAPIBurst is the burst to allow while talking with karmada-apiserver. @@ -139,6 +153,12 @@ func (o *Options) AddFlags(fs *pflag.FlagSet) { fs.StringVar(&o.Master, "master", o.Master, "The address of the Kubernetes API server. Overrides any value in KubeConfig. Only required if out-of-cluster.") fs.StringVar(&o.BindAddress, "bind-address", defaultBindAddress, "The IP address on which to listen for the --secure-port port.") fs.IntVar(&o.SecurePort, "secure-port", defaultPort, "The secure port on which to serve HTTPS.") + // nolint: errcheck + fs.MarkDeprecated("bind-address", "This flag is deprecated and will be removed in release 1.12+. Use --health-probe-bind-address and --metrics-bind-address instead. Note: In release 1.12+, these two addresses cannot be the same.") + // nolint: errcheck + fs.MarkDeprecated("secure-port", "This flag is deprecated and will be removed in release 1.12+. Use --health-probe-bind-address and --metrics-bind-address instead. Note: In release 1.12+, these two addresses cannot be the same.") + fs.StringVar(&o.MetricsBindAddress, "metrics-bind-address", "", "The TCP address that the server should bind to for serving prometheus metrics(e.g. 127.0.0.1:9000, :10351). It can be set to \"0\" to disable the metrics serving. Defaults to 0.0.0.0:10351.") + fs.StringVar(&o.HealthProbeBindAddress, "health-probe-bind-address", "", "The TCP address that the server should bind to for serving health probes(e.g. 127.0.0.1:9000, :10351). It can be set to \"0\" to disable serving the health probe. Defaults to 0.0.0.0:10351.") fs.Float32Var(&o.KubeAPIQPS, "kube-api-qps", 40.0, "QPS to use while talking with karmada-apiserver.") fs.IntVar(&o.KubeAPIBurst, "kube-api-burst", 60, "Burst to use while talking with karmada-apiserver.") fs.BoolVar(&o.EnableSchedulerEstimator, "enable-scheduler-estimator", false, "Enable calling cluster scheduler estimator for adjusting replicas.") diff --git a/cmd/scheduler/app/options/validation.go b/cmd/scheduler/app/options/validation.go index 7612ff2e83ce..793ac542eb99 100644 --- a/cmd/scheduler/app/options/validation.go +++ b/cmd/scheduler/app/options/validation.go @@ -18,27 +18,30 @@ package options import ( "net" + "strconv" "k8s.io/apimachinery/pkg/util/validation/field" ) +// Complete ensures that options are valid and marshals them if necessary. +func (o *Options) Complete() error { + if len(o.HealthProbeBindAddress) == 0 { + o.HealthProbeBindAddress = net.JoinHostPort(o.BindAddress, strconv.Itoa(o.SecurePort)) + } + if len(o.MetricsBindAddress) == 0 { + o.MetricsBindAddress = net.JoinHostPort(o.BindAddress, strconv.Itoa(o.SecurePort)) + } + return nil +} + // Validate checks Options and return a slice of found errs. func (o *Options) Validate() field.ErrorList { errs := field.ErrorList{} newPath := field.NewPath("Options") - if net.ParseIP(o.BindAddress) == nil { - errs = append(errs, field.Invalid(newPath.Child("BindAddress"), o.BindAddress, "not a valid textual representation of an IP address")) - } - - if o.SecurePort < 0 || o.SecurePort > 65535 { - errs = append(errs, field.Invalid(newPath.Child("SecurePort"), o.SecurePort, "must be a valid port between 0 and 65535 inclusive")) - } - if o.SchedulerEstimatorPort < 0 || o.SchedulerEstimatorPort > 65535 { errs = append(errs, field.Invalid(newPath.Child("SchedulerEstimatorPort"), o.SchedulerEstimatorPort, "must be a valid port between 0 and 65535 inclusive")) } - if o.SchedulerEstimatorTimeout.Duration < 0 { errs = append(errs, field.Invalid(newPath.Child("SchedulerEstimatorTimeout"), o.SchedulerEstimatorTimeout, "must be greater than or equal to 0")) } diff --git a/cmd/scheduler/app/options/validation_test.go b/cmd/scheduler/app/options/validation_test.go index 42940a6e6a03..ee451959dc55 100644 --- a/cmd/scheduler/app/options/validation_test.go +++ b/cmd/scheduler/app/options/validation_test.go @@ -62,8 +62,6 @@ func TestValidateKarmadaSchedulerConfiguration(t *testing.T) { LeaderElection: componentbaseconfig.LeaderElectionConfiguration{ LeaderElect: false, }, - BindAddress: "127.0.0.1", - SecurePort: 9000, KubeAPIQPS: 40, KubeAPIBurst: 30, SchedulerName: "default-scheduler", @@ -81,18 +79,6 @@ func TestValidateKarmadaSchedulerConfiguration(t *testing.T) { opt Options expectedErrs field.ErrorList }{ - "invalid BindAddress": { - opt: New(func(option *Options) { - option.BindAddress = "127.0.0.1:8080" - }), - expectedErrs: field.ErrorList{field.Invalid(newPath.Child("BindAddress"), "127.0.0.1:8080", "not a valid textual representation of an IP address")}, - }, - "invalid SecurePort": { - opt: New(func(option *Options) { - option.SecurePort = 90000 - }), - expectedErrs: field.ErrorList{field.Invalid(newPath.Child("SecurePort"), 90000, "must be a valid port between 0 and 65535 inclusive")}, - }, "invalid SchedulerEstimatorPort": { opt: New(func(option *Options) { option.SchedulerEstimatorPort = 90000 diff --git a/cmd/scheduler/app/scheduler.go b/cmd/scheduler/app/scheduler.go index 9d4bad259136..c7d8899294a5 100644 --- a/cmd/scheduler/app/scheduler.go +++ b/cmd/scheduler/app/scheduler.go @@ -19,10 +19,8 @@ package app import ( "context" "fmt" - "net" "net/http" "os" - "strconv" "time" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -100,6 +98,10 @@ The scheduler determines which clusters are valid placements for each resource i constraints and available resources. The scheduler then ranks each valid cluster and binds the resource to the most suitable cluster.`, RunE: func(_ *cobra.Command, _ []string) error { + // complete options + if err := opts.Complete(); err != nil { + return err + } // validate options if errs := opts.Validate(); len(errs) != 0 { return errs.ToAggregate() @@ -139,7 +141,7 @@ the most suitable cluster.`, func run(opts *options.Options, stopChan <-chan struct{}, registryOptions ...Option) error { klog.Infof("karmada-scheduler version: %s", version.Get()) - go serveHealthzAndMetrics(net.JoinHostPort(opts.BindAddress, strconv.Itoa(opts.SecurePort))) + serveHealthzAndMetrics(opts.HealthProbeBindAddress, opts.MetricsBindAddress) profileflag.ListenAndServe(opts.ProfileOpts) @@ -225,26 +227,64 @@ func run(opts *options.Options, stopChan <-chan struct{}, registryOptions ...Opt return nil } -func serveHealthzAndMetrics(address string) { +func serveHealthzAndMetrics(healthProbeBindAddress, metricsBindAddress string) { + if healthProbeBindAddress == metricsBindAddress { + if healthProbeBindAddress != "0" { + go serveCombined(healthProbeBindAddress) + } + } else { + if healthProbeBindAddress != "0" { + go serveHealthz(healthProbeBindAddress) + } + if metricsBindAddress != "0" { + go serveMetrics(metricsBindAddress) + } + } +} + +func serveCombined(address string) { mux := http.NewServeMux() - mux.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte("ok")) - }) + mux.HandleFunc("/healthz", healthzHandler) + mux.Handle("/metrics", metricsHandler()) + + serveHTTP(address, mux, "healthz and metrics") +} - mux.Handle("/metrics", promhttp.HandlerFor(ctrlmetrics.Registry, promhttp.HandlerOpts{ +func serveHealthz(address string) { + mux := http.NewServeMux() + mux.HandleFunc("/healthz", healthzHandler) + serveHTTP(address, mux, "healthz") +} + +func serveMetrics(address string) { + mux := http.NewServeMux() + mux.Handle("/metrics", metricsHandler()) + serveHTTP(address, mux, "metrics") +} + +func healthzHandler(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte("ok")) +} + +func metricsHandler() http.Handler { + return promhttp.HandlerFor(ctrlmetrics.Registry, promhttp.HandlerOpts{ ErrorHandling: promhttp.HTTPErrorOnError, - })) + }) +} - httpServer := http.Server{ +func serveHTTP(address string, handler http.Handler, name string) { + httpServer := &http.Server{ Addr: address, - Handler: mux, + Handler: handler, ReadHeaderTimeout: ReadHeaderTimeout, WriteTimeout: WriteTimeout, ReadTimeout: ReadTimeout, } + + klog.Infof("Starting %s server on %s", name, address) if err := httpServer.ListenAndServe(); err != nil { - klog.Errorf("Failed to serve healthz and metrics: %v", err) + klog.Errorf("Failed to serve %s on %s: %v", name, address, err) os.Exit(1) } } diff --git a/docs/CHANGELOG/CHANGELOG-1.10.md b/docs/CHANGELOG/CHANGELOG-1.10.md index f6a0ae443fd6..035a0aef0dae 100644 --- a/docs/CHANGELOG/CHANGELOG-1.10.md +++ b/docs/CHANGELOG/CHANGELOG-1.10.md @@ -2,24 +2,30 @@ **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* -- [v1.10.3](#v1103) - - [Downloads for v1.10.3](#downloads-for-v1103) - - [Changelog since v1.10.2](#changelog-since-v1102) +- [v1.10.4](#v1104) + - [Downloads for v1.10.4](#downloads-for-v1104) + - [Changelog since v1.10.3](#changelog-since-v1103) - [Changes by Kind](#changes-by-kind) - [Bug Fixes](#bug-fixes) - [Others](#others) -- [v1.10.2](#v1102) - - [Downloads for v1.10.2](#downloads-for-v1102) - - [Changelog since v1.10.1](#changelog-since-v1101) +- [v1.10.3](#v1103) + - [Downloads for v1.10.3](#downloads-for-v1103) + - [Changelog since v1.10.2](#changelog-since-v1102) - [Changes by Kind](#changes-by-kind-1) - [Bug Fixes](#bug-fixes-1) - [Others](#others-1) -- [v1.10.1](#v1101) - - [Downloads for v1.10.1](#downloads-for-v1101) - - [Changelog since v1.10.0](#changelog-since-v1100) +- [v1.10.2](#v1102) + - [Downloads for v1.10.2](#downloads-for-v1102) + - [Changelog since v1.10.1](#changelog-since-v1101) - [Changes by Kind](#changes-by-kind-2) - [Bug Fixes](#bug-fixes-2) - [Others](#others-2) +- [v1.10.1](#v1101) + - [Downloads for v1.10.1](#downloads-for-v1101) + - [Changelog since v1.10.0](#changelog-since-v1100) + - [Changes by Kind](#changes-by-kind-3) + - [Bug Fixes](#bug-fixes-3) + - [Others](#others-3) - [v1.10.0](#v1100) - [Downloads for v1.10.0](#downloads-for-v1100) - [What's New](#whats-new) @@ -28,7 +34,7 @@ - [Other Notable Changes](#other-notable-changes) - [API Changes](#api-changes) - [Deprecation](#deprecation) - - [Bug Fixes](#bug-fixes-3) + - [Bug Fixes](#bug-fixes-4) - [Security](#security) - [Features & Enhancements](#features--enhancements) - [Other](#other) @@ -39,6 +45,20 @@ +# v1.10.4 +## Downloads for v1.10.4 + +Download v1.10.4 in the [v1.10.4 release page](https://github.com/karmada-io/karmada/releases/tag/v1.10.4). + +## Changelog since v1.10.3 +### Changes by Kind +#### Bug Fixes +- `Helm`: fix wrong `ClusterResourceBinding` scope in `MutatingWebhookConfiguration`. ([#5262](https://github.com/karmada-io/karmada/pull/5262), @XiShanYongYe-Chang) + +#### Others +- The base image `alpine` now has been promoted from `alpine:3.20.1` to `alpine:3.20.2`. ([#5268](https://github.com/karmada-io/karmada/pull/5268)) +- Bump golang version to `v1.21.13` ([#5371](https://github.com/karmada-io/karmada/pull/5371), @zhzhuang-zju) + # v1.10.3 ## Downloads for v1.10.3 diff --git a/docs/CHANGELOG/CHANGELOG-1.8.md b/docs/CHANGELOG/CHANGELOG-1.8.md index 683d289f121b..be08dafe64d9 100644 --- a/docs/CHANGELOG/CHANGELOG-1.8.md +++ b/docs/CHANGELOG/CHANGELOG-1.8.md @@ -2,42 +2,48 @@ **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* -- [v1.8.6](#v186) - - [Downloads for v1.8.6](#downloads-for-v186) - - [Changelog since v1.8.5](#changelog-since-v185) +- [v1.8.7](#v187) + - [Downloads for v1.8.7](#downloads-for-v187) + - [Changelog since v1.8.6](#changelog-since-v186) - [Changes by Kind](#changes-by-kind) - [Bug Fixes](#bug-fixes) - [Others](#others) -- [v1.8.5](#v185) - - [Downloads for v1.8.5](#downloads-for-v185) - - [Changelog since v1.8.4](#changelog-since-v184) +- [v1.8.6](#v186) + - [Downloads for v1.8.6](#downloads-for-v186) + - [Changelog since v1.8.5](#changelog-since-v185) - [Changes by Kind](#changes-by-kind-1) - [Bug Fixes](#bug-fixes-1) - [Others](#others-1) -- [v1.8.4](#v184) - - [Downloads for v1.8.4](#downloads-for-v184) - - [Changelog since v1.8.3](#changelog-since-v183) +- [v1.8.5](#v185) + - [Downloads for v1.8.5](#downloads-for-v185) + - [Changelog since v1.8.4](#changelog-since-v184) - [Changes by Kind](#changes-by-kind-2) - [Bug Fixes](#bug-fixes-2) - [Others](#others-2) -- [v1.8.3](#v183) - - [Downloads for v1.8.3](#downloads-for-v183) - - [Changelog since v1.8.2](#changelog-since-v182) +- [v1.8.4](#v184) + - [Downloads for v1.8.4](#downloads-for-v184) + - [Changelog since v1.8.3](#changelog-since-v183) - [Changes by Kind](#changes-by-kind-3) - [Bug Fixes](#bug-fixes-3) - [Others](#others-3) -- [v1.8.2](#v182) - - [Downloads for v1.8.2](#downloads-for-v182) - - [Changelog since v1.8.1](#changelog-since-v181) +- [v1.8.3](#v183) + - [Downloads for v1.8.3](#downloads-for-v183) + - [Changelog since v1.8.2](#changelog-since-v182) - [Changes by Kind](#changes-by-kind-4) - [Bug Fixes](#bug-fixes-4) - [Others](#others-4) -- [v1.8.1](#v181) - - [Downloads for v1.8.1](#downloads-for-v181) - - [Changelog since v1.8.0](#changelog-since-v180) +- [v1.8.2](#v182) + - [Downloads for v1.8.2](#downloads-for-v182) + - [Changelog since v1.8.1](#changelog-since-v181) - [Changes by Kind](#changes-by-kind-5) - [Bug Fixes](#bug-fixes-5) - [Others](#others-5) +- [v1.8.1](#v181) + - [Downloads for v1.8.1](#downloads-for-v181) + - [Changelog since v1.8.0](#changelog-since-v180) + - [Changes by Kind](#changes-by-kind-6) + - [Bug Fixes](#bug-fixes-6) + - [Others](#others-6) - [v1.8.0](#v180) - [Downloads for v1.8.0](#downloads-for-v180) - [What's New](#whats-new) @@ -48,7 +54,7 @@ - [Other Notable Changes](#other-notable-changes) - [API Changes](#api-changes) - [Deprecation](#deprecation) - - [Bug Fixes](#bug-fixes-6) + - [Bug Fixes](#bug-fixes-7) - [Security](#security) - [Features & Enhancements](#features--enhancements) - [Other](#other) @@ -59,6 +65,19 @@ +# v1.8.7 +## Downloads for v1.8.7 + +Download v1.8.7 in the [v1.8.7 release page](https://github.com/karmada-io/karmada/releases/tag/v1.8.7). + +## Changelog since v1.8.6 +### Changes by Kind +#### Bug Fixes +None. + +#### Others +- The base image `alpine` now has been promoted from `alpine:3.20.1` to `alpine:3.20.2`. ([#5270](https://github.com/karmada-io/karmada/pull/5270)) + # v1.8.6 ## Downloads for v1.8.6 diff --git a/docs/CHANGELOG/CHANGELOG-1.9.md b/docs/CHANGELOG/CHANGELOG-1.9.md index c0e71d012682..998f12b3a027 100644 --- a/docs/CHANGELOG/CHANGELOG-1.9.md +++ b/docs/CHANGELOG/CHANGELOG-1.9.md @@ -2,36 +2,42 @@ **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* -- [v1.9.5](#v195) - - [Downloads for v1.9.5](#downloads-for-v195) - - [Changelog since v1.9.4](#changelog-since-v194) +- [v1.9.6](#v196) + - [Downloads for v1.9.6](#downloads-for-v196) + - [Changelog since v1.9.5](#changelog-since-v195) - [Changes by Kind](#changes-by-kind) - [Bug Fixes](#bug-fixes) - [Others](#others) -- [v1.9.4](#v194) - - [Downloads for v1.9.4](#downloads-for-v194) - - [Changelog since v1.9.3](#changelog-since-v193) +- [v1.9.5](#v195) + - [Downloads for v1.9.5](#downloads-for-v195) + - [Changelog since v1.9.4](#changelog-since-v194) - [Changes by Kind](#changes-by-kind-1) - [Bug Fixes](#bug-fixes-1) - [Others](#others-1) -- [v1.9.3](#v193) - - [Downloads for v1.9.3](#downloads-for-v193) - - [Changelog since v1.9.2](#changelog-since-v192) +- [v1.9.4](#v194) + - [Downloads for v1.9.4](#downloads-for-v194) + - [Changelog since v1.9.3](#changelog-since-v193) - [Changes by Kind](#changes-by-kind-2) - [Bug Fixes](#bug-fixes-2) - [Others](#others-2) -- [v1.9.2](#v192) - - [Downloads for v1.9.2](#downloads-for-v192) - - [Changelog since v1.9.1](#changelog-since-v191) +- [v1.9.3](#v193) + - [Downloads for v1.9.3](#downloads-for-v193) + - [Changelog since v1.9.2](#changelog-since-v192) - [Changes by Kind](#changes-by-kind-3) - [Bug Fixes](#bug-fixes-3) - [Others](#others-3) -- [v1.9.1](#v191) - - [Downloads for v1.9.1](#downloads-for-v191) - - [Changelog since v1.9.0](#changelog-since-v190) +- [v1.9.2](#v192) + - [Downloads for v1.9.2](#downloads-for-v192) + - [Changelog since v1.9.1](#changelog-since-v191) - [Changes by Kind](#changes-by-kind-4) - [Bug Fixes](#bug-fixes-4) - [Others](#others-4) +- [v1.9.1](#v191) + - [Downloads for v1.9.1](#downloads-for-v191) + - [Changelog since v1.9.0](#changelog-since-v190) + - [Changes by Kind](#changes-by-kind-5) + - [Bug Fixes](#bug-fixes-5) + - [Others](#others-5) - [v1.9.0](#v190) - [Downloads for v1.9.0](#downloads-for-v190) - [What's New](#whats-new) @@ -41,7 +47,7 @@ - [Other Notable Changes](#other-notable-changes) - [API Changes](#api-changes) - [Deprecation](#deprecation) - - [Bug Fixes](#bug-fixes-5) + - [Bug Fixes](#bug-fixes-6) - [Security](#security) - [Features & Enhancements](#features--enhancements) - [Other](#other) @@ -52,6 +58,20 @@ +# v1.9.6 +## Downloads for v1.9.6 + +Download v1.9.6 in the [v1.9.6 release page](https://github.com/karmada-io/karmada/releases/tag/v1.9.6). + +## Changelog since v1.9.5 +### Changes by Kind +#### Bug Fixes +None. + +#### Others +- The base image `alpine` now has been promoted from `alpine:3.20.1` to `alpine:3.20.2`. ([#5269](https://github.com/karmada-io/karmada/pull/5269)) +- Bump golang version to `v1.20.14`. ([#5374](https://github.com/karmada-io/karmada/pull/5374) @zhzhuang-zju) + # v1.9.5 ## Downloads for v1.9.5 diff --git a/docs/proposals/cleanup-propagated-resources/README.md b/docs/proposals/cleanup-propagated-resources/README.md index 36dec6990c87..cadc0c5fa613 100644 --- a/docs/proposals/cleanup-propagated-resources/README.md +++ b/docs/proposals/cleanup-propagated-resources/README.md @@ -75,7 +75,7 @@ In kubefed's propose, the author suggest add a `BestEffort` strategy, reviewers #### Needless Strategy -Not need cleanup propagated resources when unjoining cluster. `Karmada` should use this strategy as default value, condsider the business risk. +Not need cleanup propagated resources when unjoining cluster. `Karmada` should use this strategy as default value, consider the business risk. #### Required Strategy diff --git a/docs/proposals/dispatch-suspension/README.md b/docs/proposals/dispatch-suspension/README.md index 4664ee170247..2a984c181e73 100644 --- a/docs/proposals/dispatch-suspension/README.md +++ b/docs/proposals/dispatch-suspension/README.md @@ -153,7 +153,7 @@ type WorkSpec struct { } ``` -A new ConditionType called `SuspendDispatching` is introduced to describe the distribution suspension status of the Work resource. Meanwhile, the system will also report events to record the suspension of resource distribution. +A new ConditionType called `Dispatching` is introduced to describe the distribution suspension status of the Work resource. Meanwhile, the system will also report events to record the suspension of resource distribution. ### User usage example @@ -195,7 +195,7 @@ spec: status: conditions: - lastTransitionTime: "2024-07-01T08:33:28Z" - message: resource distribution is in a pause state. + message: Work dispatching is in a suspended state. reason: SuspendDispatching status: "True" type: Dispatching @@ -256,6 +256,12 @@ If, after synchronizing the new version of the resource to the member1 cluster, Q&A: How to remove the annotation `propagation.karmada.io/instruction` from Work? It can be carried by the `Dispatching` field in the Work. +### Corner Case Consideration + +1. Resource dispatching suspension does not block resource deletion. + +When a user specifies through PropagationPolicy that a resource is in a dispatching suspension, and then performs a deletion operation with the intention of removing the resource, the resource will be deleted normally without blocking the deletion, thus preventing leftover resources in the member clusters. + ### Test Plan #### UT diff --git a/docs/proposals/karmadactl/enhance_karmadactl_maintenance_experience.md b/docs/proposals/karmadactl/enhance_karmadactl_maintenance_experience.md new file mode 100644 index 000000000000..91d99926411c --- /dev/null +++ b/docs/proposals/karmadactl/enhance_karmadactl_maintenance_experience.md @@ -0,0 +1,325 @@ +--- +title: Enhance karmadactl operation and maintenance experience +authors: +- "@hulizhe" +- "@zhzhuang-zju" +reviewers: +- "@RainbowMango" + +approvers: +- "@RainbowMango" + +creation-date: 2024-07-22 +--- + +# Enhance karmadactl operation and maintenance experience + +## Summary + +Karmadactl is a CLI (Command Line Interface) tool entirely dedicated to Karmada's multi-cluster scenarios. Currently, karmadactl implements commands such as `get` and `describe` for partial applications in a multi-cluster context. For instance, `karmadactl get` is used to display one or many resources in member clusters, and `karmadactl describe` shows detailed information about a specific resource or group of resources within a member cluster. However, these commands are exclusively focused on resources within member clusters, lacking capabilities to perform CRUD (Create, Read, Update, Delete) operations on Karmada control plane resources. + +Furthermore, some kubectl commands have not been adapted to multi-cluster scenarios, such as `create`, `label`, and `edit`. This omission prevents karmadactl from functioning independently of kubectl, necessitating the use of both tools to manage resources comprehensively across multi-cluster environments managed by Karmada. + +Therefore, this proposal plans to enhance the functionality of karmadactl in multi-cluster scenarios, aiming to further improve the operational experience of using karmadactl. The main enhancements include: + +- Enhancing the capabilities of `karmadactl get`, `karmadactl describe`, and similar commands to parse and interpret Karmada control plane resources. +- Completing the implementation of features for commands such as `karmadactl create`, `karmadactl label`, and `karmadactl edit`. + +## Motivation + + +Currently, due to incomplete capabilities of karmadactl in multi-cluster scenarios, in actual operations and maintenance, karmadactl is often used in conjunction with kubectl. This leads to issues such as switching between karmadactl and kubectl commands under different usage scenarios, and frequent context switching required by kubectl: + +1. Suppose Karmada has a deployment named `foo` that has been dispatched to member clusters member1 and member2. +2. If you wish to inspect the `foo` deployment under the Karmada control plane and in each member cluster, +3. Firstly, you would need to use the kubectl command `kubectl get --kubeconfig $HOME/.kube/karmada.config --context karmada-apiserver` to display the `foo` deployment in Karmada control plane. +4. Next, you would switch to the karmadactl command `karmadactl get` to check the `foo` deployment in the member clusters. + +This disjointed process also creates a fragmented experience for the user, as described in the [issue](https://github.com/karmada-io/karmada/issues/5205). + +If karmadactl were capable of viewing resources from Karmada control plane, then the above requirements could be fulfilled simply by using the command `karmadactl get`. + +### Goals + +- Providing the ability for karmadactl to perform Create, Read, Update, and Delete (CRUD) operations on Karmada control plane resources. +- Bridging the gap by incorporating functionalities into karmadactl that have yet to be inherited from kubectl, notably including `karmadactl create`, `karmadactl delete`, `karmadactl label`, `karmadactl edit`, `karamdactl patch`, `karmadactl annotate`, `karmadctl attach`, `karmadactl api-resources`, `karmadactl explain`, `karmadactl top node`. + +### Non-Goals + +- Optimization of command output for improved display and readability. +- Replacing kubectl with karmadactl in the [karmada repository](https://github.com/karmada-io/karmada). +- Mining the multi-cluster specific capabilities with karmadactl. + +## Proposal + +The operation scope for karmadactl commands, based on their specific functionalities, can be categorized as follows: + +- Karmada Control Plane +- Karmada Control Plane or a Single Member Cluster +- Karmada Control Plane and Multiple Member Clusters + +**To unify the representation of different commands with varying scopes of usage, the following conventions are agreed upon**: + +- Default Scope: The default scope for commands is the Karmada Control Plane. +- Specifying Member Clusters: If a command is intended to affect member clusters, the user could specify the target member cluster(s) via a flag. This allows the command to be directed towards a particular member cluster or a list of member clusters. + +These guidelines ensure that there is a clear and consistent way to differentiate between commands that operate at the level of the Karamda control plane versus those that target individual or multiple member clusters. This helps prevent ambiguity and ensures that users can accurately predict the behavior of each command based on its scope and the flags provided, facilitating more efficient and error-free operations within the Karmada multi-cluster environment. + +Currently, the flag set of karmadactl is only sufficient for viewing or modifying resources within member clusters. Therefore, the first step is to design and modify the flag set of karmadactl, ensuring it can accommodate the various scenarios outlined previously. + +Secondly, karmadactl commands can be classified based on whether they inherit from kubectl: + +- Inherited from kubectl: These commands represent extensions of single-cluster capabilities to multi-cluster scenarios. +- Multi-cluster-specific abilities: These are commands unique to karmadactl, designed to address the specific requirements and complexities inherent to managing resources across multiple clusters. + +To facilitate a smooth transition for users moving from kubectl to karmadactl, efforts should be made to ensure that the user experience for identical commands remains as consistent as possible between the two tools. This includes maintaining similar command structures, output formatting, and behavior wherever feasible, while also leveraging the extended capabilities of karmadactl to manage resources effectively in a multi-cluster environment. + +Given that directly modifying resources in member clusters could potentially lead to conflicts between Karmada control plane and the member clusters, karmadactl should not offer the capability to directly create, delete, or update resources in member clusters. + +### User Stories (Optional) + + + +#### Story 1 + +As an operations personnel, I hope to be able to view resources from the current Karmada control plane as well as member clusters without context switching or changing between CLIs. + +**Scenario**: + +1. Given that both the Karmada control plane and member clusters have a deployment named `foo`. +2. When I use the command `karmadactl get`, it will display deployment `foo` from the Karmada control plane as well as from all member clusters, providing a consolidated view of the resource across the multi-cluster environment. + +### Notes/Constraints/Caveats (Optional) + + + +### Risks and Mitigations + + + +## Design Details + + + +### CLI flags changes + +This proposal proposes new flags `--operation-scope` in karmadactl flag set. + +| name | type | shorthand | default | usage | +|-----------------|--------|-----------|---------|------------------------------------------------| +| operation-scope | string | / | karmada | Used to control the operation scope of command | + +The value of `operation-scope` is an enumeration, including `karmada`, `members`, and `all`. With the flag: + +- The default operation scope for the command is Karmada control plane, and resources in member clusters will be ignored. +- If the desired operation scope for the command is the member clusters, we can set the flag `--operation-scope` to `members`, in which case resources in the Karmada control plane will be ignored. +- If the desired operation scope for the command includes both the karmada control plane and member clusters, we can set the flag `--operation-scope` to `all`. + +NOTE: Not all commands include `all` as a value for the `operation-scope` flag; some commands, such as `describe`, can only operate on a single cluster, so `all` will not be included as a value for the `operation-scope` flag in these cases. + +#### Interacts with other flags + +The `clusters/cluster` flag only takes effect when the `operation-scope` flag is set to `members` or `all`. + +### Modification of Existing Commands + +#### karmadactl get + +- description: Display one or many resources in Karmada control plane and member clusters. +- operation scope: Karmada control plane and member clusters. +- scope-related flag set: + +| name | type | optional values | default | usage | +|-----------------|----------|-----------------------|---------|------------------------------------------------| +| clusters | []string | / | none | Used to specify target member clusters | +| operation-scope | string | karmada; members; all | karmada | Used to control the operation scope of command | + +- performance: +
    +
  1. Use the command `karmadactl get` or `karmadactl get --operation-scope karmada` to display resources in the karmada control plane.
  2. +
  3. Use the command `karmadactl get --operation-scope members` to display resources in all member clusters.
  4. +
  5. Use the command `karmadactl get --operation-scope members --clusters member1,member2` to display resources in member1 cluster and member2 cluster.
  6. +
  7. Use the command `karmadactl get --operation-scope all` to display resources in Karmada control plane and all member clusters.
  8. +
  9. Use the command `karmadactl get --operation-scope all --clusters member1,member2` to display resources in Karmada control plane, member1 cluster and member2 cluster.
  10. +
+ +#### karmadactl describe + +- description: Show details of a specific resource or group of resources in Karmada control plane or a member cluster. +- usage scope: Karmada Control Plane or a Single Member Cluster. +- scope-related flag set: + +| name | type | optional values | default | usage | +|-----------------|--------|------------------|---------|------------------------------------------------| +| cluster | string | / | none | Used to specify target member cluster | +| operation-scope | string | karmada; members | karmada | Used to control the operation scope of command | + +- performance: +
    +
  1. Use the command `karmadactl describe` or `karmadactl describe --operation-scope karmada` to show details of resources in the karmada control plane.
  2. +
  3. Use the command `karmadactl describe --operation-scope members --cluster member1` to show details of resources in the member1 cluster.
  4. +
  5. When the `operation-scope` flag is set to members and the `cluster` flag is empty, a message should prompt the user with "must specify a cluster".
  6. +
+ + +#### karmadactl top pod + +- description: Display resource (CPU/memory) usage of pods in Karmada control plane and member clusters.. +- usage scope: Karmada control plane and member clusters. +- scope-related flag set: + +| name | type | optional values | default | usage | +|-----------------|----------|-----------------------|---------|------------------------------------------------| +| clusters | []string | / | none | Used to specify target member clusters | +| operation-scope | string | karmada; members; all | karmada | Used to control the operation scope of command | + +- performance: + +
    +
  1. Use the command `karmadactl top pod` or `karmadactl top pod --operation-scope karmada` to display resource (CPU/memory) usage of pods in Karmada control plane.
  2. +
  3. Use the command `karmadactl top pod --operation-scope members` to display resource (CPU/memory) usage of pods in all member clusters.
  4. +
  5. Use the command `karmadactl top pod --operation-scope members --clusters member1,member2` to display resource (CPU/memory) usage of pods in member1 cluster and member2 cluster.
  6. +
  7. Use the command `karmadactl top pod --operation-scope all` to display resource (CPU/memory) usage of pods in Karmada control plane and all member clusters.
  8. +
  9. Use the command `karmadactl top pod --operation-scope all --clusters member1,member2` to display resource (CPU/memory) usage of pods in Karmada control plane, member1 cluster and member2 cluster.
  10. +
+ +### Adding New Commands + +#### karmadactl edit, create, delete, label, patch and annotate + +These commands provide the capability for karmadactl to create, delete, and update resources on the Karmada control plane with functionalities that are consistent with those available in kubectl. + +- usage scope: Karmada control plane +- scope-related flag set: None. + +#### karmadactl top node + +- description: Display resource (CPU/memory) usage of nodes in Karmada control plane and member clusters. +- usage scope: Karmada control plane and member clusters. +- scope-related flag set: + +| name | type | optional values | default | usage | +|-----------------|----------|-----------------------|---------|------------------------------------------------| +| clusters | []string | / | none | Used to specify target member clusters | +| operation-scope | string | karmada; members; all | karmada | Used to control the operation scope of command | + +- performance: + +
    +
  1. Use the command `karmadactl top node` or `karmadactl top node --operation-scope karmada` to display resource (CPU/memory) usage of nodes in Karmada control plane.
  2. +
  3. Use the command `karmadactl top node --operation-scope members` to display resource (CPU/memory) usage of nodes in all member clusters.
  4. +
  5. Use the command `karmadactl top node --operation-scope members --clusters member1,member2` to display resource (CPU/memory) usage of nodes in member1 cluster and member2 cluster.
  6. +
  7. Use the command `karmadactl top node --operation-scope all` to display resource (CPU/memory) usage of nodes in Karmada control plane and all member clusters.
  8. +
  9. Use the command `karmadactl top node --operation-scope all --clusters member1,member2` to display resource (CPU/memory) usage of nodes in Karmada control plane, member1 cluster and member2 cluster.
  10. +
+ +#### karmadactl attach +- description: attach to a process that is already running inside an existing container in Karmada control plane or a member cluster. +- usage scope: Karmada Control Plane or a Single Member Cluster. +- scope-related flag set: + +| name | type | optional values | default | usage | +|-----------------|--------|------------------|---------|------------------------------------------------| +| cluster | string | / | none | Used to specify target member cluster | +| operation-scope | string | karmada; members | karmada | Used to control the operation scope of command | + +- performance: +
    +
  1. Use the command `karmadactl attach` or `karmadactl attach --operation-scope karmada` to attach to a process running inside an existing container in the karmada control plane.
  2. +
  3. Use the command `karmadactl attach --operation-scope members --cluster member1` to attach to a process running inside an existing container in the member1 cluster.
  4. +
  5. When the `operation-scope` flag is set to members and the `cluster` flag is empty, a message should prompt the user with "must specify a cluster".
  6. +
+ +#### karmadactl api-resources +- description: Print the supported API resources on the server in Karmada control plane or a member cluster. +- usage scope: Karmada Control Plane or a Single Member Cluster +- scope-related flag set: + +| name | type | optional values | default | usage | +|-----------------|--------|------------------|---------|------------------------------------------------| +| cluster | string | / | none | Used to specify target member cluster | +| operation-scope | string | karmada; members | karmada | Used to control the operation scope of command | + +- performance: +
    +
  1. Use the command `karmadactl api-resources` or `karmadactl api-resources --operation-scope karmada` to print the supported API resources on the server in Karmada control plane.
  2. +
  3. Use the command `karmadactl api-resources --operation-scope members --cluster member1` to attach to print the supported API resources on the server in the member1 cluster.
  4. +
  5. When the `operation-scope` flag is set to members and the `cluster` flag is empty, a message should prompt the user with "must specify a cluster".
  6. +
+ +#### karmadactl explain +- description: Describe fields and structure of various resources in Karmada control plane or a member cluster. +- usage scope: Karmada Control Plane or a Single Member Cluster +- scope-related flag set: + +| name | type | optional values | default | usage | +|-----------------|--------|------------------|---------|------------------------------------------------| +| cluster | string | / | none | Used to specify target member cluster | +| operation-scope | string | karmada; members | karmada | Used to control the operation scope of command | + +- performance: +
    +
  1. Use the command `karmadactl explain` or `karmadactl explain --operation-scope karmada` to describe fields and structure of various resources in Karmada control plane.
  2. +
  3. Use the command `karmadactl explain --operation-scope members --cluster member1` to describe fields and structure of various resources in the member1 cluster.
  4. +
  5. When the `operation-scope` flag is set to members and the `cluster` flag is empty, a message should prompt the user with "must specify a cluster".
  6. +
+ +### Q&A + +#### Why choose to complete the above command? + +Choosing to complete the above command is based on the following reasons: + +- It's a popular command in kubectl. +- There is considerable usage value, which can improve the operations experience. + +#### karmadactl hopes to complement the capabilities of kubectl. How should it handle the evolution of kubectl in the future, and will there be significant maintenance costs? + +- For commands that are completely consistent with kubectl's capabilities, karmadactl can achieve this by encapsulating kubectl, ensuring its capabilities remain consistent with those of `k8s.io/kubectl` that karmada depends on, eliminating the need for additional maintenance. +- For commands that have evolved from kubectl, they are effectively different commands and can evolve independently. New capabilities added to kubectl in the future can be considered for separate introduction based on demand. +- For new commands added to kubectl, they can be considered for separate introduction based on need. + +In summary, the overall maintenance cost is controllable. + +#### For commands that are currently identical to kubectl's capabilities, such as `karmadactl delete`, if optimizations are identified during later evolution, how should they be handled? + +This situation is likely to occur because many commands specific to Karmada's functionality are yet to be fully explored. Once the requirements become clear, the command can be evolved accordingly. This can be planned as part of the next iteration of karmadactl's optimization. + +## Alternatives + + + + diff --git a/docs/proposals/scheduling/policy-preemption/README.md b/docs/proposals/scheduling/policy-preemption/README.md index 978d541f1ed3..026a79e83f8e 100644 --- a/docs/proposals/scheduling/policy-preemption/README.md +++ b/docs/proposals/scheduling/policy-preemption/README.md @@ -49,7 +49,7 @@ Even if workloads have been propagated by a policy, they can be preempted by a h Cluster administrators usually cannot foresee future expansion scenarios when configuring policies. They will usually start with a broad policy to set the base strategy. When an application requires special configuration, -the administrator wants to provide a persionalized policy to take over the application. +the administrator wants to provide a personalized policy to take over the application. At this time, it hopes that the high-priority policy can preempt the low-priority policy. ### Goals @@ -257,7 +257,7 @@ metadata: namespace: default ``` -Assume that there is a high-priority policy which allows preepmtion: +Assume that there is a high-priority policy which allows preemption: ```yaml apiVersion: policy.karmada.io/v1alpha1 diff --git a/docs/proposals/scheduling/workload-rebalancer/workload-rebalancer.md b/docs/proposals/scheduling/workload-rebalancer/workload-rebalancer.md index 160d1ce80662..2cecb5df454e 100644 --- a/docs/proposals/scheduling/workload-rebalancer/workload-rebalancer.md +++ b/docs/proposals/scheduling/workload-rebalancer/workload-rebalancer.md @@ -87,7 +87,7 @@ sufficient resource to accommodate all replicas, so that the application better #### Story 4 -In disaster-recovery scenario, replicas migrated from primary cluster to backup cluster when primary cluster failue. +In disaster-recovery scenario, replicas migrated from primary cluster to backup cluster when primary cluster failure. As a cluster administrator, I hope that replicas can migrate back when cluster restored, so that: @@ -402,7 +402,7 @@ status: > 1. the `observedWorkloads` is sorted in increasing dict order of the combined string of `apiVersion/kind/namespace/name` . > 2. if workload referenced binding not found, it will be marked as `failed` without retry. > 3. if workload rebalanced failed due to occasional network error, the controller will retry, and its `result` and `reason` -> field will left empty until it succees. +> field will left empty until it succeeds. ### How to update this resource diff --git a/docs/proposals/service-discovery/README.md b/docs/proposals/service-discovery/README.md index 8a2d6a182345..1cb48158af11 100644 --- a/docs/proposals/service-discovery/README.md +++ b/docs/proposals/service-discovery/README.md @@ -162,7 +162,7 @@ With this API, we will: * Use `ServiceProvisionClusters` to specify the member clusters which will provision the service backend, if leave it empty, we will collect the backend endpoints from all clusters and sync them to the `ServiceConsumptionClusters`. * Use `ServiceConsumptionClusters` to specify the clusters where the service will be exposed. If leave it empty, the service will be exposed to all clusters. -For example, if we want access `foo`` service which are localted in member2 from member3 , we can use the following yaml: +For example, if we want access `foo`` service which are located in member2 from member3 , we can use the following yaml: ```yaml apiVersion: v1 kind: Service @@ -223,10 +223,10 @@ The process of synchronizing `EndpointSlice` from `ServiceProvisionClusters` to 1. `endpointsliceDispatch` controller will list&watch `MultiClusterService`. 1. `endpointsliceDispatch` controller will list&watch `EndpointSlice` from `MultiClusterService`'s `spec.serviceProvisionClusters`. -1. `endpointsliceDispatch` controller will creat the corresponding Work for each `EndpointSlice` in the cluster namespace of `MultiClusterService`'s `spec.serviceConsumptionClusters`. +1. `endpointsliceDispatch` controller will create the corresponding Work for each `EndpointSlice` in the cluster namespace of `MultiClusterService`'s `spec.serviceConsumptionClusters`. When creating the Work, in order to facilitate problem investigation, we should add following annotation to record the original `EndpointSlice` information: * `endpointslice.karmada.io/work-provision-cluster`: the cluster name of the original `EndpointSlice`. - Also, we should add the following annotation to the syned `EndpointSlice` record the original information: + Also, we should add the following annotation to the synced `EndpointSlice` record the original information: * `endpointslice.karmada.io/endpointslice-generation`: the resource generation of the `EndpointSlice`, it could be used to check whether the `EndpointSlice` is the newest version. * `endpointslice.karmada.io/provision-cluster`: the cluster location of the original `EndpointSlice`. 1. Karmada will sync the `EndpointSlice`'s work to the member clusters. @@ -326,7 +326,7 @@ For better monitoring, we should have following metrics: * For `multiclusterservice` controller, List&watch cluster creation/deletion, reconcile the work in corresponding cluster execution namespace. (10) * For `endpointsliceCollect` controller, List&watch mcs, collect the corresponding EndpointSlice from `serviceProvisionClusters`, and `endpointsliceDispatch` controller should sync the corresponding Work. (5d) * For `endpointsliceCollect` controller, List&watch cluster creation/deletion, reconcile the EndpointSlice's work in corresponding cluster execution namespace. (10d) -* If cluster gets unhealth, mcs-eps-controller should delete the EndpointSlice from all the cluster execution namespace. (5d) +* If cluster gets unhealthy, mcs-eps-controller should delete the EndpointSlice from all the cluster execution namespace. (5d) ### Test Plan diff --git a/examples/customresourceinterpreter/webhook/app/webhook_test.go b/examples/customresourceinterpreter/webhook/app/webhook_test.go new file mode 100644 index 000000000000..99ac9ea7cb4e --- /dev/null +++ b/examples/customresourceinterpreter/webhook/app/webhook_test.go @@ -0,0 +1,47 @@ +/* +Copyright 2024 The Karmada 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 app + +import ( + "context" + "testing" +) + +func TestNewWebhookCommand(t *testing.T) { + ctx := context.Background() + cmd := NewWebhookCommand(ctx) + + if cmd == nil { + t.Fatal("NewWebhookCommand returned nil") + } + + if cmd.Use != "karmada-interpreter-webhook-example" { + t.Errorf("Expected command use to be 'karmada-interpreter-webhook-example', got %s", cmd.Use) + } + + if cmd.Run == nil { + t.Error("Expected Run function to be set") + } + + flags := cmd.Flags() + expectedFlags := []string{"bind-address", "cert-dir", "secure-port"} + for _, flag := range expectedFlags { + if flags.Lookup(flag) == nil { + t.Errorf("Expected flag %s to be set", flag) + } + } +} diff --git a/examples/customresourceinterpreter/webhook/app/workloadwebhook_test.go b/examples/customresourceinterpreter/webhook/app/workloadwebhook_test.go new file mode 100644 index 000000000000..54ebd33daa1b --- /dev/null +++ b/examples/customresourceinterpreter/webhook/app/workloadwebhook_test.go @@ -0,0 +1,259 @@ +/* +Copyright 2024 The Karmada 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 app + +import ( + "context" + "encoding/json" + "net/http" + "testing" + + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/utils/ptr" + + workloadv1alpha1 "github.com/karmada-io/karmada/examples/customresourceinterpreter/apis/workload/v1alpha1" + configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1" + "github.com/karmada-io/karmada/pkg/webhook/interpreter" +) + +func TestWorkloadInterpreter_responseWithExploreReplica(t *testing.T) { + testCases := []struct { + name string + workload *workloadv1alpha1.Workload + expected int32 + }{ + { + name: "Workload with replicas", + workload: &workloadv1alpha1.Workload{ + Spec: workloadv1alpha1.WorkloadSpec{ + Replicas: ptr.To[int32](3), + }, + }, + expected: 3, + }, + { + name: "Workload without replicas", + workload: &workloadv1alpha1.Workload{ + Spec: workloadv1alpha1.WorkloadSpec{}, + }, + expected: 0, + }, + } + + interpreter := &workloadInterpreter{} + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + response := interpreter.responseWithExploreReplica(tc.workload) + if response.Replicas != nil { + assert.Equal(t, tc.expected, *response.Replicas) + } else { + assert.Equal(t, tc.expected, int32(0)) + } + }) + } +} + +func TestWorkloadInterpreter_responseWithExploreDependency(t *testing.T) { + workload := &workloadv1alpha1.Workload{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test-namespace", + }, + Spec: workloadv1alpha1.WorkloadSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + EnvFrom: []corev1.EnvFromSource{ + { + ConfigMapRef: &corev1.ConfigMapEnvSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "test-configmap", + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + + interpreter := &workloadInterpreter{} + response := interpreter.responseWithExploreDependency(workload) + + expectedDependencies := []configv1alpha1.DependentObjectReference{ + { + APIVersion: "v1", + Kind: "ConfigMap", + Namespace: "test-namespace", + Name: "test-configmap", + }, + } + + assert.Equal(t, expectedDependencies, response.Dependencies) +} + +func TestWorkloadInterpreter_responseWithExploreInterpretHealth(t *testing.T) { + testCases := []struct { + name string + workload *workloadv1alpha1.Workload + expected bool + }{ + { + name: "Healthy workload", + workload: &workloadv1alpha1.Workload{ + Spec: workloadv1alpha1.WorkloadSpec{ + Replicas: ptr.To[int32](3), + }, + Status: workloadv1alpha1.WorkloadStatus{ + ReadyReplicas: 3, + }, + }, + expected: true, + }, + { + name: "Unhealthy workload", + workload: &workloadv1alpha1.Workload{ + Spec: workloadv1alpha1.WorkloadSpec{ + Replicas: ptr.To[int32](3), + }, + Status: workloadv1alpha1.WorkloadStatus{ + ReadyReplicas: 2, + }, + }, + expected: false, + }, + } + + interpreter := &workloadInterpreter{} + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + response := interpreter.responseWithExploreInterpretHealth(tc.workload) + assert.Equal(t, tc.expected, *response.Healthy) + }) + } +} + +func TestWorkloadInterpreter_responseWithExploreInterpretStatus(t *testing.T) { + workload := &workloadv1alpha1.Workload{ + Status: workloadv1alpha1.WorkloadStatus{ + ReadyReplicas: 3, + }, + } + + interpreter := &workloadInterpreter{} + response := interpreter.responseWithExploreInterpretStatus(workload) + + expectedStatus := &workloadv1alpha1.WorkloadStatus{ + ReadyReplicas: 3, + } + expectedBytes, _ := json.Marshal(expectedStatus) + + assert.Equal(t, expectedBytes, response.RawStatus.Raw) +} + +func TestWorkloadInterpreter_Handle(t *testing.T) { + testCases := []struct { + name string + operation configv1alpha1.InterpreterOperation + expectedStatus int32 + checkResponse func(*testing.T, interpreter.Response) + }{ + { + name: "InterpretReplica operation", + operation: configv1alpha1.InterpreterOperationInterpretReplica, + expectedStatus: http.StatusOK, + }, + { + name: "InterpretDependency operation", + operation: configv1alpha1.InterpreterOperationInterpretDependency, + expectedStatus: http.StatusOK, + }, + { + name: "InterpretHealth operation", + operation: configv1alpha1.InterpreterOperationInterpretHealth, + expectedStatus: http.StatusOK, + }, + { + name: "InterpretStatus operation", + operation: configv1alpha1.InterpreterOperationInterpretStatus, + expectedStatus: http.StatusOK, + }, + { + name: "Invalid operation", + operation: "InvalidOperation", + expectedStatus: http.StatusBadRequest, + }, + } + + scheme := runtime.NewScheme() + _ = workloadv1alpha1.Install(scheme) + decoder := interpreter.NewDecoder(scheme) + + interpreterInstance := &workloadInterpreter{ + decoder: decoder, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + workload := &workloadv1alpha1.Workload{ + Spec: workloadv1alpha1.WorkloadSpec{ + Replicas: ptr.To[int32](3), + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + EnvFrom: []corev1.EnvFromSource{ + { + ConfigMapRef: &corev1.ConfigMapEnvSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "test-configmap", + }, + }, + }, + }, + }, + }, + }, + }, + }, + Status: workloadv1alpha1.WorkloadStatus{ + ReadyReplicas: 3, + }, + } + workloadBytes, _ := json.Marshal(workload) + + req := interpreter.Request{ + ResourceInterpreterRequest: configv1alpha1.ResourceInterpreterRequest{ + Operation: tc.operation, + Object: runtime.RawExtension{ + Raw: workloadBytes, + }, + }, + } + + response := interpreterInstance.Handle(context.Background(), req) + assert.Equal(t, tc.expectedStatus, response.Status.Code) + }) + } +} diff --git a/go.mod b/go.mod index e07c93470c11..4003b456fdcb 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/karmada-io/karmada -go 1.22.4 // keep in sync with .go-version, Readme.md#Prerequisites, hack/util.sh +go 1.22.6 // keep in sync with .go-version, Readme.md#Prerequisites, hack/util.sh require ( github.com/adhocore/gronx v1.6.3 @@ -14,8 +14,8 @@ require ( github.com/kr/pretty v0.3.1 github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f github.com/olekukonko/tablewriter v0.0.5 - github.com/onsi/ginkgo/v2 v2.17.1 - github.com/onsi/gomega v1.32.0 + github.com/onsi/ginkgo/v2 v2.17.2 + github.com/onsi/gomega v1.33.1 github.com/opensearch-project/opensearch-go v1.1.0 github.com/prometheus/client_golang v1.18.0 github.com/spf13/cobra v1.8.0 @@ -26,11 +26,11 @@ require ( github.com/vektra/mockery/v2 v2.10.0 github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 go.uber.org/mock v0.4.0 - golang.org/x/net v0.23.0 - golang.org/x/term v0.18.0 + golang.org/x/net v0.24.0 + golang.org/x/term v0.19.0 golang.org/x/text v0.14.0 golang.org/x/time v0.5.0 - golang.org/x/tools v0.18.0 + golang.org/x/tools v0.20.0 gomodules.xyz/jsonpatch/v2 v2.4.0 google.golang.org/grpc v1.60.1 gopkg.in/yaml.v3 v3.0.1 @@ -47,15 +47,15 @@ require ( k8s.io/controller-manager v0.30.2 k8s.io/klog/v2 v2.120.1 k8s.io/kube-aggregator v0.30.2 - k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 + k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f k8s.io/kubectl v0.30.2 k8s.io/metrics v0.30.2 - k8s.io/utils v0.0.0-20231127182322-b307cd553661 + k8s.io/utils v0.0.0-20240423183400-0849a56e8f22 layeh.com/gopher-json v0.0.0-20201124131017-552bb3c4c3bf sigs.k8s.io/cluster-api v1.7.1 sigs.k8s.io/controller-runtime v0.18.4 - sigs.k8s.io/custom-metrics-apiserver v1.29.0 - sigs.k8s.io/kind v0.22.0 + sigs.k8s.io/custom-metrics-apiserver v1.30.0 + sigs.k8s.io/kind v0.24.0 sigs.k8s.io/mcs-api v0.1.0 sigs.k8s.io/metrics-server v0.7.1 sigs.k8s.io/structured-merge-diff/v4 v4.4.1 @@ -64,10 +64,10 @@ require ( require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect - github.com/BurntSushi/toml v1.0.0 // indirect + github.com/BurntSushi/toml v1.4.0 // indirect github.com/MakeNowJust/heredoc v1.0.0 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect - github.com/alessio/shellescape v1.4.1 // indirect + github.com/alessio/shellescape v1.4.2 // indirect github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -79,7 +79,7 @@ require ( github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/emicklei/go-restful/v3 v3.12.0 // indirect github.com/evanphx/json-patch v5.7.0+incompatible // indirect github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect github.com/fatih/camelcase v1.0.0 // indirect @@ -93,14 +93,14 @@ require ( github.com/go-openapi/jsonpointer v0.20.2 // indirect github.com/go-openapi/jsonreference v0.20.4 // indirect github.com/go-openapi/swag v0.22.7 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/btree v1.0.1 // indirect github.com/google/cel-go v0.17.8 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 // indirect + github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/gorilla/websocket v1.5.0 // indirect @@ -129,7 +129,7 @@ require ( github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/pelletier/go-toml v1.9.4 // indirect + github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect @@ -170,12 +170,12 @@ require ( go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect - golang.org/x/crypto v0.21.0 // indirect + golang.org/x/crypto v0.22.0 // indirect golang.org/x/exp v0.0.0-20231226003508-02704c960a9b // indirect - golang.org/x/mod v0.15.0 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.18.0 // indirect - golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.18.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.19.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto v0.0.0-20231212172506-995d672761c0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0 // indirect diff --git a/go.sum b/go.sum index 67d6cb6db3c6..7791a8d41aa1 100644 --- a/go.sum +++ b/go.sum @@ -65,8 +65,8 @@ github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxB github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU= -github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= +github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= @@ -88,8 +88,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alessio/shellescape v1.2.2/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= -github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= -github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= +github.com/alessio/shellescape v1.4.2 h1:MHPfaU+ddJ0/bYWpgIeUnQUqKrlJ1S7BfEYPM4uEoM0= +github.com/alessio/shellescape v1.4.2/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18= @@ -190,8 +190,8 @@ github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+m github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.12.0 h1:y2DdzBAURM29NFF94q6RaY4vjIH1rtwDapwQtU84iWk= +github.com/emicklei/go-restful/v3 v3.12.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -212,7 +212,6 @@ github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLi github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI= github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.0.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= -github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= @@ -307,8 +306,8 @@ github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+ github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -402,8 +401,8 @@ github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 h1:pUa4ghanp6q4IJHwE9RwLgmVFfReJN+KbQ8ExNEUUoQ= -github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 h1:SJ+NtwL6QaZ21U+IrK7d0gGgpjGGvd2kz+FzTHVzdqI= github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2/go.mod h1:Tv1PlzqC9t8wNnpPdctvtSUOPUUg4SHeE6vR1Ir2hmg= @@ -590,7 +589,6 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= @@ -601,15 +599,15 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8= -github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= +github.com/onsi/ginkgo/v2 v2.17.2 h1:7eMhcy3GimbsA3hEnVKdw/PQM9XN9krpKVXsZdph0/g= +github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk= -github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg= +github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= +github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= 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/opensearch-project/opensearch-go v1.1.0 h1:eG5sh3843bbU1itPRjA9QXbxcg8LaZ+DjEzQH9aLN3M= @@ -619,8 +617,9 @@ github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144T github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= -github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= @@ -721,7 +720,6 @@ github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3 github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= -github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= @@ -891,8 +889,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -933,8 +931,8 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= -golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -992,8 +990,8 @@ golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1025,8 +1023,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1116,13 +1114,13 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1207,8 +1205,8 @@ golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= -golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= +golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= +golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1381,7 +1379,6 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= @@ -1477,16 +1474,16 @@ k8s.io/kube-aggregator v0.30.2 h1:0+yk/ED6foCprY8VmkDPUhngjaAPKsNTXB/UrtvbIz0= k8s.io/kube-aggregator v0.30.2/go.mod h1:EhqCfDdxysNWXk1wRL9SEHAdo1DKl6EULQagztkBcXE= k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= -k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= -k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= +k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f h1:0LQagt0gDpKqvIkAMPaRGcXawNMouPECM1+F9BVxEaM= +k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f/go.mod h1:S9tOR0FxgyusSNR+MboCuiDpVWkAifZvaYI1Q2ubgro= k8s.io/kubectl v0.30.2 h1:cgKNIvsOiufgcs4yjvgkK0+aPCfa8pUwzXdJtkbhsH8= k8s.io/kubectl v0.30.2/go.mod h1:rz7GHXaxwnigrqob0lJsiA07Df8RE3n1TSaC2CTeuB4= k8s.io/metrics v0.30.2 h1:zj4kIPTCfEbY0RHEogpA7QtlItU7xaO11+Gz1zVDxlc= k8s.io/metrics v0.30.2/go.mod h1:GpoO5XTy/g8CclVLtgA5WTrr2Cy5vCsqr5Xa/0ETWIk= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20200603063816-c1c6865ac451/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20231127182322-b307cd553661 h1:FepOBzJ0GXm8t0su67ln2wAZjbQ6RxQGZDnzuLcrUTI= -k8s.io/utils v0.0.0-20231127182322-b307cd553661/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20240423183400-0849a56e8f22 h1:ao5hUqGhsqdm+bYbjH/pRkCs0unBGe9UyDahzs9zQzQ= +k8s.io/utils v0.0.0-20240423183400-0849a56e8f22/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= layeh.com/gopher-json v0.0.0-20201124131017-552bb3c4c3bf h1:rRz0YsF7VXj9fXRF6yQgFI7DzST+hsI3TeFSGupntu0= layeh.com/gopher-json v0.0.0-20201124131017-552bb3c4c3bf/go.mod h1:ivKkcY8Zxw5ba0jldhZCYYQfGdb2K6u9tbYK1AwMIBc= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= @@ -1501,13 +1498,13 @@ sigs.k8s.io/controller-runtime v0.6.1/go.mod h1:XRYBPdbf5XJu9kpS84VJiZ7h/u1hF3gE sigs.k8s.io/controller-runtime v0.18.4 h1:87+guW1zhvuPLh1PHybKdYFLU0YJp4FhJRmiHvm5BZw= sigs.k8s.io/controller-runtime v0.18.4/go.mod h1:TVoGrfdpbA9VRFaRnKgk9P5/atA0pMwq+f+msb9M8Sg= sigs.k8s.io/controller-tools v0.3.0/go.mod h1:enhtKGfxZD1GFEoMgP8Fdbu+uKQ/cq1/WGJhdVChfvI= -sigs.k8s.io/custom-metrics-apiserver v1.29.0 h1:uUoUjbPrE6nVBE82bo8siIkUDMsfbaSTBB6jAx/LJ9M= -sigs.k8s.io/custom-metrics-apiserver v1.29.0/go.mod h1:4XXz92s/SEmP3L2nlUu6lMWorxEQXAD39AdL22IQkDA= +sigs.k8s.io/custom-metrics-apiserver v1.30.0 h1:BCgg2QfInoWXvoJgPK8TxrSS9r5wR4NNvr7M+9sUOYo= +sigs.k8s.io/custom-metrics-apiserver v1.30.0/go.mod h1:QXOKIL83M545uITzoZn4OC1C7nr0WhLh70A38pbzUpk= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/kind v0.8.1/go.mod h1:oNKTxUVPYkV9lWzY6CVMNluVq8cBsyq+UgPJdvA3uu4= -sigs.k8s.io/kind v0.22.0 h1:z/+yr/azoOfzsfooqRsPw1wjJlqT/ukXP0ShkHwNlsI= -sigs.k8s.io/kind v0.22.0/go.mod h1:aBlbxg08cauDgZ612shr017/rZwqd7AS563FvpWKPVs= +sigs.k8s.io/kind v0.24.0 h1:g4y4eu0qa+SCeKESLpESgMmVFBebL0BDa6f777OIWrg= +sigs.k8s.io/kind v0.24.0/go.mod h1:t7ueEpzPYJvHA8aeLtI52rtFftNgUYUaCwvxjk7phfw= sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0= sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY= sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM7vh3b7HvGNfXrJ/xL6BDMS0v1V/HHg5U= @@ -1522,6 +1519,5 @@ sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+s sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/hack/README.md b/hack/README.md index de625268b496..75f649a42720 100644 --- a/hack/README.md +++ b/hack/README.md @@ -12,6 +12,8 @@ ensures development quality. - [`local-up-karmada.sh`](local-up-karmada.sh) This script will quickly set up a local development environment with member clusters based on the current codebase. +- [`local-down-karmada.sh`](local-down-karmada.sh) This script will clean up the whole local deployment environment installed by the previous `local-up-karmada.sh` script. + - [`remote-up-karmada.sh`](remote-up-karmada.sh) This script will install Karmada to a standalone K8s cluster, this cluster may be real, remote , and even for production. It is worth noting for the connectivity from your client to Karmada API server, it will directly use host network by default, else `export LOAD_BALANCER=true` with the `LoadBalancer` type service before the following script. diff --git a/hack/cli-testing-environment.sh b/hack/cli-testing-environment.sh index 0fc8c715bc09..698a1df7f496 100755 --- a/hack/cli-testing-environment.sh +++ b/hack/cli-testing-environment.sh @@ -33,6 +33,29 @@ MEMBER_CLUSTER_2_NAME=${MEMBER_CLUSTER_2_NAME:-"member2"} CLUSTER_VERSION=${CLUSTER_VERSION:-"${DEFAULT_CLUSTER_VERSION}"} BUILD_PATH=${BUILD_PATH:-"_output/bin/linux/amd64"} + +# install kind and kubectl +kind_version=v0.22.0 +echo -n "Preparing: 'kind' existence check - " +if util::cmd_exist kind; then + echo "passed" +else + echo "not pass" + util::install_tools "sigs.k8s.io/kind" $kind_version +fi +# get arch name and os name in bootstrap +BS_ARCH=$(go env GOARCH) +BS_OS=$(go env GOOS) +# check arch and os name before installing +util::install_environment_check "${BS_ARCH}" "${BS_OS}" +echo -n "Preparing: 'kubectl' existence check - " +if util::cmd_exist kubectl; then + echo "passed" +else + echo "not pass" + util::install_kubectl "" "${BS_ARCH}" "${BS_OS}" +fi + # prepare the newest crds echo "Prepare the newest crds" cd charts/karmada/ diff --git a/hack/local-up-karmada.sh b/hack/local-up-karmada.sh index 17336e6e7c53..991ccb290b6e 100755 --- a/hack/local-up-karmada.sh +++ b/hack/local-up-karmada.sh @@ -79,7 +79,7 @@ util::verify_go_version util::verify_docker # install kind and kubectl -kind_version=v0.22.0 +kind_version=v0.24.0 echo -n "Preparing: 'kind' existence check - " if util::cmd_exist kind; then echo "passed" diff --git a/hack/util.sh b/hack/util.sh index 3f60ceef54dc..2230e09f2135 100755 --- a/hack/util.sh +++ b/hack/util.sh @@ -37,9 +37,9 @@ KARMADA_METRICS_ADAPTER_LABEL="karmada-metrics-adapter" KARMADA_GO_PACKAGE="github.com/karmada-io/karmada" -MIN_Go_VERSION=go1.22.4 +MIN_Go_VERSION=go1.22.6 -DEFAULT_CLUSTER_VERSION="kindest/node:v1.27.3" +DEFAULT_CLUSTER_VERSION="kindest/node:v1.31.0" KARMADA_TARGET_SOURCE=( karmada-aggregated-apiserver=cmd/aggregated-apiserver diff --git a/operator/config/crds/operator.karmada.io_karmadas.yaml b/operator/config/crds/operator.karmada.io_karmadas.yaml index 8da390cc121e..9a04701a8dbe 100644 --- a/operator/config/crds/operator.karmada.io_karmadas.yaml +++ b/operator/config/crds/operator.karmada.io_karmadas.yaml @@ -1733,6 +1733,34 @@ spec: type: object type: object type: object + crdTarball: + description: |- + CRDTarball specifies the source from which the Karmada CRD tarball should be downloaded, along with the download policy to use. + If not set, the operator will download the tarball from a GitHub release. + By default, it will download the tarball of the same version as the operator itself. + For instance, if the operator's version is v1.10.0, the tarball will be downloaded from the following location: + https://github.com/karmada-io/karmada/releases/download/v1.10.0/crds.tar.gz + By default, the operator will only attempt to download the tarball if it's not yet present in the local cache. + properties: + crdDownloadPolicy: + default: IfNotPresent + description: |- + CRDDownloadPolicy specifies a policy that should be used to download the CRD tarball. + Valid values are "Always" and "IfNotPresent". + Defaults to "IfNotPresent". + enum: + - Always + - IfNotPresent + type: string + httpSource: + description: HTTPSource specifies how to download the CRD tarball + via either HTTP or HTTPS protocol. + properties: + url: + description: URL specifies the URL of the CRD tarball resource. + type: string + type: object + type: object featureGates: additionalProperties: type: boolean diff --git a/operator/pkg/apis/operator/v1alpha1/type.go b/operator/pkg/apis/operator/v1alpha1/type.go index fbe5dfd72711..dd2ebb518333 100644 --- a/operator/pkg/apis/operator/v1alpha1/type.go +++ b/operator/pkg/apis/operator/v1alpha1/type.go @@ -44,6 +44,38 @@ type Karmada struct { Status KarmadaStatus `json:"status,omitempty"` } +// CRDDownloadPolicy specifies a policy for how the operator will download the Karmada CRD tarball +type CRDDownloadPolicy string + +const ( + // DownloadAlways instructs the Karmada operator to always download the CRD tarball from a remote location. + DownloadAlways CRDDownloadPolicy = "Always" + + // DownloadIfNotPresent instructs the Karmada operator to download the CRDs tarball from a remote location only if it is not yet present in the local cache. + DownloadIfNotPresent CRDDownloadPolicy = "IfNotPresent" +) + +// HTTPSource specifies how to download the CRD tarball via either HTTP or HTTPS protocol. +type HTTPSource struct { + // URL specifies the URL of the CRD tarball resource. + URL string `json:"url,omitempty"` +} + +// CRDTarball specifies the source from which the Karmada CRD tarball should be downloaded, along with the download policy to use. +type CRDTarball struct { + // HTTPSource specifies how to download the CRD tarball via either HTTP or HTTPS protocol. + // +optional + HTTPSource *HTTPSource `json:"httpSource,omitempty"` + + // CRDDownloadPolicy specifies a policy that should be used to download the CRD tarball. + // Valid values are "Always" and "IfNotPresent". + // Defaults to "IfNotPresent". + // +kubebuilder:validation:Enum=Always;IfNotPresent + // +kubebuilder:default=IfNotPresent + // +optional + CRDDownloadPolicy *CRDDownloadPolicy `json:"crdDownloadPolicy,omitempty"` +} + // KarmadaSpec is the specification of the desired behavior of the Karmada. type KarmadaSpec struct { // HostCluster represents the cluster where to install the Karmada control plane. @@ -72,6 +104,15 @@ type KarmadaSpec struct { // More info: https://github.com/karmada-io/karmada/blob/master/pkg/features/features.go // +optional FeatureGates map[string]bool `json:"featureGates,omitempty"` + + // CRDTarball specifies the source from which the Karmada CRD tarball should be downloaded, along with the download policy to use. + // If not set, the operator will download the tarball from a GitHub release. + // By default, it will download the tarball of the same version as the operator itself. + // For instance, if the operator's version is v1.10.0, the tarball will be downloaded from the following location: + // https://github.com/karmada-io/karmada/releases/download/v1.10.0/crds.tar.gz + // By default, the operator will only attempt to download the tarball if it's not yet present in the local cache. + // +optional + CRDTarball *CRDTarball `json:"crdTarball,omitempty"` } // ImageRegistry represents an image registry as well as the diff --git a/operator/pkg/apis/operator/v1alpha1/zz_generated.deepcopy.go b/operator/pkg/apis/operator/v1alpha1/zz_generated.deepcopy.go index 7e0139e61292..465f0cf1a622 100644 --- a/operator/pkg/apis/operator/v1alpha1/zz_generated.deepcopy.go +++ b/operator/pkg/apis/operator/v1alpha1/zz_generated.deepcopy.go @@ -27,6 +27,32 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CRDTarball) DeepCopyInto(out *CRDTarball) { + *out = *in + if in.HTTPSource != nil { + in, out := &in.HTTPSource, &out.HTTPSource + *out = new(HTTPSource) + **out = **in + } + if in.CRDDownloadPolicy != nil { + in, out := &in.CRDDownloadPolicy, &out.CRDDownloadPolicy + *out = new(CRDDownloadPolicy) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CRDTarball. +func (in *CRDTarball) DeepCopy() *CRDTarball { + if in == nil { + return nil + } + out := new(CRDTarball) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CommonSettings) DeepCopyInto(out *CommonSettings) { *out = *in @@ -126,6 +152,22 @@ func (in *ExternalEtcd) DeepCopy() *ExternalEtcd { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPSource) DeepCopyInto(out *HTTPSource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPSource. +func (in *HTTPSource) DeepCopy() *HTTPSource { + if in == nil { + return nil + } + out := new(HTTPSource) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *HostCluster) DeepCopyInto(out *HostCluster) { *out = *in @@ -559,6 +601,11 @@ func (in *KarmadaSpec) DeepCopyInto(out *KarmadaSpec) { (*out)[key] = val } } + if in.CRDTarball != nil { + in, out := &in.CRDTarball, &out.CRDTarball + *out = new(CRDTarball) + (*in).DeepCopyInto(*out) + } return } diff --git a/operator/pkg/controller/context/context_test.go b/operator/pkg/controller/context/context_test.go new file mode 100644 index 000000000000..507800745650 --- /dev/null +++ b/operator/pkg/controller/context/context_test.go @@ -0,0 +1,113 @@ +/* +Copyright 2024 The Karmada 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 context + +import ( + "testing" + + "k8s.io/apimachinery/pkg/util/sets" +) + +func TestIsControllerEnabled(t *testing.T) { + tests := []struct { + name string + controllers []string + controllerName string + disabledByDefaultControllers sets.Set[string] + expected bool + }{ + { + name: "Explicitly enabled controller", + controllers: []string{"foo", "bar"}, + controllerName: "foo", + disabledByDefaultControllers: sets.New[string](), + expected: true, + }, + { + name: "Explicitly disabled controller", + controllers: []string{"-foo", "bar"}, + controllerName: "foo", + disabledByDefaultControllers: sets.New[string](), + expected: false, + }, + { + name: "Controller not mentioned, no star", + controllers: []string{"bar", "baz"}, + controllerName: "foo", + disabledByDefaultControllers: sets.New[string](), + expected: false, + }, + { + name: "Controller not mentioned, with star", + controllers: []string{"*", "bar"}, + controllerName: "foo", + disabledByDefaultControllers: sets.New[string](), + expected: true, + }, + { + name: "Controller not mentioned, with star, disabled by default", + controllers: []string{"*", "bar"}, + controllerName: "foo", + disabledByDefaultControllers: sets.New("foo"), + expected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx := Context{Controllers: tt.controllers} + result := ctx.IsControllerEnabled(tt.controllerName, tt.disabledByDefaultControllers) + if result != tt.expected { + t.Errorf("IsControllerEnabled() = %v, want %v", result, tt.expected) + } + }) + } +} + +func TestInitializersControllerNames(t *testing.T) { + tests := []struct { + name string + initializers Initializers + expected []string + }{ + { + name: "Three controllers", + initializers: Initializers{ + "controller1": func(_ Context) (bool, error) { return true, nil }, + "controller2": func(_ Context) (bool, error) { return true, nil }, + "controller3": func(_ Context) (bool, error) { return true, nil }, + }, + expected: []string{"controller1", "controller2", "controller3"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := tt.initializers.ControllerNames() + if len(result) != len(tt.expected) { + t.Errorf("ControllerNames() returned %d names, want %d", len(result), len(tt.expected)) + } + + expectedSet := sets.NewString(tt.expected...) + for _, name := range result { + if !expectedSet.Has(name) { + t.Errorf("ControllerNames() returned unexpected name: %s", name) + } + } + }) + } +} diff --git a/operator/pkg/controlplane/manifests.go b/operator/pkg/controlplane/manifests.go index fc67c4d2fa96..65ff5386763e 100644 --- a/operator/pkg/controlplane/manifests.go +++ b/operator/pkg/controlplane/manifests.go @@ -128,11 +128,10 @@ spec: command: - /bin/karmada-controller-manager - --kubeconfig=/etc/karmada/kubeconfig - - --bind-address=0.0.0.0 - --cluster-status-update-frequency=10s - - --secure-port=10357 - --failover-eviction-timeout=30s - --leader-elect-resource-namespace={{ .SystemNamespace }} + - --health-probe-bind-address=0.0.0.0:10357 - --v=4 livenessProbe: httpGet: @@ -184,8 +183,8 @@ spec: command: - /bin/karmada-scheduler - --kubeconfig=/etc/karmada/kubeconfig - - --bind-address=0.0.0.0 - - --secure-port=10351 + - --metrics-bind-address=0.0.0.0:10351 + - --health-probe-bind-address=0.0.0.0:10351 - --enable-scheduler-estimator=true - --leader-elect-resource-namespace={{ .SystemNamespace }} - --scheduler-estimator-ca-file=/etc/karmada/pki/ca.crt @@ -248,7 +247,8 @@ spec: command: - /bin/karmada-descheduler - --kubeconfig=/etc/karmada/kubeconfig - - --bind-address=0.0.0.0 + - --metrics-bind-address=0.0.0.0:10358 + - --health-probe-bind-address=0.0.0.0:10358 - --leader-elect-resource-namespace={{ .SystemNamespace }} - --scheduler-estimator-ca-file=/etc/karmada/pki/ca.crt - --scheduler-estimator-cert-file=/etc/karmada/pki/karmada.crt diff --git a/operator/pkg/init.go b/operator/pkg/init.go index f6bde11f760c..31a0bce99cdb 100644 --- a/operator/pkg/init.go +++ b/operator/pkg/init.go @@ -48,7 +48,7 @@ type InitOptions struct { Namespace string Kubeconfig *rest.Config KarmadaVersion string - CRDRemoteURL string + CRDTarball operatorv1alpha1.CRDTarball KarmadaDataDir string Karmada *operatorv1alpha1.Karmada } @@ -60,9 +60,9 @@ func (opt *InitOptions) Validate() error { if len(opt.Name) == 0 || len(opt.Namespace) == 0 { return errors.New("unexpected empty name or namespace") } - if len(opt.CRDRemoteURL) > 0 { - if _, err := url.Parse(opt.CRDRemoteURL); err != nil { - return fmt.Errorf("unexpected invalid crds remote url %s", opt.CRDRemoteURL) + if opt.CRDTarball.HTTPSource != nil { + if _, err := url.Parse(opt.CRDTarball.HTTPSource.URL); err != nil { + return fmt.Errorf("unexpected invalid crds remote url %s", opt.CRDTarball.HTTPSource.URL) } } if !util.IsInCluster(opt.Karmada.Spec.HostCluster) && opt.Karmada.Spec.Components.KarmadaAPIServer.ServiceType == corev1.ServiceTypeClusterIP { @@ -102,7 +102,7 @@ type initData struct { remoteClient clientset.Interface karmadaClient clientset.Interface dnsDomain string - CRDRemoteURL string + CRDTarball operatorv1alpha1.CRDTarball karmadaDataDir string privateRegistry string featureGates map[string]bool @@ -183,7 +183,7 @@ func newRunData(opt *InitOptions) (*initData, error) { karmadaVersion: version, controlplaneAddress: address, remoteClient: remoteClient, - CRDRemoteURL: opt.CRDRemoteURL, + CRDTarball: opt.CRDTarball, karmadaDataDir: opt.KarmadaDataDir, privateRegistry: privateRegistry, components: opt.Karmada.Spec.Components, @@ -235,8 +235,8 @@ func (data *initData) DataDir() string { return data.karmadaDataDir } -func (data *initData) CrdsRemoteURL() string { - return data.CRDRemoteURL +func (data *initData) CrdTarball() operatorv1alpha1.CRDTarball { + return data.CRDTarball } func (data *initData) KarmadaVersion() string { @@ -268,8 +268,14 @@ func defaultJobInitOptions() *InitOptions { // set defaults for karmada. operatorscheme.Scheme.Default(karmada) + defaultDownloadPolicy := operatorv1alpha1.DownloadIfNotPresent return &InitOptions{ - CRDRemoteURL: fmt.Sprintf(defaultCrdURL, operatorv1alpha1.DefaultKarmadaImageVersion), + CRDTarball: operatorv1alpha1.CRDTarball{ + CRDDownloadPolicy: &defaultDownloadPolicy, + HTTPSource: &operatorv1alpha1.HTTPSource{ + URL: fmt.Sprintf(defaultCrdURL, operatorv1alpha1.DefaultKarmadaImageVersion), + }, + }, KarmadaVersion: operatorv1alpha1.DefaultKarmadaImageVersion, KarmadaDataDir: constants.KarmadaDataDir, Karmada: karmada, @@ -282,6 +288,9 @@ func NewInitOptWithKarmada(karmada *operatorv1alpha1.Karmada) InitOpt { o.Karmada = karmada o.Name = karmada.GetName() o.Namespace = karmada.GetNamespace() + if karmada.Spec.CRDTarball != nil { + o.CRDTarball = *karmada.Spec.CRDTarball + } } } diff --git a/operator/pkg/tasks/init/crd.go b/operator/pkg/tasks/init/crd.go index 197895424d00..431ea840f19b 100644 --- a/operator/pkg/tasks/init/crd.go +++ b/operator/pkg/tasks/init/crd.go @@ -17,6 +17,8 @@ limitations under the License. package tasks import ( + "crypto/sha256" + "encoding/hex" "errors" "fmt" "os" @@ -25,6 +27,7 @@ import ( "k8s.io/klog/v2" + operatorv1alpha1 "github.com/karmada-io/karmada/operator/pkg/apis/operator/v1alpha1" "github.com/karmada-io/karmada/operator/pkg/util" "github.com/karmada-io/karmada/operator/pkg/workflow" ) @@ -60,7 +63,11 @@ func runPrepareCrds(r workflow.RunData) error { return errors.New("prepare-crds task invoked with an invalid data struct") } - crdsDir := path.Join(data.DataDir(), data.KarmadaVersion()) + crdsDir, err := getCrdsDir(data) + if err != nil { + return fmt.Errorf("[prepare-crds] failed to get CRD dir, err: %w", err) + } + klog.V(4).InfoS("[prepare-crds] Running prepare-crds task", "karmada", klog.KObj(data)) klog.V(2).InfoS("[prepare-crds] Using crd folder", "folder", crdsDir, "karmada", klog.KObj(data)) @@ -73,7 +80,17 @@ func skipCrdsDownload(r workflow.RunData) (bool, error) { return false, errors.New("prepare-crds task invoked with an invalid data struct") } - crdsDir := path.Join(data.DataDir(), data.KarmadaVersion()) + crdTarball := data.CrdTarball() + if crdTarball.CRDDownloadPolicy != nil && *crdTarball.CRDDownloadPolicy == operatorv1alpha1.DownloadAlways { + klog.V(2).InfoS("[skipCrdsDownload] CrdDownloadPolicy is 'Always', skipping cache check") + return false, nil + } + + crdsDir, err := getCrdsDir(data) + if err != nil { + return false, fmt.Errorf("[skipCrdsDownload] failed to get CRD dir, err: %w", err) + } + if exist, err := util.PathExists(crdsDir); !exist || err != nil { return false, err } @@ -82,7 +99,6 @@ func skipCrdsDownload(r workflow.RunData) (bool, error) { return false, nil } - klog.V(2).InfoS("[download-crds] Skip download crd yaml files, the crd tar exists on disk", "karmada", klog.KObj(data)) return true, nil } @@ -92,31 +108,33 @@ func runCrdsDownload(r workflow.RunData) error { return errors.New("download-crds task invoked with an invalid data struct") } - var ( - crdsDir = path.Join(data.DataDir(), data.KarmadaVersion()) - crdsTarPath = path.Join(crdsDir, crdsFileSuffix) - ) + crdsDir, err := getCrdsDir(data) + if err != nil { + return fmt.Errorf("[download-crds] failed to get CRD dir, err: %w", err) + } + crdsTarPath := path.Join(crdsDir, crdsFileSuffix) exist, err := util.PathExists(crdsDir) if err != nil { return err } - if !exist { - if err := os.MkdirAll(crdsDir, 0700); err != nil { - return err + + if exist { + if err := os.RemoveAll(crdsDir); err != nil { + return fmt.Errorf("failed to delete CRDs directory, err: %w", err) } } - if !existCrdsTar(crdsDir) { - err := util.DownloadFile(data.CrdsRemoteURL(), crdsTarPath) - if err != nil { - return fmt.Errorf("failed to download crd tar, err: %w", err) - } - } else { - klog.V(2).InfoS("[download-crds] The crd tar exists on disk", "path", crdsDir, "karmada", klog.KObj(data)) + if err := os.MkdirAll(crdsDir, 0700); err != nil { + return fmt.Errorf("failed to create CRDs directory, err: %w", err) } - klog.V(2).InfoS("[download-crds] Successfully downloaded crd package for remote url", "karmada", klog.KObj(data)) + crdTarball := data.CrdTarball() + if err := util.DownloadFile(crdTarball.HTTPSource.URL, crdsTarPath); err != nil { + return fmt.Errorf("failed to download CRD tar, err: %w", err) + } + + klog.V(2).InfoS("[download-crds] Successfully downloaded crd package", "karmada", klog.KObj(data)) return nil } @@ -126,15 +144,16 @@ func runUnpack(r workflow.RunData) error { return errors.New("unpack task invoked with an invalid data struct") } - var ( - crdsDir = path.Join(data.DataDir(), data.KarmadaVersion()) - crdsTarPath = path.Join(crdsDir, crdsFileSuffix) - crdsPath = path.Join(crdsDir, crdPathSuffix) - ) + crdsDir, err := getCrdsDir(data) + if err != nil { + return fmt.Errorf("[unpack] failed to get CRD dir, err: %w", err) + } + crdsTarPath := path.Join(crdsDir, crdsFileSuffix) + crdsPath := path.Join(crdsDir, crdPathSuffix) - // TODO: check whether crd yaml is valid. exist, _ := util.PathExists(crdsPath) if !exist { + klog.V(2).InfoS("[runUnpack] CRD yaml files do not exist, unpacking tar file", "unpackDir", crdsDir) if err := util.Unpack(crdsTarPath, crdsDir); err != nil { return fmt.Errorf("[unpack] failed to unpack crd tar, err: %w", err) } @@ -148,6 +167,7 @@ func runUnpack(r workflow.RunData) error { func existCrdsTar(crdsDir string) bool { files := util.ListFiles(crdsDir) + klog.V(2).InfoS("[existCrdsTar] Checking for CRD tar file in directory", "directory", crdsDir) for _, file := range files { if strings.Contains(file.Name(), crdsFileSuffix) && file.Size() > 0 { @@ -156,3 +176,11 @@ func existCrdsTar(crdsDir string) bool { } return false } + +func getCrdsDir(data InitData) (string, error) { + crdTarball := data.CrdTarball() + key := strings.TrimSpace(crdTarball.HTTPSource.URL) + hash := sha256.Sum256([]byte(key)) + hashedKey := hex.EncodeToString(hash[:]) + return path.Join(data.DataDir(), "cache", hashedKey), nil +} diff --git a/operator/pkg/tasks/init/data.go b/operator/pkg/tasks/init/data.go index 6ce0a24910ae..12dd256c0a10 100644 --- a/operator/pkg/tasks/init/data.go +++ b/operator/pkg/tasks/init/data.go @@ -35,7 +35,7 @@ type InitData interface { RemoteClient() clientset.Interface KarmadaClient() clientset.Interface DataDir() string - CrdsRemoteURL() string + CrdTarball() operatorv1alpha1.CRDTarball KarmadaVersion() string Components() *operatorv1alpha1.KarmadaComponents FeatureGates() map[string]bool diff --git a/operator/pkg/tasks/init/karmadaresource.go b/operator/pkg/tasks/init/karmadaresource.go index fb8a421fd285..f0c6dd5e0253 100644 --- a/operator/pkg/tasks/init/karmadaresource.go +++ b/operator/pkg/tasks/init/karmadaresource.go @@ -101,12 +101,12 @@ func runCrds(r workflow.RunData) error { return errors.New("crds task invoked with an invalid data struct") } - var ( - crdsDir = path.Join(data.DataDir(), data.KarmadaVersion()) - crdsPath = path.Join(crdsDir, "crds/bases") - crdsPatchPath = path.Join(crdsDir, "crds/patches") - ) - + crdsDir, err := getCrdsDir(data) + if err != nil { + return fmt.Errorf("failed to get CRD dir, err: %w", err) + } + crdsPath := path.Join(crdsDir, "crds/bases") + crdsPatchPath := path.Join(crdsDir, "crds/patches") crdsClient, err := apiclient.NewCRDsClient(data.ControlplaneConfig()) if err != nil { return err diff --git a/pkg/apis/policy/v1alpha1/propagation_types.go b/pkg/apis/policy/v1alpha1/propagation_types.go index 89c22b65e6e6..ee6a38a85867 100644 --- a/pkg/apis/policy/v1alpha1/propagation_types.go +++ b/pkg/apis/policy/v1alpha1/propagation_types.go @@ -286,6 +286,7 @@ type ApplicationFailoverBehavior struct { // cluster from which the application is migrated. // Valid options are "Immediately", "Graciously" and "Never". // Defaults to "Graciously". + // +kubebuilder:validation:Enum=Immediately;Graciously;Never // +kubebuilder:default=Graciously // +optional PurgeMode PurgeMode `json:"purgeMode,omitempty"` diff --git a/pkg/apis/work/v1alpha1/work_types.go b/pkg/apis/work/v1alpha1/work_types.go index 8abda2170ca2..f1e03ee3e79c 100644 --- a/pkg/apis/work/v1alpha1/work_types.go +++ b/pkg/apis/work/v1alpha1/work_types.go @@ -152,6 +152,8 @@ const ( // WorkDegraded represents that the current state of Work does not match // the desired state for a certain period. WorkDegraded string = "Degraded" + // WorkDispatching represents the dispatching or suspension status of the Work resource + WorkDispatching string = "Dispatching" ) // ResourceHealth represents that the health status of the reference resource. diff --git a/pkg/controllers/applicationfailover/crb_application_failover_controller.go b/pkg/controllers/applicationfailover/crb_application_failover_controller.go index 3947afe17a3f..257772902289 100644 --- a/pkg/controllers/applicationfailover/crb_application_failover_controller.go +++ b/pkg/controllers/applicationfailover/crb_application_failover_controller.go @@ -79,12 +79,12 @@ func (c *CRBApplicationFailoverController) Reconcile(ctx context.Context, req co return controllerruntime.Result{}, nil } - retryDuration, err := c.syncBinding(binding) + retryDuration, err := c.syncBinding(ctx, binding) if err != nil { return controllerruntime.Result{}, err } if retryDuration > 0 { - klog.V(4).Infof("Retry to check health status of the workload after %v minutes.", retryDuration.Minutes()) + klog.V(4).Infof("Retry to check health status of the workload after %v seconds.", retryDuration.Seconds()) return controllerruntime.Result{RequeueAfter: retryDuration}, nil } return controllerruntime.Result{}, nil @@ -122,7 +122,7 @@ func (c *CRBApplicationFailoverController) detectFailure(clusters []string, tole return duration, needEvictClusters } -func (c *CRBApplicationFailoverController) syncBinding(binding *workv1alpha2.ClusterResourceBinding) (time.Duration, error) { +func (c *CRBApplicationFailoverController) syncBinding(ctx context.Context, binding *workv1alpha2.ClusterResourceBinding) (time.Duration, error) { key := types.NamespacedName{Name: binding.Name, Namespace: binding.Namespace} tolerationSeconds := binding.Spec.Failover.Application.DecisionConditions.TolerationSeconds @@ -141,7 +141,7 @@ func (c *CRBApplicationFailoverController) syncBinding(binding *workv1alpha2.Clu } if len(needEvictClusters) != 0 { - if err = c.updateBinding(binding, allClusters, needEvictClusters); err != nil { + if err = c.updateBinding(ctx, binding, allClusters, needEvictClusters); err != nil { return 0, err } } @@ -179,8 +179,8 @@ func (c *CRBApplicationFailoverController) evictBinding(binding *workv1alpha2.Cl return nil } -func (c *CRBApplicationFailoverController) updateBinding(binding *workv1alpha2.ClusterResourceBinding, allClusters sets.Set[string], needEvictClusters []string) error { - if err := c.Update(context.TODO(), binding); err != nil { +func (c *CRBApplicationFailoverController) updateBinding(ctx context.Context, binding *workv1alpha2.ClusterResourceBinding, allClusters sets.Set[string], needEvictClusters []string) error { + if err := c.Update(ctx, binding); err != nil { for _, cluster := range needEvictClusters { helper.EmitClusterEvictionEventForClusterResourceBinding(binding, cluster, c.EventRecorder, err) } diff --git a/pkg/controllers/applicationfailover/crb_application_failover_controller_test.go b/pkg/controllers/applicationfailover/crb_application_failover_controller_test.go index cc81c3a29614..96941bd2d9c7 100644 --- a/pkg/controllers/applicationfailover/crb_application_failover_controller_test.go +++ b/pkg/controllers/applicationfailover/crb_application_failover_controller_test.go @@ -199,7 +199,7 @@ func TestCRBApplicationFailoverController_syncBinding(t *testing.T) { }, } - dur, err := c.syncBinding(binding) + dur, err := c.syncBinding(context.Background(), binding) assert.Equal(t, 5*time.Second, dur) assert.NoError(t, err) } @@ -281,7 +281,7 @@ func TestCRBApplicationFailoverController_updateBinding(t *testing.T) { c := generateCRBApplicationFailoverController() t.Run("failed when c.Update", func(t *testing.T) { - err := c.updateBinding(binding, allClusters, needEvictClusters) + err := c.updateBinding(context.Background(), binding, allClusters, needEvictClusters) assert.Error(t, err) }) @@ -289,7 +289,7 @@ func TestCRBApplicationFailoverController_updateBinding(t *testing.T) { if err := c.Client.Create(context.Background(), binding); err != nil { t.Fatalf("Failed to create binding: %v", err) } - err := c.updateBinding(binding, allClusters, needEvictClusters) + err := c.updateBinding(context.Background(), binding, allClusters, needEvictClusters) assert.NoError(t, err) }) } diff --git a/pkg/controllers/applicationfailover/rb_application_failover_controller.go b/pkg/controllers/applicationfailover/rb_application_failover_controller.go index 6f12488880c7..bbb3ccf9e419 100644 --- a/pkg/controllers/applicationfailover/rb_application_failover_controller.go +++ b/pkg/controllers/applicationfailover/rb_application_failover_controller.go @@ -79,12 +79,12 @@ func (c *RBApplicationFailoverController) Reconcile(ctx context.Context, req con return controllerruntime.Result{}, nil } - retryDuration, err := c.syncBinding(binding) + retryDuration, err := c.syncBinding(ctx, binding) if err != nil { return controllerruntime.Result{}, err } if retryDuration > 0 { - klog.V(4).Infof("Retry to check health status of the workload after %v minutes.", retryDuration.Minutes()) + klog.V(4).Infof("Retry to check health status of the workload after %v seconds.", retryDuration.Seconds()) return controllerruntime.Result{RequeueAfter: retryDuration}, nil } return controllerruntime.Result{}, nil @@ -122,7 +122,7 @@ func (c *RBApplicationFailoverController) detectFailure(clusters []string, toler return duration, needEvictClusters } -func (c *RBApplicationFailoverController) syncBinding(binding *workv1alpha2.ResourceBinding) (time.Duration, error) { +func (c *RBApplicationFailoverController) syncBinding(ctx context.Context, binding *workv1alpha2.ResourceBinding) (time.Duration, error) { key := types.NamespacedName{Name: binding.Name, Namespace: binding.Namespace} tolerationSeconds := binding.Spec.Failover.Application.DecisionConditions.TolerationSeconds @@ -141,7 +141,7 @@ func (c *RBApplicationFailoverController) syncBinding(binding *workv1alpha2.Reso } if len(needEvictClusters) != 0 { - if err = c.updateBinding(binding, allClusters, needEvictClusters); err != nil { + if err = c.updateBinding(ctx, binding, allClusters, needEvictClusters); err != nil { return 0, err } } @@ -181,8 +181,8 @@ func (c *RBApplicationFailoverController) evictBinding(binding *workv1alpha2.Res return nil } -func (c *RBApplicationFailoverController) updateBinding(binding *workv1alpha2.ResourceBinding, allClusters sets.Set[string], needEvictClusters []string) error { - if err := c.Update(context.TODO(), binding); err != nil { +func (c *RBApplicationFailoverController) updateBinding(ctx context.Context, binding *workv1alpha2.ResourceBinding, allClusters sets.Set[string], needEvictClusters []string) error { + if err := c.Update(ctx, binding); err != nil { for _, cluster := range needEvictClusters { helper.EmitClusterEvictionEventForResourceBinding(binding, cluster, c.EventRecorder, err) } diff --git a/pkg/controllers/applicationfailover/rb_application_failover_controller_test.go b/pkg/controllers/applicationfailover/rb_application_failover_controller_test.go index e7925354de24..8c71652b216a 100644 --- a/pkg/controllers/applicationfailover/rb_application_failover_controller_test.go +++ b/pkg/controllers/applicationfailover/rb_application_failover_controller_test.go @@ -195,7 +195,7 @@ func TestRBApplicationFailoverController_syncBinding(t *testing.T) { }, } - dur, err := c.syncBinding(binding) + dur, err := c.syncBinding(context.Background(), binding) assert.Equal(t, 5*time.Second, dur) assert.NoError(t, err) } @@ -277,7 +277,7 @@ func TestRBApplicationFailoverController_updateBinding(t *testing.T) { c := generateRBApplicationFailoverController() t.Run("failed when c.Update", func(t *testing.T) { - err := c.updateBinding(binding, allClusters, needEvictClusters) + err := c.updateBinding(context.Background(), binding, allClusters, needEvictClusters) assert.Error(t, err) }) @@ -285,7 +285,7 @@ func TestRBApplicationFailoverController_updateBinding(t *testing.T) { if err := c.Client.Create(context.Background(), binding); err != nil { t.Fatalf("Failed to create binding: %v", err) } - err := c.updateBinding(binding, allClusters, needEvictClusters) + err := c.updateBinding(context.Background(), binding, allClusters, needEvictClusters) assert.NoError(t, err) }) } diff --git a/pkg/controllers/binding/binding_controller.go b/pkg/controllers/binding/binding_controller.go index 4003bfd5e5dc..3b798ecf78d8 100644 --- a/pkg/controllers/binding/binding_controller.go +++ b/pkg/controllers/binding/binding_controller.go @@ -82,24 +82,24 @@ func (c *ResourceBindingController) Reconcile(ctx context.Context, req controlle if !binding.DeletionTimestamp.IsZero() { klog.V(4).Infof("Begin to delete works owned by binding(%s).", req.NamespacedName.String()) - if err := helper.DeleteWorks(c.Client, req.Namespace, req.Name, binding.Labels[workv1alpha2.ResourceBindingPermanentIDLabel]); err != nil { + if err := helper.DeleteWorks(ctx, c.Client, req.Namespace, req.Name, binding.Labels[workv1alpha2.ResourceBindingPermanentIDLabel]); err != nil { klog.Errorf("Failed to delete works related to %s/%s: %v", binding.GetNamespace(), binding.GetName(), err) return controllerruntime.Result{}, err } - return c.removeFinalizer(binding) + return c.removeFinalizer(ctx, binding) } - return c.syncBinding(binding) + return c.syncBinding(ctx, binding) } // removeFinalizer removes finalizer from the given ResourceBinding -func (c *ResourceBindingController) removeFinalizer(rb *workv1alpha2.ResourceBinding) (controllerruntime.Result, error) { +func (c *ResourceBindingController) removeFinalizer(ctx context.Context, rb *workv1alpha2.ResourceBinding) (controllerruntime.Result, error) { if !controllerutil.ContainsFinalizer(rb, util.BindingControllerFinalizer) { return controllerruntime.Result{}, nil } controllerutil.RemoveFinalizer(rb, util.BindingControllerFinalizer) - err := c.Client.Update(context.TODO(), rb) + err := c.Client.Update(ctx, rb) if err != nil { return controllerruntime.Result{}, err } @@ -107,12 +107,12 @@ func (c *ResourceBindingController) removeFinalizer(rb *workv1alpha2.ResourceBin } // syncBinding will sync resourceBinding to Works. -func (c *ResourceBindingController) syncBinding(binding *workv1alpha2.ResourceBinding) (controllerruntime.Result, error) { - if err := c.removeOrphanWorks(binding); err != nil { +func (c *ResourceBindingController) syncBinding(ctx context.Context, binding *workv1alpha2.ResourceBinding) (controllerruntime.Result, error) { + if err := c.removeOrphanWorks(ctx, binding); err != nil { return controllerruntime.Result{}, err } - workload, err := helper.FetchResourceTemplate(c.DynamicClient, c.InformerManager, c.RESTMapper, binding.Spec.Resource) + workload, err := helper.FetchResourceTemplate(ctx, c.DynamicClient, c.InformerManager, c.RESTMapper, binding.Spec.Resource) if err != nil { if apierrors.IsNotFound(err) { // It might happen when the resource template has been removed but the garbage collector hasn't removed @@ -125,7 +125,7 @@ func (c *ResourceBindingController) syncBinding(binding *workv1alpha2.ResourceBi return controllerruntime.Result{}, err } start := time.Now() - err = ensureWork(c.Client, c.ResourceInterpreter, workload, c.OverrideManager, binding, apiextensionsv1.NamespaceScoped) + err = ensureWork(ctx, c.Client, c.ResourceInterpreter, workload, c.OverrideManager, binding, apiextensionsv1.NamespaceScoped) metrics.ObserveSyncWorkLatency(err, start) if err != nil { klog.Errorf("Failed to transform resourceBinding(%s/%s) to works. Error: %v.", @@ -142,8 +142,8 @@ func (c *ResourceBindingController) syncBinding(binding *workv1alpha2.ResourceBi return controllerruntime.Result{}, nil } -func (c *ResourceBindingController) removeOrphanWorks(binding *workv1alpha2.ResourceBinding) error { - works, err := helper.FindOrphanWorks(c.Client, binding.Namespace, binding.Name, +func (c *ResourceBindingController) removeOrphanWorks(ctx context.Context, binding *workv1alpha2.ResourceBinding) error { + works, err := helper.FindOrphanWorks(ctx, c.Client, binding.Namespace, binding.Name, binding.Labels[workv1alpha2.ResourceBindingPermanentIDLabel], helper.ObtainBindingSpecExistingClusters(binding.Spec)) if err != nil { klog.Errorf("Failed to find orphan works by resourceBinding(%s/%s). Error: %v.", @@ -152,7 +152,7 @@ func (c *ResourceBindingController) removeOrphanWorks(binding *workv1alpha2.Reso return err } - err = helper.RemoveOrphanWorks(c.Client, works) + err = helper.RemoveOrphanWorks(ctx, c.Client, works) if err != nil { klog.Errorf("Failed to remove orphan works by resourceBinding(%s/%s). Error: %v.", binding.GetNamespace(), binding.GetName(), err) @@ -174,7 +174,7 @@ func (c *ResourceBindingController) SetupWithManager(mgr controllerruntime.Manag } func (c *ResourceBindingController) newOverridePolicyFunc() handler.MapFunc { - return func(_ context.Context, a client.Object) []reconcile.Request { + return func(ctx context.Context, a client.Object) []reconcile.Request { var overrideRS []policyv1alpha1.ResourceSelector var namespace string switch t := a.(type) { @@ -188,7 +188,7 @@ func (c *ResourceBindingController) newOverridePolicyFunc() handler.MapFunc { } bindingList := &workv1alpha2.ResourceBindingList{} - if err := c.Client.List(context.TODO(), bindingList); err != nil { + if err := c.Client.List(ctx, bindingList); err != nil { klog.Errorf("Failed to list resourceBindings, error: %v", err) return nil } @@ -207,7 +207,7 @@ func (c *ResourceBindingController) newOverridePolicyFunc() handler.MapFunc { continue } - workload, err := helper.FetchResourceTemplate(c.DynamicClient, c.InformerManager, c.RESTMapper, binding.Spec.Resource) + workload, err := helper.FetchResourceTemplate(ctx, c.DynamicClient, c.InformerManager, c.RESTMapper, binding.Spec.Resource) if err != nil { // If we cannot fetch resource template from binding, this may be due to the fact that the resource template has been deleted. // Just skip it so that it will not affect other bindings. diff --git a/pkg/controllers/binding/binding_controller_test.go b/pkg/controllers/binding/binding_controller_test.go index 563b971fc79f..70d813d98d17 100644 --- a/pkg/controllers/binding/binding_controller_test.go +++ b/pkg/controllers/binding/binding_controller_test.go @@ -34,10 +34,12 @@ import ( controllerruntime "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/reconcile" policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1" workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" testing2 "github.com/karmada-io/karmada/pkg/search/proxy/testing" + "github.com/karmada-io/karmada/pkg/util" "github.com/karmada-io/karmada/pkg/util/fedinformer/genericmanager" "github.com/karmada-io/karmada/pkg/util/gclient" testing3 "github.com/karmada-io/karmada/pkg/util/testing" @@ -197,7 +199,7 @@ func TestResourceBindingController_syncBinding(t *testing.T) { t.Errorf("makeFakeRBCByResource %v", makeErr) return } - got, err := c.syncBinding(tt.rb) + got, err := c.syncBinding(context.Background(), tt.rb) if (err != nil) != tt.wantErr { t.Errorf("syncBinding() error = %v, wantErr %v", err, tt.wantErr) return @@ -242,7 +244,7 @@ func TestResourceBindingController_removeOrphanWorks(t *testing.T) { t.Errorf("makeFakeRBCByResource %v", makeErr) return } - if err := c.removeOrphanWorks(tt.rb); (err != nil) != tt.wantErr { + if err := c.removeOrphanWorks(context.TODO(), tt.rb); (err != nil) != tt.wantErr { t.Errorf("removeOrphanWorks() error = %v, wantErr %v", err, tt.wantErr) } }) @@ -257,19 +259,39 @@ func TestResourceBindingController_newOverridePolicyFunc(t *testing.T) { Name: "pod", } tests := []struct { - name string - want bool - obIsNil bool + name string + want []reconcile.Request + req client.Object + rb *workv1alpha2.ResourceBinding }{ { - name: "newOverridePolicyFunc success test", - want: false, - obIsNil: false, + name: "newOverridePolicyFunc success test", + want: []reconcile.Request{{NamespacedName: types.NamespacedName{Namespace: "default", Name: "test-rb"}}}, + req: &policyv1alpha1.OverridePolicy{ + ObjectMeta: metav1.ObjectMeta{Namespace: rs.Namespace}, + Spec: policyv1alpha1.OverrideSpec{ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: rs.APIVersion, + Kind: rs.Kind, + Namespace: rs.Namespace, + Name: rs.Name, + }, + }}, + }, + rb: &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-rb", + Namespace: "default", + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: rs, + }, + }, }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tempOP := &policyv1alpha1.OverridePolicy{ + { + name: "namespace not match", + want: nil, + req: &policyv1alpha1.OverridePolicy{ ObjectMeta: metav1.ObjectMeta{Namespace: rs.Namespace}, Spec: policyv1alpha1.OverrideSpec{ResourceSelectors: []policyv1alpha1.ResourceSelector{ { @@ -279,18 +301,138 @@ func TestResourceBindingController_newOverridePolicyFunc(t *testing.T) { Name: rs.Name, }, }}, - } + }, + rb: &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-rb", + Namespace: "test", + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: rs, + }, + }, + }, + { + name: "ResourceSelector is empty", + want: []reconcile.Request{{NamespacedName: types.NamespacedName{Namespace: "default", Name: "test-rb"}}}, + req: &policyv1alpha1.OverridePolicy{ + ObjectMeta: metav1.ObjectMeta{Namespace: rs.Namespace}, + Spec: policyv1alpha1.OverrideSpec{ResourceSelectors: []policyv1alpha1.ResourceSelector{}}, + }, + rb: &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-rb", + Namespace: "default", + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: rs, + }, + }, + }, + { + name: "client is nil", + want: nil, + req: nil, + rb: &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-rb", + Namespace: "default", + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: rs, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { c, makeErr := makeFakeRBCByResource(&rs) if makeErr != nil { t.Errorf("makeFakeRBCByResource %v", makeErr) return } + + if tt.rb != nil { + if err := c.Client.Create(context.Background(), tt.rb); err != nil { + t.Errorf("create rb %v", err) + return + } + } + got := c.newOverridePolicyFunc() - if (got == nil) != tt.want { - t.Errorf("newOverridePolicyFunc() is not same as want:%v", tt.want) + result := got(context.Background(), tt.req) + if !reflect.DeepEqual(result, tt.want) { + t.Errorf("newOverridePolicyFunc() got() result is %v not same as want: %v", result, tt.want) + } + }) + } +} + +func TestResourceBindingController_removeFinalizer(t *testing.T) { + tests := []struct { + name string + want controllerruntime.Result + wantErr bool + rb *workv1alpha2.ResourceBinding + create bool + }{ + { + name: "Remove finalizer succeed", + want: controllerruntime.Result{}, + wantErr: false, + rb: &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Finalizers: []string{util.BindingControllerFinalizer}, + }, + }, + create: true, + }, + { + name: "finalizers not exist", + want: controllerruntime.Result{}, + wantErr: false, + rb: &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + }, + create: true, + }, + { + name: "rb not found", + want: controllerruntime.Result{}, + wantErr: true, + rb: &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Finalizers: []string{util.BindingControllerFinalizer}, + }, + }, + create: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c, err := makeFakeRBCByResource(nil) + if err != nil { + t.Fatalf("Failed to create ClusterResourceBindingController: %v", err) + } + + if tt.create && tt.rb != nil { + if err := c.Client.Create(context.Background(), tt.rb); err != nil { + t.Fatalf("Failed to create ClusterResourceBinding: %v", err) + } + } + + result, err := c.removeFinalizer(context.Background(), tt.rb) + if (err != nil) != tt.wantErr { + t.Errorf("ClusterResourceBindingController.removeFinalizer() error = %v, wantErr %v", err, tt.wantErr) + return } - if (got(context.TODO(), client.Object(tempOP)) == nil) == tt.obIsNil { - t.Errorf("newOverridePolicyFunc() got() result is not same as want: %v", tt.obIsNil) + if !reflect.DeepEqual(result, tt.want) { + t.Errorf("ClusterResourceBindingController.removeFinalizer() = %v, want %v", result, tt.want) } }) } diff --git a/pkg/controllers/binding/cluster_resource_binding_controller.go b/pkg/controllers/binding/cluster_resource_binding_controller.go index 5e9f09834dd2..a897224ca174 100644 --- a/pkg/controllers/binding/cluster_resource_binding_controller.go +++ b/pkg/controllers/binding/cluster_resource_binding_controller.go @@ -82,24 +82,24 @@ func (c *ClusterResourceBindingController) Reconcile(ctx context.Context, req co if !clusterResourceBinding.DeletionTimestamp.IsZero() { klog.V(4).Infof("Begin to delete works owned by binding(%s).", req.NamespacedName.String()) - if err := helper.DeleteWorks(c.Client, "", req.Name, clusterResourceBinding.Labels[workv1alpha2.ClusterResourceBindingPermanentIDLabel]); err != nil { + if err := helper.DeleteWorks(ctx, c.Client, "", req.Name, clusterResourceBinding.Labels[workv1alpha2.ClusterResourceBindingPermanentIDLabel]); err != nil { klog.Errorf("Failed to delete works related to %s: %v", clusterResourceBinding.GetName(), err) return controllerruntime.Result{}, err } - return c.removeFinalizer(clusterResourceBinding) + return c.removeFinalizer(ctx, clusterResourceBinding) } - return c.syncBinding(clusterResourceBinding) + return c.syncBinding(ctx, clusterResourceBinding) } // removeFinalizer removes finalizer from the given ClusterResourceBinding -func (c *ClusterResourceBindingController) removeFinalizer(crb *workv1alpha2.ClusterResourceBinding) (controllerruntime.Result, error) { +func (c *ClusterResourceBindingController) removeFinalizer(ctx context.Context, crb *workv1alpha2.ClusterResourceBinding) (controllerruntime.Result, error) { if !controllerutil.ContainsFinalizer(crb, util.ClusterResourceBindingControllerFinalizer) { return controllerruntime.Result{}, nil } controllerutil.RemoveFinalizer(crb, util.ClusterResourceBindingControllerFinalizer) - err := c.Client.Update(context.TODO(), crb) + err := c.Client.Update(ctx, crb) if err != nil { return controllerruntime.Result{}, err } @@ -107,12 +107,12 @@ func (c *ClusterResourceBindingController) removeFinalizer(crb *workv1alpha2.Clu } // syncBinding will sync clusterResourceBinding to Works. -func (c *ClusterResourceBindingController) syncBinding(binding *workv1alpha2.ClusterResourceBinding) (controllerruntime.Result, error) { - if err := c.removeOrphanWorks(binding); err != nil { +func (c *ClusterResourceBindingController) syncBinding(ctx context.Context, binding *workv1alpha2.ClusterResourceBinding) (controllerruntime.Result, error) { + if err := c.removeOrphanWorks(ctx, binding); err != nil { return controllerruntime.Result{}, err } - workload, err := helper.FetchResourceTemplate(c.DynamicClient, c.InformerManager, c.RESTMapper, binding.Spec.Resource) + workload, err := helper.FetchResourceTemplate(ctx, c.DynamicClient, c.InformerManager, c.RESTMapper, binding.Spec.Resource) if err != nil { if apierrors.IsNotFound(err) { // It might happen when the resource template has been removed but the garbage collector hasn't removed @@ -125,7 +125,7 @@ func (c *ClusterResourceBindingController) syncBinding(binding *workv1alpha2.Clu } start := time.Now() - err = ensureWork(c.Client, c.ResourceInterpreter, workload, c.OverrideManager, binding, apiextensionsv1.ClusterScoped) + err = ensureWork(ctx, c.Client, c.ResourceInterpreter, workload, c.OverrideManager, binding, apiextensionsv1.ClusterScoped) metrics.ObserveSyncWorkLatency(err, start) if err != nil { klog.Errorf("Failed to transform clusterResourceBinding(%s) to works. Error: %v.", binding.GetName(), err) @@ -141,15 +141,15 @@ func (c *ClusterResourceBindingController) syncBinding(binding *workv1alpha2.Clu return controllerruntime.Result{}, nil } -func (c *ClusterResourceBindingController) removeOrphanWorks(binding *workv1alpha2.ClusterResourceBinding) error { - works, err := helper.FindOrphanWorks(c.Client, "", binding.Name, binding.Labels[workv1alpha2.ClusterResourceBindingPermanentIDLabel], helper.ObtainBindingSpecExistingClusters(binding.Spec)) +func (c *ClusterResourceBindingController) removeOrphanWorks(ctx context.Context, binding *workv1alpha2.ClusterResourceBinding) error { + works, err := helper.FindOrphanWorks(ctx, c.Client, "", binding.Name, binding.Labels[workv1alpha2.ClusterResourceBindingPermanentIDLabel], helper.ObtainBindingSpecExistingClusters(binding.Spec)) if err != nil { klog.Errorf("Failed to find orphan works by ClusterResourceBinding(%s). Error: %v.", binding.GetName(), err) c.EventRecorder.Event(binding, corev1.EventTypeWarning, events.EventReasonCleanupWorkFailed, err.Error()) return err } - err = helper.RemoveOrphanWorks(c.Client, works) + err = helper.RemoveOrphanWorks(ctx, c.Client, works) if err != nil { klog.Errorf("Failed to remove orphan works by clusterResourceBinding(%s). Error: %v.", binding.GetName(), err) c.EventRecorder.Event(binding, corev1.EventTypeWarning, events.EventReasonCleanupWorkFailed, err.Error()) @@ -169,7 +169,7 @@ func (c *ClusterResourceBindingController) SetupWithManager(mgr controllerruntim } func (c *ClusterResourceBindingController) newOverridePolicyFunc() handler.MapFunc { - return func(_ context.Context, a client.Object) []reconcile.Request { + return func(ctx context.Context, a client.Object) []reconcile.Request { var overrideRS []policyv1alpha1.ResourceSelector switch t := a.(type) { case *policyv1alpha1.ClusterOverridePolicy: @@ -179,7 +179,7 @@ func (c *ClusterResourceBindingController) newOverridePolicyFunc() handler.MapFu } bindingList := &workv1alpha2.ClusterResourceBindingList{} - if err := c.Client.List(context.TODO(), bindingList); err != nil { + if err := c.Client.List(ctx, bindingList); err != nil { klog.Errorf("Failed to list clusterResourceBindings, error: %v", err) return nil } @@ -193,7 +193,7 @@ func (c *ClusterResourceBindingController) newOverridePolicyFunc() handler.MapFu continue } - workload, err := helper.FetchResourceTemplate(c.DynamicClient, c.InformerManager, c.RESTMapper, binding.Spec.Resource) + workload, err := helper.FetchResourceTemplate(ctx, c.DynamicClient, c.InformerManager, c.RESTMapper, binding.Spec.Resource) if err != nil { // If we cannot fetch resource template from binding, this may be due to the fact that the resource template has been deleted. // Just skip it so that it will not affect other bindings. diff --git a/pkg/controllers/binding/cluster_resource_binding_controller_test.go b/pkg/controllers/binding/cluster_resource_binding_controller_test.go new file mode 100644 index 000000000000..22572b4935d4 --- /dev/null +++ b/pkg/controllers/binding/cluster_resource_binding_controller_test.go @@ -0,0 +1,434 @@ +/* +Copyright 2024 The Karmada 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 binding + +import ( + "context" + "fmt" + "reflect" + "testing" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + fakedynamic "k8s.io/client-go/dynamic/fake" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/tools/record" + controllerruntime "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1" + workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" + testing2 "github.com/karmada-io/karmada/pkg/search/proxy/testing" + "github.com/karmada-io/karmada/pkg/util" + "github.com/karmada-io/karmada/pkg/util/fedinformer/genericmanager" + "github.com/karmada-io/karmada/pkg/util/gclient" + testing3 "github.com/karmada-io/karmada/pkg/util/testing" + "github.com/karmada-io/karmada/test/helper" +) + +func makeFakeCRBCByResource(rs *workv1alpha2.ObjectReference) (*ClusterResourceBindingController, error) { + tempDyClient := fakedynamic.NewSimpleDynamicClient(scheme.Scheme) + if rs == nil { + return &ClusterResourceBindingController{ + Client: fake.NewClientBuilder().WithScheme(gclient.NewSchema()).Build(), + RESTMapper: testing2.RestMapper, + InformerManager: genericmanager.NewSingleClusterInformerManager(tempDyClient, 0, nil), + DynamicClient: tempDyClient, + }, nil + } + + var obj runtime.Object + var src string + switch rs.Kind { + case "Namespace": + obj = &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Namespace: "", Name: rs.Name}} + src = "namespaces" + default: + return nil, fmt.Errorf("%s not support yet, pls add for it", rs.Kind) + } + + tempDyClient.Resources = []*metav1.APIResourceList{ + { + GroupVersion: appsv1.SchemeGroupVersion.String(), + APIResources: []metav1.APIResource{ + {Name: rs.Name, Namespaced: true, Kind: rs.Kind, Version: rs.APIVersion}, + }, + }, + } + + return &ClusterResourceBindingController{ + Client: fake.NewClientBuilder().WithScheme(gclient.NewSchema()).Build(), + RESTMapper: helper.NewGroupRESTMapper(rs.Kind, meta.RESTScopeNamespace), + InformerManager: testing3.NewSingleClusterInformerManagerByRS(src, obj), + DynamicClient: tempDyClient, + EventRecorder: record.NewFakeRecorder(1024), + }, nil +} + +func TestClusterResourceBindingController_Reconcile(t *testing.T) { + rs := workv1alpha2.ObjectReference{ + APIVersion: "v1", + Kind: "Namespace", + Name: "test", + } + req := controllerruntime.Request{NamespacedName: client.ObjectKey{Namespace: "", Name: "test"}} + + tests := []struct { + name string + want controllerruntime.Result + wantErr bool + crb *workv1alpha2.ClusterResourceBinding + del bool + req controllerruntime.Request + }{ + { + name: "Reconcile create crb", + want: controllerruntime.Result{}, + wantErr: false, + crb: &workv1alpha2.ClusterResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Labels: map[string]string{"clusterresourcebinding.karmada.io/permanent-id": "f2603cdb-f3f3-4a4b-b289-3186a4fef979"}, + Finalizers: []string{util.ClusterResourceBindingControllerFinalizer}, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: rs, + }, + }, + req: req, + }, + { + name: "Reconcile crb deleted", + want: controllerruntime.Result{}, + wantErr: false, + crb: &workv1alpha2.ClusterResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Labels: map[string]string{"clusterresourcebinding.karmada.io/permanent-id": "f2603cdb-f3f3-4a4b-b289-3186a4fef979"}, + Finalizers: []string{util.ClusterResourceBindingControllerFinalizer}, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: rs, + }, + }, + del: true, + req: req, + }, + { + name: "Req not found", + want: controllerruntime.Result{}, + wantErr: false, + crb: &workv1alpha2.ClusterResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-noexist", + }, + }, + req: req, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c, err := makeFakeCRBCByResource(&rs) + if err != nil { + t.Fatalf("%s", err) + } + + if tt.crb != nil { + if err := c.Client.Create(context.Background(), tt.crb); err != nil { + t.Fatalf("Failed to create ClusterResourceBinding: %v", err) + } + } + + if tt.del { + if err := c.Client.Delete(context.Background(), tt.crb); err != nil { + t.Fatalf("Failed to delete ClusterResourceBinding: %v", err) + } + } + + result, err := c.Reconcile(context.Background(), req) + if (err != nil) != tt.wantErr { + t.Errorf("ClusterResourceBindingController.Reconcile() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(result, tt.want) { + t.Errorf("ClusterResourceBindingController.Reconcile() = %v, want %v", result, tt.want) + } + }) + } +} + +func TestClusterResourceBindingController_removeFinalizer(t *testing.T) { + tests := []struct { + name string + want controllerruntime.Result + wantErr bool + crb *workv1alpha2.ClusterResourceBinding + create bool + }{ + { + name: "Remove finalizer succeed", + want: controllerruntime.Result{}, + wantErr: false, + crb: &workv1alpha2.ClusterResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Finalizers: []string{util.ClusterResourceBindingControllerFinalizer}, + }, + }, + create: true, + }, + { + name: "finalizers not exist", + want: controllerruntime.Result{}, + wantErr: false, + crb: &workv1alpha2.ClusterResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + }, + create: true, + }, + { + name: "crb not found", + want: controllerruntime.Result{}, + wantErr: true, + crb: &workv1alpha2.ClusterResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Finalizers: []string{util.ClusterResourceBindingControllerFinalizer}, + }, + }, + create: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c, err := makeFakeCRBCByResource(nil) + if err != nil { + t.Fatalf("Failed to create ClusterResourceBindingController: %v", err) + } + + if tt.create && tt.crb != nil { + if err := c.Client.Create(context.Background(), tt.crb); err != nil { + t.Fatalf("Failed to create ClusterResourceBinding: %v", err) + } + } + + result, err := c.removeFinalizer(context.Background(), tt.crb) + if (err != nil) != tt.wantErr { + t.Errorf("ClusterResourceBindingController.removeFinalizer() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(result, tt.want) { + t.Errorf("ClusterResourceBindingController.removeFinalizer() = %v, want %v", result, tt.want) + } + }) + } +} + +func TestClusterResourceBindingController_syncBinding(t *testing.T) { + rs := workv1alpha2.ObjectReference{ + APIVersion: "v1", + Kind: "Namespace", + Name: "test", + } + tests := []struct { + name string + want controllerruntime.Result + wantErr bool + crb *workv1alpha2.ClusterResourceBinding + }{ + { + name: "sync binding", + want: controllerruntime.Result{}, + wantErr: false, + crb: &workv1alpha2.ClusterResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Labels: map[string]string{"clusterresourcebinding.karmada.io/permanent-id": "f2603cdb-f3f3-4a4b-b289-3186a4fef979"}, + Finalizers: []string{util.ClusterResourceBindingControllerFinalizer}, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: rs, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c, err := makeFakeCRBCByResource(&rs) + if err != nil { + t.Fatalf("failed to create fake ClusterResourceBindingController: %v", err) + } + + result, err := c.syncBinding(context.Background(), tt.crb) + if (err != nil) != tt.wantErr { + t.Errorf("ClusterResourceBindingController.syncBinding() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(result, tt.want) { + t.Errorf("ClusterResourceBindingController.syncBinding() = %v, want %v", result, tt.want) + } + }) + } +} + +func TestClusterResourceBindingController_removeOrphanWorks(t *testing.T) { + rs := workv1alpha2.ObjectReference{ + APIVersion: "v1", + Kind: "Namespace", + Name: "test", + } + tests := []struct { + name string + wantErr bool + crb *workv1alpha2.ClusterResourceBinding + }{ + { + name: "removeOrphanWorks test", + wantErr: false, + crb: &workv1alpha2.ClusterResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Labels: map[string]string{"clusterresourcebinding.karmada.io/permanent-id": "f2603cdb-f3f3-4a4b-b289-3186a4fef979"}, + Finalizers: []string{util.ClusterResourceBindingControllerFinalizer}, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: rs, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c, err := makeFakeCRBCByResource(&rs) + if err != nil { + t.Fatalf("failed to create fake ClusterResourceBindingController: %v", err) + } + + err = c.removeOrphanWorks(context.Background(), tt.crb) + if (err != nil) != tt.wantErr { + t.Errorf("ClusterResourceBindingController.syncBinding() error = %v, wantErr %v", err, tt.wantErr) + return + } + }) + } +} + +func TestClusterResourceBindingController_newOverridePolicyFunc(t *testing.T) { + rs := workv1alpha2.ObjectReference{ + APIVersion: "v1", + Kind: "Namespace", + Name: "test", + } + + tests := []struct { + name string + want []reconcile.Request + req client.Object + crb *workv1alpha2.ClusterResourceBinding + }{ + { + name: "not clusteroverridepolicy", + want: nil, + req: &policyv1alpha1.OverridePolicy{}, + crb: &workv1alpha2.ClusterResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Labels: map[string]string{"clusterresourcebinding.karmada.io/permanent-id": "f2603cdb-f3f3-4a4b-b289-3186a4fef979"}, + Finalizers: []string{util.ClusterResourceBindingControllerFinalizer}, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: rs, + }, + }, + }, + { + name: "newOverridePolicyFunc test succeed", + want: []reconcile.Request{{NamespacedName: types.NamespacedName{Name: rs.Name}}}, + req: &policyv1alpha1.ClusterOverridePolicy{ + Spec: policyv1alpha1.OverrideSpec{ + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: rs.APIVersion, + Kind: rs.Kind, + Name: rs.Name, + }, + }, + }, + }, + crb: &workv1alpha2.ClusterResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Labels: map[string]string{"clusterresourcebinding.karmada.io/permanent-id": "f2603cdb-f3f3-4a4b-b289-3186a4fef979"}, + Finalizers: []string{util.ClusterResourceBindingControllerFinalizer}, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: rs, + }, + }, + }, + { + name: "ResourceSelector is empty", + want: []reconcile.Request{{NamespacedName: types.NamespacedName{Name: rs.Name}}}, + req: &policyv1alpha1.ClusterOverridePolicy{ + Spec: policyv1alpha1.OverrideSpec{ + ResourceSelectors: []policyv1alpha1.ResourceSelector{}, + }, + }, + crb: &workv1alpha2.ClusterResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Labels: map[string]string{"clusterresourcebinding.karmada.io/permanent-id": "f2603cdb-f3f3-4a4b-b289-3186a4fef979"}, + Finalizers: []string{util.ClusterResourceBindingControllerFinalizer}, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: rs, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c, err := makeFakeCRBCByResource(&rs) + if err != nil { + t.Fatalf("failed to create fake ClusterResourceBindingController: %v", err) + } + + if tt.crb != nil { + if err := c.Client.Create(context.Background(), tt.crb); err != nil { + t.Fatalf("Failed to create ClusterResourceBinding: %v", err) + } + } + + got := c.newOverridePolicyFunc() + result := got(context.Background(), tt.req) + if !reflect.DeepEqual(result, tt.want) { + t.Errorf("ClusterResourceBindingController.newOverridePolicyFunc() get = %v, want %v", result, tt.want) + return + } + }) + } +} diff --git a/pkg/controllers/binding/common.go b/pkg/controllers/binding/common.go index d69673e60978..52593cc7e0fa 100644 --- a/pkg/controllers/binding/common.go +++ b/pkg/controllers/binding/common.go @@ -17,6 +17,7 @@ limitations under the License. package binding import ( + "context" "strconv" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -38,7 +39,7 @@ import ( // ensureWork ensure Work to be created or updated. func ensureWork( - c client.Client, resourceInterpreter resourceinterpreter.ResourceInterpreter, workload *unstructured.Unstructured, + ctx context.Context, c client.Client, resourceInterpreter resourceinterpreter.ResourceInterpreter, workload *unstructured.Unstructured, overrideManager overridemanager.OverrideManager, binding metav1.Object, scope apiextensionsv1.ResourceScope, ) error { var targetClusters []workv1alpha2.TargetCluster @@ -134,7 +135,7 @@ func ensureWork( suspendDispatching := shouldSuspendDispatching(suspension, targetCluster) - if err = helper.CreateOrUpdateWork(c, workMeta, clonedWorkload, &suspendDispatching); err != nil { + if err = helper.CreateOrUpdateWork(ctx, c, workMeta, clonedWorkload, &suspendDispatching); err != nil { return err } } diff --git a/pkg/controllers/binding/common_test.go b/pkg/controllers/binding/common_test.go index b9cc86978bb6..e1c5832525f4 100644 --- a/pkg/controllers/binding/common_test.go +++ b/pkg/controllers/binding/common_test.go @@ -18,6 +18,7 @@ package binding import ( "reflect" + "sort" "testing" v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -379,3 +380,122 @@ func Test_shouldSuspendDispatching(t *testing.T) { }) } } + +func Test_needReviseReplicas(t *testing.T) { + tests := []struct { + name string + replicas int32 + placement *policyv1alpha1.Placement + want bool + }{ + { + name: "replicas is zero", + replicas: 0, + placement: &policyv1alpha1.Placement{ + ReplicaScheduling: &policyv1alpha1.ReplicaSchedulingStrategy{ + ReplicaSchedulingType: policyv1alpha1.ReplicaSchedulingTypeDivided, + }, + }, + want: false, + }, + { + name: "placement is nil", + replicas: 1, + placement: nil, + want: false, + }, + { + name: "replica scheduling type is not divided", + replicas: 1, + placement: &policyv1alpha1.Placement{ + ReplicaScheduling: &policyv1alpha1.ReplicaSchedulingStrategy{ + ReplicaSchedulingType: policyv1alpha1.ReplicaSchedulingTypeDuplicated, + }, + }, + want: false, + }, + { + name: "replica scheduling type is divided", + replicas: 1, + placement: &policyv1alpha1.Placement{ + ReplicaScheduling: &policyv1alpha1.ReplicaSchedulingStrategy{ + ReplicaSchedulingType: policyv1alpha1.ReplicaSchedulingTypeDivided, + }, + }, + want: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := needReviseReplicas(tt.replicas, tt.placement); got != tt.want { + t.Errorf("needReviseReplicas() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_divideReplicasByJobCompletions(t *testing.T) { + tests := []struct { + name string + workload *unstructured.Unstructured + clusters []workv1alpha2.TargetCluster + want []workv1alpha2.TargetCluster + wantErr bool + }{ + { + name: "completions found", + workload: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "spec": map[string]interface{}{ + "completions": int64(10), + }, + }, + }, + clusters: []workv1alpha2.TargetCluster{ + {Name: "cluster1", Replicas: 5}, + {Name: "cluster2", Replicas: 5}, + }, + want: []workv1alpha2.TargetCluster{ + {Name: "cluster1", Replicas: 5}, + {Name: "cluster2", Replicas: 5}, + }, + wantErr: false, + }, + { + name: "error in NestedInt64", + workload: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "spec": "invalid", + }, + }, + clusters: []workv1alpha2.TargetCluster{ + {Name: "cluster1", Replicas: 5}, + {Name: "cluster2", Replicas: 5}, + }, + want: nil, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := divideReplicasByJobCompletions(tt.workload, tt.clusters) + if (err != nil) != tt.wantErr { + t.Errorf("divideReplicasByJobCompletions() error = %v, wantErr %v", err, tt.wantErr) + return + } + + sort.Slice(got, func(i, j int) bool { + return got[i].Name < got[j].Name + }) + sort.Slice(tt.want, func(i, j int) bool { + return tt.want[i].Name < tt.want[j].Name + }) + + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("divideReplicasByJobCompletions() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/controllers/certificate/cert_rotation_controller.go b/pkg/controllers/certificate/cert_rotation_controller.go index 9fe53a085622..816de9ecb01a 100644 --- a/pkg/controllers/certificate/cert_rotation_controller.go +++ b/pkg/controllers/certificate/cert_rotation_controller.go @@ -118,7 +118,7 @@ func (c *CertRotationController) Reconcile(ctx context.Context, req controllerru return controllerruntime.Result{}, err } - if err = c.syncCertRotation(secret); err != nil { + if err = c.syncCertRotation(ctx, secret); err != nil { klog.Errorf("Failed to rotate the certificate of karmada-agent for the given member cluster: %s, err is: %v", cluster.Name, err) return controllerruntime.Result{}, err } @@ -137,7 +137,7 @@ func (c *CertRotationController) SetupWithManager(mgr controllerruntime.Manager) Complete(c) } -func (c *CertRotationController) syncCertRotation(secret *corev1.Secret) error { +func (c *CertRotationController) syncCertRotation(ctx context.Context, secret *corev1.Secret) error { karmadaKubeconfig, err := getKubeconfigFromSecret(secret) if err != nil { return err @@ -174,15 +174,15 @@ func (c *CertRotationController) syncCertRotation(secret *corev1.Secret) error { return fmt.Errorf("invalid private key for certificate request: %v", err) } - csr, err := c.createCSRInControlPlane(clusterName, privateKey, oldCert) + csr, err := c.createCSRInControlPlane(ctx, clusterName, privateKey, oldCert) if err != nil { return fmt.Errorf("failed to create csr in control plane, err is: %v", err) } var newCertData []byte klog.V(1).Infof("Waiting for the client certificate to be issued") - err = wait.PollUntilContextTimeout(context.TODO(), 1*time.Second, 5*time.Minute, false, func(context.Context) (done bool, err error) { - csr, err := c.KubeClient.CertificatesV1().CertificateSigningRequests().Get(context.TODO(), csr, metav1.GetOptions{}) + err = wait.PollUntilContextTimeout(ctx, 1*time.Second, 5*time.Minute, false, func(context.Context) (done bool, err error) { + csr, err := c.KubeClient.CertificatesV1().CertificateSigningRequests().Get(ctx, csr, metav1.GetOptions{}) if err != nil { return false, fmt.Errorf("failed to get the cluster csr %s. err: %v", clusterName, err) } @@ -210,7 +210,7 @@ func (c *CertRotationController) syncCertRotation(secret *corev1.Secret) error { secret.Data["karmada-kubeconfig"] = karmadaKubeconfigBytes // Update the karmada-kubeconfig secret in the member cluster. - if _, err := c.ClusterClient.KubeClient.CoreV1().Secrets(secret.Namespace).Update(context.TODO(), secret, metav1.UpdateOptions{}); err != nil { + if _, err := c.ClusterClient.KubeClient.CoreV1().Secrets(secret.Namespace).Update(ctx, secret, metav1.UpdateOptions{}); err != nil { return fmt.Errorf("unable to update secret, err: %w", err) } @@ -225,7 +225,7 @@ func (c *CertRotationController) syncCertRotation(secret *corev1.Secret) error { return nil } -func (c *CertRotationController) createCSRInControlPlane(clusterName string, privateKey interface{}, oldCert []*x509.Certificate) (string, error) { +func (c *CertRotationController) createCSRInControlPlane(ctx context.Context, clusterName string, privateKey interface{}, oldCert []*x509.Certificate) (string, error) { csrData, err := certutil.MakeCSR(privateKey, &oldCert[0].Subject, nil, nil) if err != nil { return "", fmt.Errorf("unable to generate certificate request: %v", err) @@ -252,7 +252,7 @@ func (c *CertRotationController) createCSRInControlPlane(clusterName string, pri }, } - _, err = c.KubeClient.CertificatesV1().CertificateSigningRequests().Create(context.TODO(), certificateSigningRequest, metav1.CreateOptions{}) + _, err = c.KubeClient.CertificatesV1().CertificateSigningRequests().Create(ctx, certificateSigningRequest, metav1.CreateOptions{}) if err != nil { return "", fmt.Errorf("unable to create certificate request in control plane: %v", err) } diff --git a/pkg/controllers/certificate/cert_rotation_controller_test.go b/pkg/controllers/certificate/cert_rotation_controller_test.go new file mode 100644 index 000000000000..9033eb541595 --- /dev/null +++ b/pkg/controllers/certificate/cert_rotation_controller_test.go @@ -0,0 +1,358 @@ +/* +Copyright 2024 The Karmada 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 certificate + +import ( + "context" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "math/big" + "reflect" + "testing" + "time" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/kubernetes/fake" + controllerruntime "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + clientfake "sigs.k8s.io/controller-runtime/pkg/client/fake" + + clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1" + "github.com/karmada-io/karmada/pkg/util" + "github.com/karmada-io/karmada/pkg/util/gclient" +) + +// cert will expire on 2124-07-28T02:18:16Z +var testCA = `-----BEGIN CERTIFICATE----- +MIIDbTCCAlWgAwIBAgIUQkIQIcbPnAqI8ucdX54k1QhlzQ4wDQYJKoZIhvcNAQEL +BQAwNDEZMBcGA1UEAwwQa3ViZXJuZXRlcy1hZG1pbjEXMBUGA1UECgwOc3lzdGVt +Om1hc3RlcnMwIBcNMjQwODIxMDIxODE2WhgPMjEyNDA3MjgwMjE4MTZaMDQxGTAX +BgNVBAMMEGt1YmVybmV0ZXMtYWRtaW4xFzAVBgNVBAoMDnN5c3RlbTptYXN0ZXJz +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqVWggRDZWNvCgNEMoncb +ASN3RNpZfA+cK4vNC/D2R9m5ATR/ZGt06aP3zWLkqc43MmwsLcFDy/wY+hB50/It +Zqjt5EaIl1jqZnRXuEXe5phq/fZICSM2vL9tt0JX9L9c5LedSWJwSZ8gvjpwQacK +SGMy+HM5lC5Ta3bOR98sTEyFG6Z8kX9KT2HgYsveShO242TRUSJPKW+xocJjxqL+ +GFHKoZp4D+yYkZ2dahHvPiSCxe9WDXKbpZRPTxNb/EMkJ6YOuU8N2QW44u9Lx1y7 +jIAPL6vGcUJeo2UhvyShGKzPrI1tGSWnjKxKCOv8rK5NPuhIXTXDHhTCDB4/r6xt +xQIDAQABo3UwczAdBgNVHQ4EFgQU3vrp4HTLqAPRBqVbo9CV53KjlQkwHwYDVR0j +BBgwFoAU3vrp4HTLqAPRBqVbo9CV53KjlQkwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud +JQQMMAoGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggEB +ADy6VgqstiGXTxV0VzyXtHqVkHX2GNl58HYwC8ti5uy/T7U/WhzOmjDMxoZonA+m +wzE25Dp1J7DN2y02skHoYMP8u0fsDBACWtXxFhwUja+De1CiEZCGhDUeMNS3ka2j +4z9Ow3yChanJXmR6n91hA5TGJ4uk9eFrQgKoLqZ/poRaoxj6861XKWiJS1Wvrz1g +fmbSjVIn4QFA9f611iwS/wGNHJ1dLUza9WuiQeOjculCqxqBl4+kQWmRBcmOkse2 ++KuZJMIMJfS2521AZO35EgXblA2BG1TgZZz6i3E0NMjzi+T1NIMwXawiWXDt4W/l +umubw9aqN/m5NUa3hZ6XmXQ= +-----END CERTIFICATE-----` + +func makeFakeCertRotationController(threshold float64) *CertRotationController { + client := clientfake.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( + &clusterv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{Name: "test", Finalizers: []string{util.ClusterControllerFinalizer}}, + Spec: clusterv1alpha1.ClusterSpec{ + APIEndpoint: "https://127.0.0.1", + SecretRef: &clusterv1alpha1.LocalSecretReference{Namespace: "ns1", Name: "secret1"}, + }, + Status: clusterv1alpha1.ClusterStatus{ + Conditions: []metav1.Condition{ + { + Type: clusterv1alpha1.ClusterConditionReady, + Status: metav1.ConditionTrue, + }, + }, + }, + }, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Namespace: "ns1", Name: "secret1"}, + Data: map[string][]byte{clusterv1alpha1.SecretTokenKey: []byte("token"), clusterv1alpha1.SecretCADataKey: []byte(testCA)}, + }).Build() + return &CertRotationController{ + Client: client, + KubeClient: fake.NewSimpleClientset(), + CertRotationRemainingTimeThreshold: threshold, + ClusterClientSetFunc: util.NewClusterClientSet, + KarmadaKubeconfigNamespace: "karmada-system", + } +} + +func TestCertRotationController_Reconcile(t *testing.T) { + tests := []struct { + name string + cluster *clusterv1alpha1.Cluster + del bool + want controllerruntime.Result + wantErr bool + }{ + { + name: "cluster not found", + cluster: &clusterv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test1", + }, + }, + want: controllerruntime.Result{}, + wantErr: false, + }, + { + name: "cluster is deleted", + cluster: &clusterv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Finalizers: []string{util.ClusterControllerFinalizer}, + }, + }, + del: true, + want: controllerruntime.Result{}, + wantErr: false, + }, + { + name: "get secret failed", + cluster: &clusterv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := makeFakeCertRotationController(0) + if tt.del { + if err := c.Client.Delete(context.Background(), tt.cluster); err != nil { + t.Fatalf("delete cluster failed, error %v", err) + } + } + + req := controllerruntime.Request{NamespacedName: client.ObjectKey{Namespace: "", Name: tt.cluster.Name}} + got, err := c.Reconcile(context.Background(), req) + if (err != nil) != tt.wantErr { + t.Errorf("CertRotationController.Reconcile() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("CertRotationController.Reconcile() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestCertRotationController_syncCertRotation(t *testing.T) { + tests := []struct { + name string + secret *corev1.Secret + signer bool + threshold float64 + wantErr bool + }{ + { + name: "shoud not rotate cert", + secret: &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Namespace: "ns1", Name: "secret"}, + Data: map[string][]byte{"karmada-kubeconfig": []byte(`apiVersion: v1 +clusters: +- cluster: + certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMvakNDQWVhZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJME1EZ3hOVEEyTVRZd01Gb1hEVE0wTURneE16QTJNVFl3TUZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTndZCjU3blNJNDgwMUZIYmtYVUhpUldTTmV3UUxRTTZQbTB5YXArd1JXR2J3emU3US9rbjl0L2xBUWwxdW1aa2ZRalUKVHgyZHV6cFpXQkRndnAreTVBNndaUyt2VTVhSFY4dE1QRi9ocHRVczB1VW11YmQ2OEs4ZnNuREd6bnJwKzdpQwo3R2VyVzB2NDNTdnpqT0dibDQ2Nlp5cXFPRmt5VVhPQ1pVWFJMbWkyMVNrbS9iU2RFS3FDZXBtRDFNSEUwVyttCkJOOXBQeFJOU1dCZGNkSFVqR29odUUrUVBJQXlDWEtBdlNlWDBOZDd6Q1Ayd1dFRE5aSmxRS0REUnFUUHdDS3QKMW9TaDdEeWhvQ0l6clBtNENIcVNHSEJCNnVORmNEZjdpNGhVY09SdW5JMHlVUEsya2FDUmdqTkZKYkJLL29SNApoSFl0SFJwUkN3b244Q3A4dWRFQ0F3RUFBYU5aTUZjd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZESUZTYXhZNDc1WlZaTlp3dGdwOU1yeFBrU2ZNQlVHQTFVZEVRUU8KTUF5Q0NtdDFZbVZ5Ym1WMFpYTXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBSnY3Ymw1L2plVlFZZkxWblByKwpBelVYNmxXdXNHajQ0b09ma2xtZGZTTmxLU3ZGUjVRMi9rWkVQZXZnU3NzZVdIWnVucmZTYkIwVDdWYjdkUkNQCjVRMTk4aUNnZDFwNm0wdXdOVGpSRi85MHhzYUdVOHBQTFQxeHlrMDlCVDc0WVVENnNtOHFVSWVrWFU0U3hlU2oKWjk3VU13azVoZndXUWpqTFc1UklwNW1qZjR2aU1uWXB6SDB4bDREV3Jka1AxbTFCdkZvWmhFMEVaKzlWcGNPYwprNTN4ZkxUR3A2S1UrQ0w4RU5teXFCeTJNcVBXdjRQKzVTZ0hldlY3Ym1WdktuMkx0blExTHdCcDdsdldYb1JRCmUzQm83d3hnSUU0Rnl0VUU4enRaS2ZJSDZPY3VzNWJGY283cGw5ckhnK1lBMHM0Y0JldjZ2UlQwODkyYUpHYmUKZnFRPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + server: https://192.168.0.180:56016 + name: kind-member1 +contexts: +- context: + cluster: kind-member1 + user: kind-member1 + name: member1 +current-context: member1 +kind: Config +preferences: {} +users: +- name: kind-member1 + user: + ## cert will expire on 2124-07-28T02:18:16Z + client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURiVENDQWxXZ0F3SUJBZ0lVUWtJUUljYlBuQXFJOHVjZFg1NGsxUWhselE0d0RRWUpLb1pJaHZjTkFRRUwKQlFBd05ERVpNQmNHQTFVRUF3d1FhM1ZpWlhKdVpYUmxjeTFoWkcxcGJqRVhNQlVHQTFVRUNnd09jM2x6ZEdWdApPbTFoYzNSbGNuTXdJQmNOTWpRd09ESXhNREl4T0RFMldoZ1BNakV5TkRBM01qZ3dNakU0TVRaYU1EUXhHVEFYCkJnTlZCQU1NRUd0MVltVnlibVYwWlhNdFlXUnRhVzR4RnpBVkJnTlZCQW9NRG5ONWMzUmxiVHB0WVhOMFpYSnoKTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUFxVldnZ1JEWldOdkNnTkVNb25jYgpBU04zUk5wWmZBK2NLNHZOQy9EMlI5bTVBVFIvWkd0MDZhUDN6V0xrcWM0M01td3NMY0ZEeS93WStoQjUwL0l0ClpxanQ1RWFJbDFqcVpuUlh1RVhlNXBocS9mWklDU00ydkw5dHQwSlg5TDljNUxlZFNXSndTWjhndmpwd1FhY0sKU0dNeStITTVsQzVUYTNiT1I5OHNURXlGRzZaOGtYOUtUMkhnWXN2ZVNoTzI0MlRSVVNKUEtXK3hvY0pqeHFMKwpHRkhLb1pwNEQreVlrWjJkYWhIdlBpU0N4ZTlXRFhLYnBaUlBUeE5iL0VNa0o2WU91VThOMlFXNDR1OUx4MXk3CmpJQVBMNnZHY1VKZW8yVWh2eVNoR0t6UHJJMXRHU1duakt4S0NPdjhySzVOUHVoSVhUWERIaFRDREI0L3I2eHQKeFFJREFRQUJvM1V3Y3pBZEJnTlZIUTRFRmdRVTN2cnA0SFRMcUFQUkJxVmJvOUNWNTNLamxRa3dId1lEVlIwagpCQmd3Rm9BVTN2cnA0SFRMcUFQUkJxVmJvOUNWNTNLamxRa3dEZ1lEVlIwUEFRSC9CQVFEQWdXZ01CTUdBMVVkCkpRUU1NQW9HQ0NzR0FRVUZCd01DTUF3R0ExVWRFd0VCL3dRQ01BQXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUIKQUR5NlZncXN0aUdYVHhWMFZ6eVh0SHFWa0hYMkdObDU4SFl3Qzh0aTV1eS9UN1UvV2h6T21qRE14b1pvbkErbQp3ekUyNURwMUo3RE4yeTAyc2tIb1lNUDh1MGZzREJBQ1d0WHhGaHdVamErRGUxQ2lFWkNHaERVZU1OUzNrYTJqCjR6OU93M3lDaGFuSlhtUjZuOTFoQTVUR0o0dWs5ZUZyUWdLb0xxWi9wb1Jhb3hqNjg2MVhLV2lKUzFXdnJ6MWcKZm1iU2pWSW40UUZBOWY2MTFpd1Mvd0dOSEoxZExVemE5V3VpUWVPamN1bENxeHFCbDQra1FXbVJCY21Pa3NlMgorS3VaSk1JTUpmUzI1MjFBWk8zNUVnWGJsQTJCRzFUZ1paejZpM0UwTk1qemkrVDFOSU13WGF3aVdYRHQ0Vy9sCnVtdWJ3OWFxTi9tNU5VYTNoWjZYbVhRPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0t + client-key-data: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ3BWYUNCRU5sWTI4S0EKMFF5aWR4c0JJM2RFMmxsOEQ1d3JpODBMOFBaSDJia0JOSDlrYTNUcG8vZk5ZdVNwempjeWJDd3R3VVBML0JqNgpFSG5UOGkxbXFPM2tSb2lYV09wbWRGZTRSZDdtbUdyOTlrZ0pJemE4djIyM1FsZjB2MXprdDUxSlluQkpueUMrCk9uQkJwd3BJWXpMNGN6bVVMbE5yZHM1SDN5eE1USVVicG55UmYwcFBZZUJpeTk1S0U3YmpaTkZSSWs4cGI3R2gKd21QR292NFlVY3FobW5nUDdKaVJuWjFxRWU4K0pJTEY3MVlOY3B1bGxFOVBFMXY4UXlRbnBnNjVUdzNaQmJqaQo3MHZIWEx1TWdBOHZxOFp4UWw2alpTRy9KS0VZck0rc2pXMFpKYWVNckVvSTYveXNyazArNkVoZE5jTWVGTUlNCkhqK3ZyRzNGQWdNQkFBRUNnZ0VBSTdLaGU1UUp2ZW5XUDBIUzRBMHI3RG1GMDBZVXgwcWpLYXIzTnlVOVJqaG8KQUJFSktpcGRJMFFsNFc2UHRoeDdGbTRuZ2gzVUpSU29UMDlaMzR5V2RhWDNRTUI5MnlvcmdCM1d3RW82aTNKbQpXOU9uckFWNGJLSU9oeXU5VHlOb2VlOGJnWFQzSnc0YzRQMkEzTlpTSEtDTkJrT0VSL0RjTlROK21UZzdKbnBDCnMvVmoyd2pibllQNmt6MVRTcEVjRksrb3NnYldXQ1AxVDFUeFRFN1k5VlBjbWhibzU5Lzdxc2EzaE8vUjgxRysKQ0VxU3U1emgrQmJvRFZHUStpZFV3OGtqUlhUS2MzWFBWb0R6SmR6cUtJVUYwTkc1Nm4wdGNoZkVEMUpWS09PSQp5a3REdjM1Qi9JWEkwYzk1UHpJN0crOWJvSHM1aW9BcUZKUlo2bllJQVFLQmdRRHNvTmJRc0p1U1pVcW9ZZTBLCkhERFpXS3F5NUM3Q1IvOFNXTXcxeFQzdnJVV2t2Wm5TZUJHUnpvYUEvZmRXQ3lGWHdBd1ZkS0xFSzFkdW5UWDEKUkQ4Zk9odFBDdTdiaXVvV2l4YlpMcGRPUXVzZlhRcDNHUWtoOUNIQVRPc1pML0tkMmxSd0F6dHpGNTZkVHRtdQplZFIxVENiTEVZK1A1Vzg0MXhjV2Y4OEh3UUtCZ1FDM01uaXBXY0xWNDBlS2xZMEg2alhBMDByWCs3V1U1M21RClFKNXAzbWlxSW5qRWlmV2ZQZHh4Y0hyVWRndzlpRk9pVUVvNENIQnNnam5wRU5wUjVhcUJpTzRWUFBuRXdXM2EKSmJ5eWdmRW4wREdBci9PdFpTTUF6OGN4NFVnZmZpSmZPSk8rZXRNemhDMXlMcFAwR05oM2UyRzlDZ0M3eVhDSQpGT1BvdWlzSEJRS0JnSGROT0VFTGFjUkxrWEtIdk0wR0haTFhZMmpDSnRrSkY0OFdlZzc2SFJvRUVFTFkzUDhDClRrbG5DT1ZzSmhHWmx2djQ5WjZ6cVlTaUhYakZobmpjS2I4Q3V0WUZPeHd4VTRoK0k4em44cDBnbkE2NkNCYTMKNXFUWncxS0M5VjFEa1YwSXdOMmdvNDZKY0F6N3ZrQjdhQ1NqZWtPVDNQKzl1Mis2OGdjRDlVdUJBb0dBUjkxdgp3aGRwUEJpZG52ck55VllTWWlOQkQvczVIMEd5eVdqZisrMzRwdzFBelBERnZ3TTRiL1BNNjMybmpaZm1IeDFhCkVDTVhYeW15NS8vcGRRa2dXeEpKTzJHaEpaTXZzY3p0K2lUSlluSGtpWFA4cG4rdlBJbEZ2Z1ovRVlPY25qZ0cKbFVsL2dvME9ldVZVdXdQb0h1N3l4NEtlQ1F5YnJYWnNkWVphakxVQ2dZRUEyeEhLenJ3T1FwMlNNbXlzOFR1bgpZbm54bzMwV0diQzNpYVJIZkQ0TGRvNC9iNHY2TWtkMG9wdXBoMzArQjduRkZoRjlWSVplbVdGWkMrcXNKWHdLCmNwOGMzdjBNZFJkeUtTcTJ4Ly9ZL2s1KytaeU5DSXRZdzdhRy91Wks4TlZyY3h0c2hXOXBobDFJTThXTjBUYmgKNmxwd2xWZGFha0RPY09ZNjE2clRGOXM9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=`)}, + }, + threshold: 0, + signer: false, + wantErr: false, + }, + { + name: "update secret failed", + secret: &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Namespace: "ns1", Name: "secret"}, + Data: map[string][]byte{"karmada-kubeconfig": []byte(`apiVersion: v1 +clusters: +- cluster: + certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMvakNDQWVhZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJME1EZ3hOVEEyTVRZd01Gb1hEVE0wTURneE16QTJNVFl3TUZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTndZCjU3blNJNDgwMUZIYmtYVUhpUldTTmV3UUxRTTZQbTB5YXArd1JXR2J3emU3US9rbjl0L2xBUWwxdW1aa2ZRalUKVHgyZHV6cFpXQkRndnAreTVBNndaUyt2VTVhSFY4dE1QRi9ocHRVczB1VW11YmQ2OEs4ZnNuREd6bnJwKzdpQwo3R2VyVzB2NDNTdnpqT0dibDQ2Nlp5cXFPRmt5VVhPQ1pVWFJMbWkyMVNrbS9iU2RFS3FDZXBtRDFNSEUwVyttCkJOOXBQeFJOU1dCZGNkSFVqR29odUUrUVBJQXlDWEtBdlNlWDBOZDd6Q1Ayd1dFRE5aSmxRS0REUnFUUHdDS3QKMW9TaDdEeWhvQ0l6clBtNENIcVNHSEJCNnVORmNEZjdpNGhVY09SdW5JMHlVUEsya2FDUmdqTkZKYkJLL29SNApoSFl0SFJwUkN3b244Q3A4dWRFQ0F3RUFBYU5aTUZjd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZESUZTYXhZNDc1WlZaTlp3dGdwOU1yeFBrU2ZNQlVHQTFVZEVRUU8KTUF5Q0NtdDFZbVZ5Ym1WMFpYTXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBSnY3Ymw1L2plVlFZZkxWblByKwpBelVYNmxXdXNHajQ0b09ma2xtZGZTTmxLU3ZGUjVRMi9rWkVQZXZnU3NzZVdIWnVucmZTYkIwVDdWYjdkUkNQCjVRMTk4aUNnZDFwNm0wdXdOVGpSRi85MHhzYUdVOHBQTFQxeHlrMDlCVDc0WVVENnNtOHFVSWVrWFU0U3hlU2oKWjk3VU13azVoZndXUWpqTFc1UklwNW1qZjR2aU1uWXB6SDB4bDREV3Jka1AxbTFCdkZvWmhFMEVaKzlWcGNPYwprNTN4ZkxUR3A2S1UrQ0w4RU5teXFCeTJNcVBXdjRQKzVTZ0hldlY3Ym1WdktuMkx0blExTHdCcDdsdldYb1JRCmUzQm83d3hnSUU0Rnl0VUU4enRaS2ZJSDZPY3VzNWJGY283cGw5ckhnK1lBMHM0Y0JldjZ2UlQwODkyYUpHYmUKZnFRPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + server: https://192.168.0.180:56016 + name: kind-member1 +contexts: +- context: + cluster: kind-member1 + user: kind-member1 + name: member1 +current-context: member1 +kind: Config +preferences: {} +users: +- name: kind-member1 + user: + ## cert will expire on 2124-07-28T02:18:16Z + client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURiVENDQWxXZ0F3SUJBZ0lVUWtJUUljYlBuQXFJOHVjZFg1NGsxUWhselE0d0RRWUpLb1pJaHZjTkFRRUwKQlFBd05ERVpNQmNHQTFVRUF3d1FhM1ZpWlhKdVpYUmxjeTFoWkcxcGJqRVhNQlVHQTFVRUNnd09jM2x6ZEdWdApPbTFoYzNSbGNuTXdJQmNOTWpRd09ESXhNREl4T0RFMldoZ1BNakV5TkRBM01qZ3dNakU0TVRaYU1EUXhHVEFYCkJnTlZCQU1NRUd0MVltVnlibVYwWlhNdFlXUnRhVzR4RnpBVkJnTlZCQW9NRG5ONWMzUmxiVHB0WVhOMFpYSnoKTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUFxVldnZ1JEWldOdkNnTkVNb25jYgpBU04zUk5wWmZBK2NLNHZOQy9EMlI5bTVBVFIvWkd0MDZhUDN6V0xrcWM0M01td3NMY0ZEeS93WStoQjUwL0l0ClpxanQ1RWFJbDFqcVpuUlh1RVhlNXBocS9mWklDU00ydkw5dHQwSlg5TDljNUxlZFNXSndTWjhndmpwd1FhY0sKU0dNeStITTVsQzVUYTNiT1I5OHNURXlGRzZaOGtYOUtUMkhnWXN2ZVNoTzI0MlRSVVNKUEtXK3hvY0pqeHFMKwpHRkhLb1pwNEQreVlrWjJkYWhIdlBpU0N4ZTlXRFhLYnBaUlBUeE5iL0VNa0o2WU91VThOMlFXNDR1OUx4MXk3CmpJQVBMNnZHY1VKZW8yVWh2eVNoR0t6UHJJMXRHU1duakt4S0NPdjhySzVOUHVoSVhUWERIaFRDREI0L3I2eHQKeFFJREFRQUJvM1V3Y3pBZEJnTlZIUTRFRmdRVTN2cnA0SFRMcUFQUkJxVmJvOUNWNTNLamxRa3dId1lEVlIwagpCQmd3Rm9BVTN2cnA0SFRMcUFQUkJxVmJvOUNWNTNLamxRa3dEZ1lEVlIwUEFRSC9CQVFEQWdXZ01CTUdBMVVkCkpRUU1NQW9HQ0NzR0FRVUZCd01DTUF3R0ExVWRFd0VCL3dRQ01BQXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUIKQUR5NlZncXN0aUdYVHhWMFZ6eVh0SHFWa0hYMkdObDU4SFl3Qzh0aTV1eS9UN1UvV2h6T21qRE14b1pvbkErbQp3ekUyNURwMUo3RE4yeTAyc2tIb1lNUDh1MGZzREJBQ1d0WHhGaHdVamErRGUxQ2lFWkNHaERVZU1OUzNrYTJqCjR6OU93M3lDaGFuSlhtUjZuOTFoQTVUR0o0dWs5ZUZyUWdLb0xxWi9wb1Jhb3hqNjg2MVhLV2lKUzFXdnJ6MWcKZm1iU2pWSW40UUZBOWY2MTFpd1Mvd0dOSEoxZExVemE5V3VpUWVPamN1bENxeHFCbDQra1FXbVJCY21Pa3NlMgorS3VaSk1JTUpmUzI1MjFBWk8zNUVnWGJsQTJCRzFUZ1paejZpM0UwTk1qemkrVDFOSU13WGF3aVdYRHQ0Vy9sCnVtdWJ3OWFxTi9tNU5VYTNoWjZYbVhRPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0t + client-key-data: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ3BWYUNCRU5sWTI4S0EKMFF5aWR4c0JJM2RFMmxsOEQ1d3JpODBMOFBaSDJia0JOSDlrYTNUcG8vZk5ZdVNwempjeWJDd3R3VVBML0JqNgpFSG5UOGkxbXFPM2tSb2lYV09wbWRGZTRSZDdtbUdyOTlrZ0pJemE4djIyM1FsZjB2MXprdDUxSlluQkpueUMrCk9uQkJwd3BJWXpMNGN6bVVMbE5yZHM1SDN5eE1USVVicG55UmYwcFBZZUJpeTk1S0U3YmpaTkZSSWs4cGI3R2gKd21QR292NFlVY3FobW5nUDdKaVJuWjFxRWU4K0pJTEY3MVlOY3B1bGxFOVBFMXY4UXlRbnBnNjVUdzNaQmJqaQo3MHZIWEx1TWdBOHZxOFp4UWw2alpTRy9KS0VZck0rc2pXMFpKYWVNckVvSTYveXNyazArNkVoZE5jTWVGTUlNCkhqK3ZyRzNGQWdNQkFBRUNnZ0VBSTdLaGU1UUp2ZW5XUDBIUzRBMHI3RG1GMDBZVXgwcWpLYXIzTnlVOVJqaG8KQUJFSktpcGRJMFFsNFc2UHRoeDdGbTRuZ2gzVUpSU29UMDlaMzR5V2RhWDNRTUI5MnlvcmdCM1d3RW82aTNKbQpXOU9uckFWNGJLSU9oeXU5VHlOb2VlOGJnWFQzSnc0YzRQMkEzTlpTSEtDTkJrT0VSL0RjTlROK21UZzdKbnBDCnMvVmoyd2pibllQNmt6MVRTcEVjRksrb3NnYldXQ1AxVDFUeFRFN1k5VlBjbWhibzU5Lzdxc2EzaE8vUjgxRysKQ0VxU3U1emgrQmJvRFZHUStpZFV3OGtqUlhUS2MzWFBWb0R6SmR6cUtJVUYwTkc1Nm4wdGNoZkVEMUpWS09PSQp5a3REdjM1Qi9JWEkwYzk1UHpJN0crOWJvSHM1aW9BcUZKUlo2bllJQVFLQmdRRHNvTmJRc0p1U1pVcW9ZZTBLCkhERFpXS3F5NUM3Q1IvOFNXTXcxeFQzdnJVV2t2Wm5TZUJHUnpvYUEvZmRXQ3lGWHdBd1ZkS0xFSzFkdW5UWDEKUkQ4Zk9odFBDdTdiaXVvV2l4YlpMcGRPUXVzZlhRcDNHUWtoOUNIQVRPc1pML0tkMmxSd0F6dHpGNTZkVHRtdQplZFIxVENiTEVZK1A1Vzg0MXhjV2Y4OEh3UUtCZ1FDM01uaXBXY0xWNDBlS2xZMEg2alhBMDByWCs3V1U1M21RClFKNXAzbWlxSW5qRWlmV2ZQZHh4Y0hyVWRndzlpRk9pVUVvNENIQnNnam5wRU5wUjVhcUJpTzRWUFBuRXdXM2EKSmJ5eWdmRW4wREdBci9PdFpTTUF6OGN4NFVnZmZpSmZPSk8rZXRNemhDMXlMcFAwR05oM2UyRzlDZ0M3eVhDSQpGT1BvdWlzSEJRS0JnSGROT0VFTGFjUkxrWEtIdk0wR0haTFhZMmpDSnRrSkY0OFdlZzc2SFJvRUVFTFkzUDhDClRrbG5DT1ZzSmhHWmx2djQ5WjZ6cVlTaUhYakZobmpjS2I4Q3V0WUZPeHd4VTRoK0k4em44cDBnbkE2NkNCYTMKNXFUWncxS0M5VjFEa1YwSXdOMmdvNDZKY0F6N3ZrQjdhQ1NqZWtPVDNQKzl1Mis2OGdjRDlVdUJBb0dBUjkxdgp3aGRwUEJpZG52ck55VllTWWlOQkQvczVIMEd5eVdqZisrMzRwdzFBelBERnZ3TTRiL1BNNjMybmpaZm1IeDFhCkVDTVhYeW15NS8vcGRRa2dXeEpKTzJHaEpaTXZzY3p0K2lUSlluSGtpWFA4cG4rdlBJbEZ2Z1ovRVlPY25qZ0cKbFVsL2dvME9ldVZVdXdQb0h1N3l4NEtlQ1F5YnJYWnNkWVphakxVQ2dZRUEyeEhLenJ3T1FwMlNNbXlzOFR1bgpZbm54bzMwV0diQzNpYVJIZkQ0TGRvNC9iNHY2TWtkMG9wdXBoMzArQjduRkZoRjlWSVplbVdGWkMrcXNKWHdLCmNwOGMzdjBNZFJkeUtTcTJ4Ly9ZL2s1KytaeU5DSXRZdzdhRy91Wks4TlZyY3h0c2hXOXBobDFJTThXTjBUYmgKNmxwd2xWZGFha0RPY09ZNjE2clRGOXM9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=`)}, + }, + threshold: 1, + signer: true, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := makeFakeCertRotationController(tt.threshold) + cc, err := util.NewClusterClientSet("test", c.Client, &util.ClientOption{}) + if err != nil { + t.Fatal(err) + } + c.ClusterClient = cc + + if tt.signer { + go mockCSRSigner(c.KubeClient) + } + + if err := c.syncCertRotation(context.Background(), tt.secret); (err != nil) != tt.wantErr { + t.Errorf("CertRotationController.syncCertRotation() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func mockCSRSigner(cs kubernetes.Interface) { + for { + select { + case <-time.After(10 * time.Second): + return + default: + csrL, _ := cs.CertificatesV1().CertificateSigningRequests().List(context.Background(), metav1.ListOptions{}) + for _, csr := range csrL.Items { + t := csr.DeepCopy() + t.Status.Certificate = []byte(testCA) + if _, err := cs.CertificatesV1().CertificateSigningRequests().UpdateStatus(context.Background(), t, metav1.UpdateOptions{}); err != nil { + return + } + } + } + } +} + +func Test_getCertValidityPeriod(t *testing.T) { + now := time.Now() + tests := []struct { + name string + certTime []map[string]time.Time + wantBefore time.Time + wantAfter time.Time + wantErr bool + }{ + { + name: "get cert validity period success", + certTime: []map[string]time.Time{ + { + "notBefore": now.Add(-36 * time.Hour).UTC().Truncate(time.Second), + "notAfter": now.Add(72 * time.Hour).UTC().Truncate(time.Second), + }, + { + "notBefore": now.Add(-24 * time.Hour).UTC().Truncate(time.Second), + "notAfter": now.Add(36 * time.Hour).UTC().Truncate(time.Second), + }, + }, + wantBefore: now.Add(-24 * time.Hour).UTC().Truncate(time.Second), + wantAfter: now.Add(36 * time.Hour).UTC().Truncate(time.Second), + wantErr: false, + }, + { + name: "parse cert fail", + certTime: []map[string]time.Time{}, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + certData := []byte{} + for _, ct := range tt.certTime { + cert, err := newMockCert(ct["notBefore"], ct["notAfter"]) + if err != nil { + t.Fatal(err) + } + certData = append(certData, pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})...) + } + + notBefore, notAfter, err := getCertValidityPeriod(certData) + if tt.wantErr { + if err == nil { + t.Error("expected error but got nil") + } + return + } + + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + + if !tt.wantBefore.Equal(*notBefore) || !tt.wantAfter.Equal(*notAfter) { + t.Errorf("got notBefore=%s, notAfter=%s; want notBefore=%s, notAfter=%s", notBefore, notAfter, tt.wantBefore, tt.wantAfter) + } + }) + } +} + +func newMockCert(notBefore, notAfter time.Time) (*x509.Certificate, error) { + serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128)) + if err != nil { + return nil, err + } + + testSigner, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return nil, err + } + + template := x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{ + CommonName: "karmada.com", + Organization: []string{"karmada"}, + }, + NotBefore: notBefore, + NotAfter: notAfter, + + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + } + + certData, err := x509.CreateCertificate(rand.Reader, &template, &template, &testSigner.PublicKey, testSigner) + if err != nil { + return nil, err + } + + return x509.ParseCertificate(certData) +} diff --git a/pkg/controllers/context/context_test.go b/pkg/controllers/context/context_test.go index d46cbc133fcc..5135b5de58c0 100644 --- a/pkg/controllers/context/context_test.go +++ b/pkg/controllers/context/context_test.go @@ -17,6 +17,8 @@ limitations under the License. package context import ( + "errors" + "reflect" "testing" "k8s.io/apimachinery/pkg/util/sets" @@ -58,6 +60,13 @@ func TestContext_IsControllerEnabled(t *testing.T) { controllers: []string{"*"}, // --controllers=* expected: false, }, + { + name: "on by star, not in disabled list", + controllerName: "foxtrot", + disabledByDefaultControllers: []string{"delta", "echo"}, + controllers: []string{"*"}, // --controllers=* + expected: true, + }, { name: "on by star, not off by name", controllerName: "alpha", @@ -79,6 +88,13 @@ func TestContext_IsControllerEnabled(t *testing.T) { controllers: []string{"alpha", "bravo", "-charlie"}, // --controllers=alpha,bravo,-charlie expected: false, }, + { + name: "empty controllers list", + controllerName: "alpha", + disabledByDefaultControllers: []string{"delta", "echo"}, + controllers: []string{}, // No controllers + expected: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -93,3 +109,84 @@ func TestContext_IsControllerEnabled(t *testing.T) { }) } } + +func TestInitializers_ControllerNames(t *testing.T) { + initializers := Initializers{ + "controller1": func(_ Context) (bool, error) { return true, nil }, + "controller2": func(_ Context) (bool, error) { return true, nil }, + "controller3": func(_ Context) (bool, error) { return true, nil }, + } + + expected := []string{"controller1", "controller2", "controller3"} + result := initializers.ControllerNames() + + if !reflect.DeepEqual(sets.New(result...), sets.New(expected...)) { + t.Errorf("expected %v, but got %v", expected, result) + } +} + +func TestInitializers_StartControllers(t *testing.T) { + tests := []struct { + name string + initializers Initializers + enabledControllers []string + disabledByDefaultControllers []string + expectedError bool + }{ + { + name: "all controllers enabled and started successfully", + initializers: Initializers{ + "controller1": func(_ Context) (bool, error) { return true, nil }, + "controller2": func(_ Context) (bool, error) { return true, nil }, + }, + enabledControllers: []string{"*"}, + disabledByDefaultControllers: []string{}, + expectedError: false, + }, + { + name: "some controllers disabled", + initializers: Initializers{ + "controller1": func(_ Context) (bool, error) { return true, nil }, + "controller2": func(_ Context) (bool, error) { return true, nil }, + "controller3": func(_ Context) (bool, error) { return true, nil }, + }, + enabledControllers: []string{"controller1", "controller2"}, + disabledByDefaultControllers: []string{"controller3"}, + expectedError: false, + }, + { + name: "controller returns error", + initializers: Initializers{ + "controller1": func(_ Context) (bool, error) { return true, nil }, + "controller2": func(_ Context) (bool, error) { return false, errors.New("test error") }, + }, + enabledControllers: []string{"*"}, + disabledByDefaultControllers: []string{}, + expectedError: true, + }, + { + name: "controller not started", + initializers: Initializers{ + "controller1": func(_ Context) (bool, error) { return true, nil }, + "controller2": func(_ Context) (bool, error) { return false, nil }, + }, + enabledControllers: []string{"*"}, + disabledByDefaultControllers: []string{}, + expectedError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx := Context{ + Opts: Options{ + Controllers: tt.enabledControllers, + }, + } + err := tt.initializers.StartControllers(ctx, sets.New(tt.disabledByDefaultControllers...)) + if (err != nil) != tt.expectedError { + t.Errorf("expected error: %v, but got: %v", tt.expectedError, err) + } + }) + } +} diff --git a/pkg/controllers/cronfederatedhpa/cronfederatedhpa_controller.go b/pkg/controllers/cronfederatedhpa/cronfederatedhpa_controller.go index be26a564c85e..ea310559efbf 100755 --- a/pkg/controllers/cronfederatedhpa/cronfederatedhpa_controller.go +++ b/pkg/controllers/cronfederatedhpa/cronfederatedhpa_controller.go @@ -94,7 +94,7 @@ func (c *CronFHPAController) Reconcile(ctx context.Context, req controllerruntim newRuleSets := sets.New[string]() for _, rule := range cronFHPA.Spec.Rules { - if err = c.processCronRule(cronFHPA, rule); err != nil { + if err = c.processCronRule(ctx, cronFHPA, rule); err != nil { return controllerruntime.Result{}, err } newRuleSets.Insert(rule.Name) @@ -106,7 +106,7 @@ func (c *CronFHPAController) Reconcile(ctx context.Context, req controllerruntim continue } c.CronHandler.StopRuleExecutor(req.NamespacedName.String(), name) - if err = c.removeCronFHPAHistory(cronFHPA, name); err != nil { + if err = c.removeCronFHPAHistory(ctx, cronFHPA, name); err != nil { return controllerruntime.Result{}, err } } @@ -125,7 +125,7 @@ func (c *CronFHPAController) SetupWithManager(mgr controllerruntime.Manager) err } // processCronRule processes the cron rule -func (c *CronFHPAController) processCronRule(cronFHPA *autoscalingv1alpha1.CronFederatedHPA, rule autoscalingv1alpha1.CronFederatedHPARule) error { +func (c *CronFHPAController) processCronRule(ctx context.Context, cronFHPA *autoscalingv1alpha1.CronFederatedHPA, rule autoscalingv1alpha1.CronFederatedHPARule) error { cronFHPAKey := helper.GetCronFederatedHPAKey(cronFHPA) if ruleOld, exists := c.CronHandler.RuleCronExecutorExists(cronFHPAKey, rule.Name); exists { if equality.Semantic.DeepEqual(ruleOld, rule) { @@ -142,7 +142,7 @@ func (c *CronFHPAController) processCronRule(cronFHPA *autoscalingv1alpha1.CronF } } - if err := c.updateRuleHistory(cronFHPA, rule); err != nil { + if err := c.updateRuleHistory(ctx, cronFHPA, rule); err != nil { c.EventRecorder.Event(cronFHPA, corev1.EventTypeWarning, "UpdateCronFederatedHPAFailed", err.Error()) return err } @@ -150,7 +150,7 @@ func (c *CronFHPAController) processCronRule(cronFHPA *autoscalingv1alpha1.CronF } // updateRuleHistory updates the rule history -func (c *CronFHPAController) updateRuleHistory(cronFHPA *autoscalingv1alpha1.CronFederatedHPA, rule autoscalingv1alpha1.CronFederatedHPARule) error { +func (c *CronFHPAController) updateRuleHistory(ctx context.Context, cronFHPA *autoscalingv1alpha1.CronFederatedHPA, rule autoscalingv1alpha1.CronFederatedHPARule) error { var nextExecutionTime *metav1.Time if !helper.IsCronFederatedHPARuleSuspend(rule) { // If rule is not suspended, we should set the nextExecutionTime filed, or the nextExecutionTime will be nil @@ -181,7 +181,7 @@ func (c *CronFHPAController) updateRuleHistory(cronFHPA *autoscalingv1alpha1.Cro cronFHPA.Status.ExecutionHistories = append(cronFHPA.Status.ExecutionHistories, ruleHistory) } - if err := c.Client.Status().Update(context.Background(), cronFHPA); err != nil { + if err := c.Client.Status().Update(ctx, cronFHPA); err != nil { klog.Errorf("Fail to update CronFederatedHPA(%s/%s) rule(%s)'s next execution time:%v", cronFHPA.Namespace, cronFHPA.Name, rule.Name, err) return err @@ -191,7 +191,7 @@ func (c *CronFHPAController) updateRuleHistory(cronFHPA *autoscalingv1alpha1.Cro } // removeCronFHPAHistory removes the rule history in status -func (c *CronFHPAController) removeCronFHPAHistory(cronFHPA *autoscalingv1alpha1.CronFederatedHPA, ruleName string) error { +func (c *CronFHPAController) removeCronFHPAHistory(ctx context.Context, cronFHPA *autoscalingv1alpha1.CronFederatedHPA, ruleName string) error { exists := false for index, history := range cronFHPA.Status.ExecutionHistories { if history.RuleName != ruleName { @@ -205,7 +205,7 @@ func (c *CronFHPAController) removeCronFHPAHistory(cronFHPA *autoscalingv1alpha1 if !exists { return nil } - if err := c.Client.Status().Update(context.Background(), cronFHPA); err != nil { + if err := c.Client.Status().Update(ctx, cronFHPA); err != nil { c.EventRecorder.Event(cronFHPA, corev1.EventTypeWarning, "UpdateCronFederatedHPAFailed", err.Error()) klog.Errorf("Fail to remove CronFederatedHPA(%s/%s) rule(%s) history:%v", cronFHPA.Namespace, cronFHPA.Name, ruleName, err) return err diff --git a/pkg/controllers/execution/execution_controller.go b/pkg/controllers/execution/execution_controller.go index 0a957433fcac..679e8560b890 100644 --- a/pkg/controllers/execution/execution_controller.go +++ b/pkg/controllers/execution/execution_controller.go @@ -30,7 +30,6 @@ import ( "k8s.io/client-go/tools/record" "k8s.io/client-go/util/retry" "k8s.io/klog/v2" - "k8s.io/utils/ptr" controllerruntime "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" @@ -53,6 +52,14 @@ import ( const ( // ControllerName is the controller name that will be used when reporting events. ControllerName = "execution-controller" + // WorkSuspendDispatchingConditionMessage is the condition and event message when dispatching is suspended. + WorkSuspendDispatchingConditionMessage = "Work dispatching is in a suspended state." + // WorkDispatchingConditionMessage is the condition and event message when dispatching is not suspended. + WorkDispatchingConditionMessage = "Work is being dispatched to member clusters." + // workSuspendDispatchingConditionReason is the reason for the WorkDispatching condition when dispatching is suspended. + workSuspendDispatchingConditionReason = "SuspendDispatching" + // workDispatchingConditionReason is the reason for the WorkDispatching condition when dispatching is not suspended. + workDispatchingConditionReason = "Dispatching" ) // Controller is to sync Work. @@ -94,15 +101,10 @@ func (c *Controller) Reconcile(ctx context.Context, req controllerruntime.Reques return controllerruntime.Result{}, err } - if ptr.Deref(work.Spec.SuspendDispatching, false) { - klog.V(4).Infof("Skip syncing work(%s/%s) for cluster(%s) as work dispatch is suspended.", work.Namespace, work.Name, cluster.Name) - return controllerruntime.Result{}, nil - } - if !work.DeletionTimestamp.IsZero() { // Abort deleting workload if cluster is unready when unjoining cluster, otherwise the unjoin process will be failed. if util.IsClusterReady(&cluster.Status) { - err := c.tryDeleteWorkload(clusterName, work) + err := c.tryDeleteWorkload(ctx, clusterName, work) if err != nil { klog.Errorf("Failed to delete work %v, namespace is %v, err is %v", work.Name, work.Namespace, err) return controllerruntime.Result{}, err @@ -111,7 +113,17 @@ func (c *Controller) Reconcile(ctx context.Context, req controllerruntime.Reques return controllerruntime.Result{}, fmt.Errorf("cluster(%s) not ready", cluster.Name) } - return c.removeFinalizer(work) + return c.removeFinalizer(ctx, work) + } + + if err := c.updateWorkDispatchingConditionIfNeeded(ctx, work); err != nil { + klog.Errorf("Failed to update work condition type %s. err is %v", workv1alpha1.WorkDispatching, err) + return controllerruntime.Result{}, err + } + + if helper.IsWorkSuspendDispatching(work) { + klog.V(4).Infof("Skip syncing work(%s/%s) for cluster(%s) as work dispatch is suspended.", work.Namespace, work.Name, cluster.Name) + return controllerruntime.Result{}, nil } if !util.IsClusterReady(&cluster.Status) { @@ -119,7 +131,7 @@ func (c *Controller) Reconcile(ctx context.Context, req controllerruntime.Reques return controllerruntime.Result{}, fmt.Errorf("cluster(%s) not ready", cluster.Name) } - return c.syncWork(clusterName, work) + return c.syncWork(ctx, clusterName, work) } // SetupWithManager creates a controller and register to controller manager. @@ -133,9 +145,9 @@ func (c *Controller) SetupWithManager(mgr controllerruntime.Manager) error { Complete(c) } -func (c *Controller) syncWork(clusterName string, work *workv1alpha1.Work) (controllerruntime.Result, error) { +func (c *Controller) syncWork(ctx context.Context, clusterName string, work *workv1alpha1.Work) (controllerruntime.Result, error) { start := time.Now() - err := c.syncToClusters(clusterName, work) + err := c.syncToClusters(ctx, clusterName, work) metrics.ObserveSyncWorkloadLatency(err, start) if err != nil { msg := fmt.Sprintf("Failed to sync work(%s/%s) to cluster(%s), err: %v", work.Namespace, work.Name, clusterName, err) @@ -150,7 +162,7 @@ func (c *Controller) syncWork(clusterName string, work *workv1alpha1.Work) (cont } // tryDeleteWorkload tries to delete resources in the given member cluster. -func (c *Controller) tryDeleteWorkload(clusterName string, work *workv1alpha1.Work) error { +func (c *Controller) tryDeleteWorkload(ctx context.Context, clusterName string, work *workv1alpha1.Work) error { for _, manifest := range work.Spec.Workload.Manifests { workload := &unstructured.Unstructured{} err := workload.UnmarshalJSON(manifest.Raw) @@ -159,7 +171,7 @@ func (c *Controller) tryDeleteWorkload(clusterName string, work *workv1alpha1.Wo return err } - err = c.ObjectWatcher.Delete(clusterName, workload) + err = c.ObjectWatcher.Delete(ctx, clusterName, workload) if err != nil { klog.Errorf("Failed to delete resource in the given member cluster %v, err is %v", clusterName, err) return err @@ -170,13 +182,13 @@ func (c *Controller) tryDeleteWorkload(clusterName string, work *workv1alpha1.Wo } // removeFinalizer remove finalizer from the given Work -func (c *Controller) removeFinalizer(work *workv1alpha1.Work) (controllerruntime.Result, error) { +func (c *Controller) removeFinalizer(ctx context.Context, work *workv1alpha1.Work) (controllerruntime.Result, error) { if !controllerutil.ContainsFinalizer(work, util.ExecutionControllerFinalizer) { return controllerruntime.Result{}, nil } controllerutil.RemoveFinalizer(work, util.ExecutionControllerFinalizer) - err := c.Client.Update(context.TODO(), work) + err := c.Client.Update(ctx, work) if err != nil { return controllerruntime.Result{}, err } @@ -184,7 +196,7 @@ func (c *Controller) removeFinalizer(work *workv1alpha1.Work) (controllerruntime } // syncToClusters ensures that the state of the given object is synchronized to member clusters. -func (c *Controller) syncToClusters(clusterName string, work *workv1alpha1.Work) error { +func (c *Controller) syncToClusters(ctx context.Context, clusterName string, work *workv1alpha1.Work) error { var errs []error syncSucceedNum := 0 for _, manifest := range work.Spec.Workload.Manifests { @@ -196,7 +208,7 @@ func (c *Controller) syncToClusters(clusterName string, work *workv1alpha1.Work) continue } - if err = c.tryCreateOrUpdateWorkload(clusterName, workload); err != nil { + if err = c.tryCreateOrUpdateWorkload(ctx, clusterName, workload); err != nil { klog.Errorf("Failed to create or update resource(%v/%v) in the given member cluster %s, err is %v", workload.GetNamespace(), workload.GetName(), clusterName, err) c.eventf(workload, corev1.EventTypeWarning, events.EventReasonSyncWorkloadFailed, "Failed to create or update resource(%s) in member cluster(%s): %v", klog.KObj(workload), clusterName, err) errs = append(errs, err) @@ -209,7 +221,7 @@ func (c *Controller) syncToClusters(clusterName string, work *workv1alpha1.Work) if len(errs) > 0 { total := len(work.Spec.Workload.Manifests) message := fmt.Sprintf("Failed to apply all manifests (%d/%d): %s", syncSucceedNum, total, errors.NewAggregate(errs).Error()) - err := c.updateAppliedCondition(work, metav1.ConditionFalse, "AppliedFailed", message) + err := c.updateAppliedCondition(ctx, work, metav1.ConditionFalse, "AppliedFailed", message) if err != nil { klog.Errorf("Failed to update applied status for given work %v, namespace is %v, err is %v", work.Name, work.Namespace, err) errs = append(errs, err) @@ -217,7 +229,7 @@ func (c *Controller) syncToClusters(clusterName string, work *workv1alpha1.Work) return errors.NewAggregate(errs) } - err := c.updateAppliedCondition(work, metav1.ConditionTrue, "AppliedSuccessful", "Manifest has been successfully applied") + err := c.updateAppliedCondition(ctx, work, metav1.ConditionTrue, "AppliedSuccessful", "Manifest has been successfully applied") if err != nil { klog.Errorf("Failed to update applied status for given work %v, namespace is %v, err is %v", work.Name, work.Namespace, err) return err @@ -226,7 +238,7 @@ func (c *Controller) syncToClusters(clusterName string, work *workv1alpha1.Work) return nil } -func (c *Controller) tryCreateOrUpdateWorkload(clusterName string, workload *unstructured.Unstructured) error { +func (c *Controller) tryCreateOrUpdateWorkload(ctx context.Context, clusterName string, workload *unstructured.Unstructured) error { fedKey, err := keys.FederatedKeyFunc(clusterName, workload) if err != nil { klog.Errorf("Failed to get FederatedKey %s, error: %v", workload.GetName(), err) @@ -239,22 +251,55 @@ func (c *Controller) tryCreateOrUpdateWorkload(clusterName string, workload *uns klog.Errorf("Failed to get the resource(kind=%s, %s/%s) from member cluster(%s), err is %v ", workload.GetKind(), workload.GetNamespace(), workload.GetName(), clusterName, err) return err } - err = c.ObjectWatcher.Create(clusterName, workload) + err = c.ObjectWatcher.Create(ctx, clusterName, workload) if err != nil { return err } return nil } - err = c.ObjectWatcher.Update(clusterName, workload, clusterObj) + err = c.ObjectWatcher.Update(ctx, clusterName, workload, clusterObj) if err != nil { return err } return nil } +func (c *Controller) updateWorkDispatchingConditionIfNeeded(ctx context.Context, work *workv1alpha1.Work) error { + newWorkDispatchingCondition := metav1.Condition{ + Type: workv1alpha1.WorkDispatching, + LastTransitionTime: metav1.Now(), + } + + if helper.IsWorkSuspendDispatching(work) { + newWorkDispatchingCondition.Status = metav1.ConditionFalse + newWorkDispatchingCondition.Reason = workSuspendDispatchingConditionReason + newWorkDispatchingCondition.Message = WorkSuspendDispatchingConditionMessage + } else { + newWorkDispatchingCondition.Status = metav1.ConditionTrue + newWorkDispatchingCondition.Reason = workDispatchingConditionReason + newWorkDispatchingCondition.Message = WorkDispatchingConditionMessage + } + + if meta.IsStatusConditionPresentAndEqual(work.Status.Conditions, newWorkDispatchingCondition.Type, newWorkDispatchingCondition.Status) { + return nil + } + + if err := c.setStatusCondition(ctx, work, newWorkDispatchingCondition); err != nil { + return err + } + + obj, err := helper.ToUnstructured(work) + if err != nil { + return err + } + + c.eventf(obj, corev1.EventTypeNormal, events.EventReasonWorkDispatching, newWorkDispatchingCondition.Message) + return nil +} + // updateAppliedCondition updates the applied condition for the given Work. -func (c *Controller) updateAppliedCondition(work *workv1alpha1.Work, status metav1.ConditionStatus, reason, message string) error { +func (c *Controller) updateAppliedCondition(ctx context.Context, work *workv1alpha1.Work, status metav1.ConditionStatus, reason, message string) error { newWorkAppliedCondition := metav1.Condition{ Type: workv1alpha1.WorkApplied, Status: status, @@ -263,9 +308,13 @@ func (c *Controller) updateAppliedCondition(work *workv1alpha1.Work, status meta LastTransitionTime: metav1.Now(), } + return c.setStatusCondition(ctx, work, newWorkAppliedCondition) +} + +func (c *Controller) setStatusCondition(ctx context.Context, work *workv1alpha1.Work, statusCondition metav1.Condition) error { return retry.RetryOnConflict(retry.DefaultRetry, func() (err error) { - _, err = helper.UpdateStatus(context.Background(), c.Client, work, func() error { - meta.SetStatusCondition(&work.Status.Conditions, newWorkAppliedCondition) + _, err = helper.UpdateStatus(ctx, c.Client, work, func() error { + meta.SetStatusCondition(&work.Status.Conditions, statusCondition) return nil }) return err diff --git a/pkg/controllers/execution/execution_controller_test.go b/pkg/controllers/execution/execution_controller_test.go index d2b6bc679abb..433d52d20aae 100644 --- a/pkg/controllers/execution/execution_controller_test.go +++ b/pkg/controllers/execution/execution_controller_test.go @@ -17,55 +17,100 @@ package execution import ( "context" + "encoding/json" + "fmt" "testing" "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/uuid" + dynamicfake "k8s.io/client-go/dynamic/fake" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/tools/record" "k8s.io/utils/ptr" controllerruntime "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1" workv1alpha1 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha1" + "github.com/karmada-io/karmada/pkg/events" + "github.com/karmada-io/karmada/pkg/util" "github.com/karmada-io/karmada/pkg/util/fedinformer/genericmanager" "github.com/karmada-io/karmada/pkg/util/gclient" - "github.com/karmada-io/karmada/pkg/util/helper" + "github.com/karmada-io/karmada/pkg/util/objectwatcher" + testhelper "github.com/karmada-io/karmada/test/helper" ) func TestExecutionController_Reconcile(t *testing.T) { tests := []struct { - name string - c Controller - work *workv1alpha1.Work - ns string - expectRes controllerruntime.Result - existErr bool + name string + work *workv1alpha1.Work + ns string + expectRes controllerruntime.Result + expectCondition *metav1.Condition + expectEventMessage string + existErr bool }{ { - name: "work dispatching is suspended, no error, no apply", - c: newController(newCluster("cluster", clusterv1alpha1.ClusterConditionReady, metav1.ConditionTrue)), - work: &workv1alpha1.Work{ - ObjectMeta: metav1.ObjectMeta{ - Name: "work", - Namespace: "karmada-es-cluster", - }, - Spec: workv1alpha1.WorkSpec{ - SuspendDispatching: ptr.To(true), - }, - Status: workv1alpha1.WorkStatus{ - Conditions: []metav1.Condition{ - { - Type: workv1alpha1.WorkApplied, - Status: metav1.ConditionTrue, - }, - }, - }, - }, + name: "work dispatching is suspended, no error, no apply", + ns: "karmada-es-cluster", + expectRes: controllerruntime.Result{}, + existErr: false, + work: newWork(func(work *workv1alpha1.Work) { + work.Spec.SuspendDispatching = ptr.To(true) + }), + }, + { + name: "work dispatching is suspended, adds false dispatching condition", + ns: "karmada-es-cluster", + expectRes: controllerruntime.Result{}, + expectCondition: &metav1.Condition{Type: workv1alpha1.WorkDispatching, Status: metav1.ConditionFalse}, + existErr: false, + + work: newWork(func(w *workv1alpha1.Work) { + w.Spec.SuspendDispatching = ptr.To(true) + }), + }, + { + name: "work dispatching is suspended, adds event message", + ns: "karmada-es-cluster", + expectRes: controllerruntime.Result{}, + expectEventMessage: fmt.Sprintf("%s %s %s", corev1.EventTypeNormal, events.EventReasonWorkDispatching, WorkSuspendDispatchingConditionMessage), + existErr: false, + work: newWork(func(w *workv1alpha1.Work) { + w.Spec.SuspendDispatching = ptr.To(true) + }), + }, + { + name: "work dispatching is suspended, overwrites existing dispatching condition", + ns: "karmada-es-cluster", + expectRes: controllerruntime.Result{}, + expectCondition: &metav1.Condition{Type: workv1alpha1.WorkDispatching, Status: metav1.ConditionFalse}, + existErr: false, + work: newWork(func(w *workv1alpha1.Work) { + w.Spec.SuspendDispatching = ptr.To(true) + meta.SetStatusCondition(&w.Status.Conditions, metav1.Condition{ + Type: workv1alpha1.WorkDispatching, + Status: metav1.ConditionTrue, + Reason: workDispatchingConditionReason, + }) + }), + }, + { + name: "suspend work with deletion timestamp is deleted", ns: "karmada-es-cluster", expectRes: controllerruntime.Result{}, existErr: false, + work: newWork(func(work *workv1alpha1.Work) { + now := metav1.Now() + work.SetDeletionTimestamp(&now) + work.SetFinalizers([]string{util.ExecutionControllerFinalizer}) + work.Spec.SuspendDispatching = ptr.To(true) + }), }, } @@ -78,27 +123,58 @@ func TestExecutionController_Reconcile(t *testing.T) { }, } - if err := tt.c.Client.Create(context.Background(), tt.work); err != nil { - t.Fatalf("Failed to create cluster: %v", err) - } - - res, err := tt.c.Reconcile(context.Background(), req) + eventRecorder := record.NewFakeRecorder(1) + c := newController(tt.work, eventRecorder) + res, err := c.Reconcile(context.Background(), req) assert.Equal(t, tt.expectRes, res) if tt.existErr { - assert.NotEmpty(t, err) + assert.Error(t, err) } else { - assert.Empty(t, err) + assert.NoError(t, err) + } + + if tt.expectCondition != nil { + assert.NoError(t, c.Client.Get(context.Background(), req.NamespacedName, tt.work)) + assert.True(t, meta.IsStatusConditionPresentAndEqual(tt.work.Status.Conditions, tt.expectCondition.Type, tt.expectCondition.Status)) + } + + if tt.expectEventMessage != "" { + assert.Equal(t, 1, len(eventRecorder.Events)) + e := <-eventRecorder.Events + assert.Equal(t, tt.expectEventMessage, e) } }) } } -func newController(objects ...client.Object) Controller { +func newController(work *workv1alpha1.Work, eventRecorder *record.FakeRecorder) Controller { + cluster := newCluster("cluster", clusterv1alpha1.ClusterConditionReady, metav1.ConditionTrue) + pod := testhelper.NewPod("default", "test") + client := fake.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects(cluster, work, pod).WithStatusSubresource(work).Build() + restMapper := meta.NewDefaultRESTMapper([]schema.GroupVersion{corev1.SchemeGroupVersion}) + restMapper.Add(corev1.SchemeGroupVersion.WithKind(pod.Kind), meta.RESTScopeNamespace) + dynamicClientSet := dynamicfake.NewSimpleDynamicClient(scheme.Scheme, pod) + informerManager := genericmanager.GetInstance() + informerManager.ForCluster(cluster.Name, dynamicClientSet, 0).Lister(corev1.SchemeGroupVersion.WithResource("pods")) + informerManager.Start(cluster.Name) + informerManager.WaitForCacheSync(cluster.Name) return Controller{ - Client: fake.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects(objects...).Build(), - InformerManager: genericmanager.GetInstance(), - PredicateFunc: helper.NewClusterPredicateOnAgent("test"), + Client: client, + InformerManager: informerManager, + EventRecorder: eventRecorder, + RESTMapper: restMapper, + ObjectWatcher: objectwatcher.NewObjectWatcher(client, restMapper, util.NewClusterDynamicClientSetForAgent, nil), + } +} + +func newWork(applyFunc func(work *workv1alpha1.Work)) *workv1alpha1.Work { + pod := testhelper.NewPod("default", "test") + bytes, _ := json.Marshal(pod) + work := testhelper.NewWork("work", "karmada-es-cluster", string(uuid.NewUUID()), bytes) + if applyFunc != nil { + applyFunc(work) } + return work } func newCluster(name string, clusterType string, clusterStatus metav1.ConditionStatus) *clusterv1alpha1.Cluster { diff --git a/pkg/controllers/federatedhpa/federatedhpa_controller.go b/pkg/controllers/federatedhpa/federatedhpa_controller.go index 8d789e580cb6..0134f3351462 100644 --- a/pkg/controllers/federatedhpa/federatedhpa_controller.go +++ b/pkg/controllers/federatedhpa/federatedhpa_controller.go @@ -211,7 +211,7 @@ func (c *FHPAController) reconcileAutoscaler(ctx context.Context, hpa *autoscali if err != nil { c.EventRecorder.Event(hpa, corev1.EventTypeWarning, "FailedGetScale", err.Error()) setCondition(hpa, autoscalingv2.AbleToScale, corev1.ConditionFalse, "FailedGetScale", "the HPA controller was unable to get the target's current scale: %v", err) - if err := c.updateStatusIfNeeded(hpaStatusOriginal, hpa); err != nil { + if err := c.updateStatusIfNeeded(ctx, hpaStatusOriginal, hpa); err != nil { utilruntime.HandleError(err) } return fmt.Errorf("invalid API version in scale target reference: %v", err) @@ -225,31 +225,31 @@ func (c *FHPAController) reconcileAutoscaler(ctx context.Context, hpa *autoscali } targetResource := &unstructured.Unstructured{} targetResource.SetGroupVersionKind(targetGVK) - err = c.Get(context.TODO(), types.NamespacedName{Name: hpa.Spec.ScaleTargetRef.Name, Namespace: hpa.Namespace}, targetResource) + err = c.Get(ctx, types.NamespacedName{Name: hpa.Spec.ScaleTargetRef.Name, Namespace: hpa.Namespace}, targetResource) if err != nil { c.EventRecorder.Event(hpa, corev1.EventTypeWarning, "FailedGetScaleTargetRef", err.Error()) setCondition(hpa, autoscalingv2.AbleToScale, corev1.ConditionFalse, "FailedGetScaleTargetRef", "the HPA controller was unable to get the target reference object: %v", err) - if err := c.updateStatusIfNeeded(hpaStatusOriginal, hpa); err != nil { + if err := c.updateStatusIfNeeded(ctx, hpaStatusOriginal, hpa); err != nil { utilruntime.HandleError(err) } return fmt.Errorf("Failed to get scale target reference: %v ", err) } - binding, err := c.getBindingByLabel(targetResource.GetLabels(), hpa.Spec.ScaleTargetRef) + binding, err := c.getBindingByLabel(ctx, targetResource.GetLabels(), hpa.Spec.ScaleTargetRef) if err != nil { c.EventRecorder.Event(hpa, corev1.EventTypeWarning, "FailedGetBindings", err.Error()) setCondition(hpa, autoscalingv2.AbleToScale, corev1.ConditionFalse, "FailedGetBinding", "the HPA controller was unable to get the binding by scaleTargetRef: %v", err) - if err := c.updateStatusIfNeeded(hpaStatusOriginal, hpa); err != nil { + if err := c.updateStatusIfNeeded(ctx, hpaStatusOriginal, hpa); err != nil { utilruntime.HandleError(err) } return err } - allClusters, err := c.getTargetCluster(binding) + allClusters, err := c.getTargetCluster(ctx, binding) if err != nil { c.EventRecorder.Event(hpa, corev1.EventTypeWarning, "FailedGetTargetClusters", err.Error()) setCondition(hpa, autoscalingv2.AbleToScale, corev1.ConditionFalse, "FailedGetTargetClusters", "the HPA controller was unable to get the target clusters from binding: %v", err) - if err := c.updateStatusIfNeeded(hpaStatusOriginal, hpa); err != nil { + if err := c.updateStatusIfNeeded(ctx, hpaStatusOriginal, hpa); err != nil { utilruntime.HandleError(err) } return err @@ -259,24 +259,24 @@ func (c *FHPAController) reconcileAutoscaler(ctx context.Context, hpa *autoscali if err != nil { c.EventRecorder.Event(hpa, corev1.EventTypeWarning, "FailedGetScale", err.Error()) setCondition(hpa, autoscalingv2.AbleToScale, corev1.ConditionFalse, "FailedGetScale", "the HPA controller was unable to get the target's current scale: %v", err) - if err := c.updateStatusIfNeeded(hpaStatusOriginal, hpa); err != nil { + if err := c.updateStatusIfNeeded(ctx, hpaStatusOriginal, hpa); err != nil { utilruntime.HandleError(err) } return fmt.Errorf("unable to determine resource for scale target reference: %v", err) } - scale, podList, err := c.scaleForTargetCluster(allClusters, hpa, mapping) + scale, podList, err := c.scaleForTargetCluster(ctx, allClusters, hpa, mapping) if err != nil { c.EventRecorder.Event(hpa, corev1.EventTypeWarning, "FailedGetScale", err.Error()) setCondition(hpa, autoscalingv2.AbleToScale, corev1.ConditionFalse, "FailedGetScale", "the HPA controller was unable to get the target's current scale: %v", err) - if err := c.updateStatusIfNeeded(hpaStatusOriginal, hpa); err != nil { + if err := c.updateStatusIfNeeded(ctx, hpaStatusOriginal, hpa); err != nil { utilruntime.HandleError(err) } return fmt.Errorf("failed to query scale subresource for %s: %v", reference, err) } templateScaleObj := &unstructured.Unstructured{} - err = c.Client.SubResource("scale").Get(context.TODO(), targetResource, templateScaleObj) + err = c.Client.SubResource("scale").Get(ctx, targetResource, templateScaleObj) if err != nil { return fmt.Errorf("failed to get scale subresource for resource template %s: %v", reference, err) } @@ -330,7 +330,7 @@ func (c *FHPAController) reconcileAutoscaler(ctx context.Context, hpa *autoscali // That means some metrics still work and HPA should perform scaling based on them. if err != nil && metricDesiredReplicas == -1 { c.setCurrentReplicasInStatus(hpa, currentReplicas) - if err := c.updateStatusIfNeeded(hpaStatusOriginal, hpa); err != nil { + if err := c.updateStatusIfNeeded(ctx, hpaStatusOriginal, hpa); err != nil { utilruntime.HandleError(err) } c.EventRecorder.Event(hpa, corev1.EventTypeWarning, "FailedComputeMetricsReplicas", err.Error()) @@ -366,12 +366,12 @@ func (c *FHPAController) reconcileAutoscaler(ctx context.Context, hpa *autoscali if err = helper.ApplyReplica(templateScaleObj, int64(desiredReplicas), util.ReplicasField); err != nil { return err } - err = c.Client.SubResource("scale").Update(context.TODO(), targetResource, client.WithSubResourceBody(templateScaleObj)) + err = c.Client.SubResource("scale").Update(ctx, targetResource, client.WithSubResourceBody(templateScaleObj)) if err != nil { c.EventRecorder.Eventf(hpa, corev1.EventTypeWarning, "FailedRescale", "New size: %d; reason: %s; error: %v", desiredReplicas, rescaleReason, err.Error()) setCondition(hpa, autoscalingv2.AbleToScale, corev1.ConditionFalse, "FailedUpdateScale", "the HPA controller was unable to update the target scale: %v", err) c.setCurrentReplicasInStatus(hpa, currentReplicas) - if err := c.updateStatusIfNeeded(hpaStatusOriginal, hpa); err != nil { + if err := c.updateStatusIfNeeded(ctx, hpaStatusOriginal, hpa); err != nil { utilruntime.HandleError(err) } return fmt.Errorf("failed to rescale %s: %v", reference, err) @@ -393,7 +393,7 @@ func (c *FHPAController) reconcileAutoscaler(ctx context.Context, hpa *autoscali } c.setStatus(hpa, currentReplicas, desiredReplicas, metricStatuses, rescale) - err = c.updateStatusIfNeeded(hpaStatusOriginal, hpa) + err = c.updateStatusIfNeeded(ctx, hpaStatusOriginal, hpa) if err != nil { // we can overwrite retErr in this case because it's an internal error. return err @@ -402,7 +402,7 @@ func (c *FHPAController) reconcileAutoscaler(ctx context.Context, hpa *autoscali return retErr } -func (c *FHPAController) getBindingByLabel(resourceLabel map[string]string, resourceRef autoscalingv2.CrossVersionObjectReference) (*workv1alpha2.ResourceBinding, error) { +func (c *FHPAController) getBindingByLabel(ctx context.Context, resourceLabel map[string]string, resourceRef autoscalingv2.CrossVersionObjectReference) (*workv1alpha2.ResourceBinding, error) { if len(resourceLabel) == 0 { return nil, errors.New("target resource has no label") } @@ -422,7 +422,7 @@ func (c *FHPAController) getBindingByLabel(resourceLabel map[string]string, reso binding := &workv1alpha2.ResourceBinding{} bindingList := &workv1alpha2.ResourceBindingList{} - err := c.Client.List(context.TODO(), bindingList, &client.ListOptions{LabelSelector: selector}) + err := c.Client.List(ctx, bindingList, &client.ListOptions{LabelSelector: selector}) if err != nil { return nil, err } @@ -445,7 +445,7 @@ func (c *FHPAController) getBindingByLabel(resourceLabel map[string]string, reso return binding, nil } -func (c *FHPAController) getTargetCluster(binding *workv1alpha2.ResourceBinding) ([]string, error) { +func (c *FHPAController) getTargetCluster(ctx context.Context, binding *workv1alpha2.ResourceBinding) ([]string, error) { if len(binding.Spec.Clusters) == 0 { return nil, errors.New("binding has no schedulable clusters") } @@ -453,7 +453,7 @@ func (c *FHPAController) getTargetCluster(binding *workv1alpha2.ResourceBinding) var allClusters []string cluster := &clusterv1alpha1.Cluster{} for _, targetCluster := range binding.Spec.Clusters { - err := c.Client.Get(context.TODO(), types.NamespacedName{Name: targetCluster.Name}, cluster) + err := c.Client.Get(ctx, types.NamespacedName{Name: targetCluster.Name}, cluster) if err != nil { return nil, err } @@ -465,7 +465,7 @@ func (c *FHPAController) getTargetCluster(binding *workv1alpha2.ResourceBinding) return allClusters, nil } -func (c *FHPAController) scaleForTargetCluster(clusters []string, hpa *autoscalingv1alpha1.FederatedHPA, mapping *meta.RESTMapping) (*autoscalingv1.Scale, []*corev1.Pod, error) { +func (c *FHPAController) scaleForTargetCluster(ctx context.Context, clusters []string, hpa *autoscalingv1alpha1.FederatedHPA, mapping *meta.RESTMapping) (*autoscalingv1.Scale, []*corev1.Pod, error) { multiClusterScale := &autoscalingv1.Scale{ Spec: autoscalingv1.ScaleSpec{ Replicas: 0, @@ -491,7 +491,7 @@ func (c *FHPAController) scaleForTargetCluster(clusters []string, hpa *autoscali continue } - scale, err := clusterClient.ScaleClient.Scales(hpa.Namespace).Get(context.TODO(), targetGR, hpa.Spec.ScaleTargetRef.Name, metav1.GetOptions{}) + scale, err := clusterClient.ScaleClient.Scales(hpa.Namespace).Get(ctx, targetGR, hpa.Spec.ScaleTargetRef.Name, metav1.GetOptions{}) if err != nil { klog.Errorf("Failed to get scale subResource of resource %s in cluster %s.", hpa.Spec.ScaleTargetRef.Name, cluster) continue @@ -1356,17 +1356,17 @@ func (c *FHPAController) setStatus(hpa *autoscalingv1alpha1.FederatedHPA, curren } // updateStatusIfNeeded calls updateStatus only if the status of the new HPA is not the same as the old status -func (c *FHPAController) updateStatusIfNeeded(oldStatus *autoscalingv2.HorizontalPodAutoscalerStatus, newHPA *autoscalingv1alpha1.FederatedHPA) error { +func (c *FHPAController) updateStatusIfNeeded(ctx context.Context, oldStatus *autoscalingv2.HorizontalPodAutoscalerStatus, newHPA *autoscalingv1alpha1.FederatedHPA) error { // skip a write if we wouldn't need to update if apiequality.Semantic.DeepEqual(oldStatus, &newHPA.Status) { return nil } - return c.updateStatus(newHPA) + return c.updateStatus(ctx, newHPA) } // updateStatus actually does the update request for the status of the given HPA -func (c *FHPAController) updateStatus(hpa *autoscalingv1alpha1.FederatedHPA) error { - err := c.Status().Update(context.TODO(), hpa) +func (c *FHPAController) updateStatus(ctx context.Context, hpa *autoscalingv1alpha1.FederatedHPA) error { + err := c.Status().Update(ctx, hpa) if err != nil { c.EventRecorder.Event(hpa, corev1.EventTypeWarning, "FailedUpdateStatus", err.Error()) return fmt.Errorf("failed to update status for %s: %v", hpa.Name, err) diff --git a/pkg/controllers/federatedresourcequota/federated_resource_quota_status_controller.go b/pkg/controllers/federatedresourcequota/federated_resource_quota_status_controller.go index 23039535f0bd..4950014c080b 100644 --- a/pkg/controllers/federatedresourcequota/federated_resource_quota_status_controller.go +++ b/pkg/controllers/federatedresourcequota/federated_resource_quota_status_controller.go @@ -77,7 +77,7 @@ func (c *StatusController) Reconcile(ctx context.Context, req controllerruntime. return controllerruntime.Result{}, nil } - if err := c.collectQuotaStatus(quota); err != nil { + if err := c.collectQuotaStatus(ctx, quota); err != nil { klog.Errorf("Failed to collect status from works to federatedResourceQuota(%s), error: %v", req.NamespacedName.String(), err) c.EventRecorder.Eventf(quota, corev1.EventTypeWarning, events.EventReasonCollectFederatedResourceQuotaStatusFailed, err.Error()) return controllerruntime.Result{}, err @@ -134,8 +134,8 @@ func (c *StatusController) SetupWithManager(mgr controllerruntime.Manager) error Complete(c) } -func (c *StatusController) collectQuotaStatus(quota *policyv1alpha1.FederatedResourceQuota) error { - workList, err := helper.GetWorksByLabelsSet(c.Client, labels.Set{ +func (c *StatusController) collectQuotaStatus(ctx context.Context, quota *policyv1alpha1.FederatedResourceQuota) error { + workList, err := helper.GetWorksByLabelsSet(ctx, c.Client, labels.Set{ util.FederatedResourceQuotaNamespaceLabel: quota.Namespace, util.FederatedResourceQuotaNameLabel: quota.Name, }) @@ -160,7 +160,7 @@ func (c *StatusController) collectQuotaStatus(quota *policyv1alpha1.FederatedRes } return retry.RetryOnConflict(retry.DefaultRetry, func() error { - _, err = helper.UpdateStatus(context.Background(), c.Client, quota, func() error { + _, err = helper.UpdateStatus(ctx, c.Client, quota, func() error { quota.Status = *quotaStatus return nil }) diff --git a/pkg/controllers/federatedresourcequota/federated_resource_quota_sync_controller.go b/pkg/controllers/federatedresourcequota/federated_resource_quota_sync_controller.go index 2f0ea3cc2ebd..5e555a58b364 100644 --- a/pkg/controllers/federatedresourcequota/federated_resource_quota_sync_controller.go +++ b/pkg/controllers/federatedresourcequota/federated_resource_quota_sync_controller.go @@ -64,7 +64,7 @@ func (c *SyncController) Reconcile(ctx context.Context, req controllerruntime.Re if err := c.Client.Get(ctx, req.NamespacedName, quota); err != nil { if apierrors.IsNotFound(err) { klog.V(4).Infof("Begin to cleanup works created by federatedResourceQuota(%s)", req.NamespacedName.String()) - if err = c.cleanUpWorks(req.Namespace, req.Name); err != nil { + if err = c.cleanUpWorks(ctx, req.Namespace, req.Name); err != nil { klog.Errorf("Failed to cleanup works created by federatedResourceQuota(%s)", req.NamespacedName.String()) return controllerruntime.Result{}, err } @@ -79,7 +79,7 @@ func (c *SyncController) Reconcile(ctx context.Context, req controllerruntime.Re return controllerruntime.Result{}, err } - if err := c.buildWorks(quota, clusterList.Items); err != nil { + if err := c.buildWorks(ctx, quota, clusterList.Items); err != nil { klog.Errorf("Failed to build works for federatedResourceQuota(%s), error: %v", req.NamespacedName.String(), err) c.EventRecorder.Eventf(quota, corev1.EventTypeWarning, events.EventReasonSyncFederatedResourceQuotaFailed, err.Error()) return controllerruntime.Result{}, err @@ -92,11 +92,11 @@ func (c *SyncController) Reconcile(ctx context.Context, req controllerruntime.Re // SetupWithManager creates a controller and register to controller manager. func (c *SyncController) SetupWithManager(mgr controllerruntime.Manager) error { fn := handler.MapFunc( - func(context.Context, client.Object) []reconcile.Request { + func(ctx context.Context, _ client.Object) []reconcile.Request { var requests []reconcile.Request FederatedResourceQuotaList := &policyv1alpha1.FederatedResourceQuotaList{} - if err := c.Client.List(context.TODO(), FederatedResourceQuotaList); err != nil { + if err := c.Client.List(ctx, FederatedResourceQuotaList); err != nil { klog.Errorf("Failed to list FederatedResourceQuota, error: %v", err) } @@ -134,10 +134,10 @@ func (c *SyncController) SetupWithManager(mgr controllerruntime.Manager) error { Complete(c) } -func (c *SyncController) cleanUpWorks(namespace, name string) error { +func (c *SyncController) cleanUpWorks(ctx context.Context, namespace, name string) error { var errs []error workList := &workv1alpha1.WorkList{} - if err := c.List(context.TODO(), workList, client.MatchingLabels{ + if err := c.List(ctx, workList, client.MatchingLabels{ util.FederatedResourceQuotaNamespaceLabel: namespace, util.FederatedResourceQuotaNameLabel: name, }); err != nil { @@ -147,7 +147,7 @@ func (c *SyncController) cleanUpWorks(namespace, name string) error { for index := range workList.Items { work := &workList.Items[index] - if err := c.Delete(context.TODO(), work); err != nil && !apierrors.IsNotFound(err) { + if err := c.Delete(ctx, work); err != nil && !apierrors.IsNotFound(err) { klog.Errorf("Failed to delete work(%s): %v", klog.KObj(work).String(), err) errs = append(errs, err) } @@ -156,7 +156,7 @@ func (c *SyncController) cleanUpWorks(namespace, name string) error { return errors.NewAggregate(errs) } -func (c *SyncController) buildWorks(quota *policyv1alpha1.FederatedResourceQuota, clusters []clusterv1alpha1.Cluster) error { +func (c *SyncController) buildWorks(ctx context.Context, quota *policyv1alpha1.FederatedResourceQuota, clusters []clusterv1alpha1.Cluster) error { var errs []error for _, cluster := range clusters { resourceQuota := &corev1.ResourceQuota{} @@ -183,7 +183,7 @@ func (c *SyncController) buildWorks(quota *policyv1alpha1.FederatedResourceQuota }, } - err = helper.CreateOrUpdateWork(c.Client, objectMeta, resourceQuotaObj, nil) + err = helper.CreateOrUpdateWork(ctx, c.Client, objectMeta, resourceQuotaObj, nil) if err != nil { errs = append(errs, err) } diff --git a/pkg/controllers/gracefuleviction/crb_graceful_eviction_controller.go b/pkg/controllers/gracefuleviction/crb_graceful_eviction_controller.go index f765fe23ef75..3fac1d851bb0 100644 --- a/pkg/controllers/gracefuleviction/crb_graceful_eviction_controller.go +++ b/pkg/controllers/gracefuleviction/crb_graceful_eviction_controller.go @@ -66,7 +66,7 @@ func (c *CRBGracefulEvictionController) Reconcile(ctx context.Context, req contr return controllerruntime.Result{}, nil } - retryDuration, err := c.syncBinding(binding) + retryDuration, err := c.syncBinding(ctx, binding) if err != nil { return controllerruntime.Result{}, err } @@ -77,7 +77,7 @@ func (c *CRBGracefulEvictionController) Reconcile(ctx context.Context, req contr return controllerruntime.Result{}, nil } -func (c *CRBGracefulEvictionController) syncBinding(binding *workv1alpha2.ClusterResourceBinding) (time.Duration, error) { +func (c *CRBGracefulEvictionController) syncBinding(ctx context.Context, binding *workv1alpha2.ClusterResourceBinding) (time.Duration, error) { keptTask, evictedClusters := assessEvictionTasks(binding.Spec, binding.Status.AggregatedStatus, c.GracefulEvictionTimeout, metav1.Now()) if reflect.DeepEqual(binding.Spec.GracefulEvictionTasks, keptTask) { return nextRetry(keptTask, c.GracefulEvictionTimeout, metav1.Now().Time), nil @@ -86,7 +86,7 @@ func (c *CRBGracefulEvictionController) syncBinding(binding *workv1alpha2.Cluste objPatch := client.MergeFrom(binding) modifiedObj := binding.DeepCopy() modifiedObj.Spec.GracefulEvictionTasks = keptTask - err := c.Client.Patch(context.TODO(), modifiedObj, objPatch) + err := c.Client.Patch(ctx, modifiedObj, objPatch) if err != nil { return 0, err } diff --git a/pkg/controllers/gracefuleviction/rb_graceful_eviction_controller.go b/pkg/controllers/gracefuleviction/rb_graceful_eviction_controller.go index a1e970246b2b..0c08f3dddf1f 100644 --- a/pkg/controllers/gracefuleviction/rb_graceful_eviction_controller.go +++ b/pkg/controllers/gracefuleviction/rb_graceful_eviction_controller.go @@ -66,7 +66,7 @@ func (c *RBGracefulEvictionController) Reconcile(ctx context.Context, req contro return controllerruntime.Result{}, nil } - retryDuration, err := c.syncBinding(binding) + retryDuration, err := c.syncBinding(ctx, binding) if err != nil { return controllerruntime.Result{}, err } @@ -77,7 +77,7 @@ func (c *RBGracefulEvictionController) Reconcile(ctx context.Context, req contro return controllerruntime.Result{}, nil } -func (c *RBGracefulEvictionController) syncBinding(binding *workv1alpha2.ResourceBinding) (time.Duration, error) { +func (c *RBGracefulEvictionController) syncBinding(ctx context.Context, binding *workv1alpha2.ResourceBinding) (time.Duration, error) { keptTask, evictedCluster := assessEvictionTasks(binding.Spec, binding.Status.AggregatedStatus, c.GracefulEvictionTimeout, metav1.Now()) if reflect.DeepEqual(binding.Spec.GracefulEvictionTasks, keptTask) { return nextRetry(keptTask, c.GracefulEvictionTimeout, metav1.Now().Time), nil @@ -86,7 +86,7 @@ func (c *RBGracefulEvictionController) syncBinding(binding *workv1alpha2.Resourc objPatch := client.MergeFrom(binding) modifiedObj := binding.DeepCopy() modifiedObj.Spec.GracefulEvictionTasks = keptTask - err := c.Client.Patch(context.TODO(), modifiedObj, objPatch) + err := c.Client.Patch(ctx, modifiedObj, objPatch) if err != nil { return 0, err } diff --git a/pkg/controllers/hpascaletargetmarker/hpa_scale_target_marker_controller.go b/pkg/controllers/hpascaletargetmarker/hpa_scale_target_marker_controller.go index df96a7b6eab4..c066b3321eeb 100644 --- a/pkg/controllers/hpascaletargetmarker/hpa_scale_target_marker_controller.go +++ b/pkg/controllers/hpascaletargetmarker/hpa_scale_target_marker_controller.go @@ -35,7 +35,7 @@ const ( scaleTargetWorkerNum = 1 ) -// HpaScaleTargetMarker is to automatically add `retain-replicas` label to resource template mananged by HPA. +// HpaScaleTargetMarker is to automatically add `retain-replicas` label to resource template managed by HPA. type HpaScaleTargetMarker struct { DynamicClient dynamic.Interface RESTMapper meta.RESTMapper diff --git a/pkg/controllers/mcs/endpointslice_controller.go b/pkg/controllers/mcs/endpointslice_controller.go index d63ce47e7c3c..a65daa57b591 100644 --- a/pkg/controllers/mcs/endpointslice_controller.go +++ b/pkg/controllers/mcs/endpointslice_controller.go @@ -63,37 +63,37 @@ func (c *EndpointSliceController) Reconcile(ctx context.Context, req controllerr if !work.DeletionTimestamp.IsZero() { // Clean up derived EndpointSlices when deleting the work. - if err := helper.DeleteEndpointSlice(c.Client, labels.Set{ + if err := helper.DeleteEndpointSlice(ctx, c.Client, labels.Set{ workv1alpha2.WorkPermanentIDLabel: work.Labels[workv1alpha2.WorkPermanentIDLabel], }); err != nil { klog.Errorf("Failed to delete endpointslice of the work(%s/%s) when deleting the work, err is %v", work.Namespace, work.Name, err) return controllerruntime.Result{}, err } - return controllerruntime.Result{}, c.removeFinalizer(work.DeepCopy()) + return controllerruntime.Result{}, c.removeFinalizer(ctx, work.DeepCopy()) } // TBD: The work is managed by service-export-controller and endpointslice-collect-controller now, // after the ServiceExport is deleted, the corresponding works' labels will be cleaned, so we should delete the EndpointSlice in control plane. // Once the conflict between service_export_controller.go and endpointslice_collect_controller.go is fixed, the following code should be deleted. if serviceName := util.GetLabelValue(work.Labels, util.ServiceNameLabel); serviceName == "" { - err := helper.DeleteEndpointSlice(c.Client, labels.Set{ + err := helper.DeleteEndpointSlice(ctx, c.Client, labels.Set{ workv1alpha2.WorkPermanentIDLabel: work.Labels[workv1alpha2.WorkPermanentIDLabel], }) if err != nil { klog.Errorf("Failed to delete endpointslice of the work(%s/%s) when the serviceexport is deleted, err is %v", work.Namespace, work.Name, err) return controllerruntime.Result{}, err } - return controllerruntime.Result{}, c.removeFinalizer(work.DeepCopy()) + return controllerruntime.Result{}, c.removeFinalizer(ctx, work.DeepCopy()) } - return controllerruntime.Result{}, c.collectEndpointSliceFromWork(work) + return controllerruntime.Result{}, c.collectEndpointSliceFromWork(ctx, work) } -func (c *EndpointSliceController) removeFinalizer(work *workv1alpha1.Work) error { +func (c *EndpointSliceController) removeFinalizer(ctx context.Context, work *workv1alpha1.Work) error { if !controllerutil.RemoveFinalizer(work, util.EndpointSliceControllerFinalizer) { return nil } - return c.Client.Update(context.TODO(), work) + return c.Client.Update(ctx, work) } // SetupWithManager creates a controller and register to controller manager. @@ -118,7 +118,7 @@ func (c *EndpointSliceController) SetupWithManager(mgr controllerruntime.Manager return controllerruntime.NewControllerManagedBy(mgr).For(&workv1alpha1.Work{}, builder.WithPredicates(serviceImportPredicateFun)).Complete(c) } -func (c *EndpointSliceController) collectEndpointSliceFromWork(work *workv1alpha1.Work) error { +func (c *EndpointSliceController) collectEndpointSliceFromWork(ctx context.Context, work *workv1alpha1.Work) error { clusterName, err := names.GetClusterName(work.Namespace) if err != nil { klog.Errorf("Failed to get cluster name for work %s/%s", work.Namespace, work.Name) @@ -149,7 +149,7 @@ func (c *EndpointSliceController) collectEndpointSliceFromWork(work *workv1alpha workv1alpha2.WorkNameAnnotation: work.Name, }) - if err = helper.CreateOrUpdateEndpointSlice(c.Client, desiredEndpointSlice); err != nil { + if err = helper.CreateOrUpdateEndpointSlice(ctx, c.Client, desiredEndpointSlice); err != nil { return err } } diff --git a/pkg/controllers/mcs/service_export_controller.go b/pkg/controllers/mcs/service_export_controller.go index 02207bef1e6d..b9a03200d0c7 100644 --- a/pkg/controllers/mcs/service_export_controller.go +++ b/pkg/controllers/mcs/service_export_controller.go @@ -192,6 +192,7 @@ func (c *ServiceExportController) enqueueReportedEpsServiceExport() { } func (c *ServiceExportController) syncServiceExportOrEndpointSlice(key util.QueueKey) error { + ctx := context.Background() fedKey, ok := key.(keys.FederatedKey) if !ok { klog.Errorf("Failed to sync serviceExport as invalid key: %v", key) @@ -202,13 +203,13 @@ func (c *ServiceExportController) syncServiceExportOrEndpointSlice(key util.Queu switch fedKey.Kind { case util.ServiceExportKind: - if err := c.handleServiceExportEvent(fedKey); err != nil { + if err := c.handleServiceExportEvent(ctx, fedKey); err != nil { klog.Errorf("Failed to handle serviceExport(%s) event, Error: %v", fedKey.NamespaceKey(), err) return err } case util.EndpointSliceKind: - if err := c.handleEndpointSliceEvent(fedKey); err != nil { + if err := c.handleEndpointSliceEvent(ctx, fedKey); err != nil { klog.Errorf("Failed to handle endpointSlice(%s) event, Error: %v", fedKey.NamespaceKey(), err) return err @@ -338,11 +339,11 @@ func (c *ServiceExportController) genHandlerDeleteFunc(clusterName string) func( // handleServiceExportEvent syncs EndPointSlice objects to control-plane according to ServiceExport event. // For ServiceExport create or update event, reports the referencing service's EndpointSlice. // For ServiceExport delete event, cleanup the previously reported EndpointSlice. -func (c *ServiceExportController) handleServiceExportEvent(serviceExportKey keys.FederatedKey) error { +func (c *ServiceExportController) handleServiceExportEvent(ctx context.Context, serviceExportKey keys.FederatedKey) error { _, err := helper.GetObjectFromCache(c.RESTMapper, c.InformerManager, serviceExportKey) if err != nil { if apierrors.IsNotFound(err) { - return cleanupWorkWithServiceExportDelete(c.Client, serviceExportKey) + return cleanupWorkWithServiceExportDelete(ctx, c.Client, serviceExportKey) } return err } @@ -351,7 +352,7 @@ func (c *ServiceExportController) handleServiceExportEvent(serviceExportKey keys // be redundant, but it helps to avoid a corner case: // If skip report here, after ServiceExport deletion and re-creation, if no EndpointSlice changes, we didn't get a // change to sync. - if err = c.reportEndpointSliceWithServiceExportCreate(serviceExportKey); err != nil { + if err = c.reportEndpointSliceWithServiceExportCreate(ctx, serviceExportKey); err != nil { klog.Errorf("Failed to handle ServiceExport(%s) event, Error: %v", serviceExportKey.NamespaceKey(), err) return err @@ -363,16 +364,16 @@ func (c *ServiceExportController) handleServiceExportEvent(serviceExportKey keys // handleEndpointSliceEvent syncs EndPointSlice objects to control-plane according to EndpointSlice event. // For EndpointSlice create or update event, reports the EndpointSlice when referencing service has been exported. // For EndpointSlice delete event, cleanup the previously reported EndpointSlice. -func (c *ServiceExportController) handleEndpointSliceEvent(endpointSliceKey keys.FederatedKey) error { +func (c *ServiceExportController) handleEndpointSliceEvent(ctx context.Context, endpointSliceKey keys.FederatedKey) error { endpointSliceObj, err := helper.GetObjectFromCache(c.RESTMapper, c.InformerManager, endpointSliceKey) if err != nil { if apierrors.IsNotFound(err) { - return cleanupWorkWithEndpointSliceDelete(c.Client, endpointSliceKey) + return cleanupWorkWithEndpointSliceDelete(ctx, c.Client, endpointSliceKey) } return err } - if err = c.reportEndpointSliceWithEndpointSliceCreateOrUpdate(endpointSliceKey.Cluster, endpointSliceObj); err != nil { + if err = c.reportEndpointSliceWithEndpointSliceCreateOrUpdate(ctx, endpointSliceKey.Cluster, endpointSliceObj); err != nil { klog.Errorf("Failed to handle endpointSlice(%s) event, Error: %v", endpointSliceKey.NamespaceKey(), err) return err @@ -382,7 +383,7 @@ func (c *ServiceExportController) handleEndpointSliceEvent(endpointSliceKey keys } // reportEndpointSliceWithServiceExportCreate reports the referencing service's EndpointSlice. -func (c *ServiceExportController) reportEndpointSliceWithServiceExportCreate(serviceExportKey keys.FederatedKey) error { +func (c *ServiceExportController) reportEndpointSliceWithServiceExportCreate(ctx context.Context, serviceExportKey keys.FederatedKey) error { var ( endpointSliceObjects []runtime.Object err error @@ -401,20 +402,20 @@ func (c *ServiceExportController) reportEndpointSliceWithServiceExportCreate(ser return err } - err = c.removeOrphanWork(endpointSliceObjects, serviceExportKey) + err = c.removeOrphanWork(ctx, endpointSliceObjects, serviceExportKey) if err != nil { return err } for index := range endpointSliceObjects { - if err = reportEndpointSlice(c.Client, endpointSliceObjects[index].(*unstructured.Unstructured), serviceExportKey.Cluster); err != nil { + if err = reportEndpointSlice(ctx, c.Client, endpointSliceObjects[index].(*unstructured.Unstructured), serviceExportKey.Cluster); err != nil { errs = append(errs, err) } } return utilerrors.NewAggregate(errs) } -func (c *ServiceExportController) removeOrphanWork(endpointSliceObjects []runtime.Object, serviceExportKey keys.FederatedKey) error { +func (c *ServiceExportController) removeOrphanWork(ctx context.Context, endpointSliceObjects []runtime.Object, serviceExportKey keys.FederatedKey) error { willReportWorks := sets.NewString() for index := range endpointSliceObjects { endpointSlice := endpointSliceObjects[index].(*unstructured.Unstructured) @@ -423,7 +424,7 @@ func (c *ServiceExportController) removeOrphanWork(endpointSliceObjects []runtim } collectedEpsWorkList := &workv1alpha1.WorkList{} - if err := c.List(context.TODO(), collectedEpsWorkList, &client.ListOptions{ + if err := c.List(ctx, collectedEpsWorkList, &client.ListOptions{ Namespace: names.GenerateExecutionSpaceName(serviceExportKey.Cluster), LabelSelector: labels.SelectorFromSet(labels.Set{ util.PropagationInstruction: util.PropagationInstructionSuppressed, @@ -452,7 +453,7 @@ func (c *ServiceExportController) removeOrphanWork(endpointSliceObjects []runtim continue } - err := cleanEndpointSliceWork(c.Client, &work) + err := cleanEndpointSliceWork(ctx, c.Client, &work) if err != nil { errs = append(errs, err) } @@ -461,7 +462,7 @@ func (c *ServiceExportController) removeOrphanWork(endpointSliceObjects []runtim } // reportEndpointSliceWithEndpointSliceCreateOrUpdate reports the EndpointSlice when referencing service has been exported. -func (c *ServiceExportController) reportEndpointSliceWithEndpointSliceCreateOrUpdate(clusterName string, endpointSlice *unstructured.Unstructured) error { +func (c *ServiceExportController) reportEndpointSliceWithEndpointSliceCreateOrUpdate(ctx context.Context, clusterName string, endpointSlice *unstructured.Unstructured) error { relatedServiceName := endpointSlice.GetLabels()[discoveryv1.LabelServiceName] singleClusterManager := c.InformerManager.GetSingleClusterManager(clusterName) @@ -480,30 +481,30 @@ func (c *ServiceExportController) reportEndpointSliceWithEndpointSliceCreateOrUp return err } - return reportEndpointSlice(c.Client, endpointSlice, clusterName) + return reportEndpointSlice(ctx, c.Client, endpointSlice, clusterName) } // reportEndpointSlice report EndPointSlice objects to control-plane. -func reportEndpointSlice(c client.Client, endpointSlice *unstructured.Unstructured, clusterName string) error { +func reportEndpointSlice(ctx context.Context, c client.Client, endpointSlice *unstructured.Unstructured, clusterName string) error { executionSpace := names.GenerateExecutionSpaceName(clusterName) workName := names.GenerateWorkName(endpointSlice.GetKind(), endpointSlice.GetName(), endpointSlice.GetNamespace()) - workMeta, err := getEndpointSliceWorkMeta(c, executionSpace, workName, endpointSlice) + workMeta, err := getEndpointSliceWorkMeta(ctx, c, executionSpace, workName, endpointSlice) if err != nil { return err } - if err := helper.CreateOrUpdateWork(c, workMeta, endpointSlice, nil); err != nil { + if err := helper.CreateOrUpdateWork(ctx, c, workMeta, endpointSlice, nil); err != nil { return err } return nil } -func getEndpointSliceWorkMeta(c client.Client, ns string, workName string, endpointSlice *unstructured.Unstructured) (metav1.ObjectMeta, error) { +func getEndpointSliceWorkMeta(ctx context.Context, c client.Client, ns string, workName string, endpointSlice *unstructured.Unstructured) (metav1.ObjectMeta, error) { existWork := &workv1alpha1.Work{} var err error - if err = c.Get(context.Background(), types.NamespacedName{ + if err = c.Get(ctx, types.NamespacedName{ Namespace: ns, Name: workName, }, existWork); err != nil && !apierrors.IsNotFound(err) { @@ -538,11 +539,11 @@ func getEndpointSliceWorkMeta(c client.Client, ns string, workName string, endpo return workMeta, nil } -func cleanupWorkWithServiceExportDelete(c client.Client, serviceExportKey keys.FederatedKey) error { +func cleanupWorkWithServiceExportDelete(ctx context.Context, c client.Client, serviceExportKey keys.FederatedKey) error { executionSpace := names.GenerateExecutionSpaceName(serviceExportKey.Cluster) workList := &workv1alpha1.WorkList{} - if err := c.List(context.TODO(), workList, &client.ListOptions{ + if err := c.List(ctx, workList, &client.ListOptions{ Namespace: executionSpace, LabelSelector: labels.SelectorFromSet(labels.Set{ util.ServiceNamespaceLabel: serviceExportKey.Namespace, @@ -556,14 +557,14 @@ func cleanupWorkWithServiceExportDelete(c client.Client, serviceExportKey keys.F var errs []error for _, work := range workList.Items { - if err := cleanEndpointSliceWork(c, work.DeepCopy()); err != nil { + if err := cleanEndpointSliceWork(ctx, c, work.DeepCopy()); err != nil { errs = append(errs, err) } } return utilerrors.NewAggregate(errs) } -func cleanupWorkWithEndpointSliceDelete(c client.Client, endpointSliceKey keys.FederatedKey) error { +func cleanupWorkWithEndpointSliceDelete(ctx context.Context, c client.Client, endpointSliceKey keys.FederatedKey) error { executionSpace := names.GenerateExecutionSpaceName(endpointSliceKey.Cluster) workNamespaceKey := types.NamespacedName{ @@ -571,7 +572,7 @@ func cleanupWorkWithEndpointSliceDelete(c client.Client, endpointSliceKey keys.F Name: names.GenerateWorkName(endpointSliceKey.Kind, endpointSliceKey.Name, endpointSliceKey.Namespace), } work := &workv1alpha1.Work{} - if err := c.Get(context.TODO(), workNamespaceKey, work); err != nil { + if err := c.Get(ctx, workNamespaceKey, work); err != nil { if apierrors.IsNotFound(err) { return nil } @@ -580,14 +581,14 @@ func cleanupWorkWithEndpointSliceDelete(c client.Client, endpointSliceKey keys.F return err } - return cleanEndpointSliceWork(c, work.DeepCopy()) + return cleanEndpointSliceWork(ctx, c, work.DeepCopy()) } // TBD: Currently, the EndpointSlice work can be handled by both service-export-controller and endpointslice-collect-controller. To indicate this, we've introduced the label endpointslice.karmada.io/managed-by. Therefore, // if managed by both controllers, simply remove each controller's respective labels. // If managed solely by its own controller, delete the work accordingly. // This logic should be deleted after the conflict is fixed. -func cleanEndpointSliceWork(c client.Client, work *workv1alpha1.Work) error { +func cleanEndpointSliceWork(ctx context.Context, c client.Client, work *workv1alpha1.Work) error { controllers := util.GetLabelValue(work.Labels, util.EndpointSliceWorkManagedByLabel) controllerSet := sets.New[string]() controllerSet.Insert(strings.Split(controllers, ".")...) @@ -597,14 +598,14 @@ func cleanEndpointSliceWork(c client.Client, work *workv1alpha1.Work) error { delete(work.Labels, util.ServiceNamespaceLabel) work.Labels[util.EndpointSliceWorkManagedByLabel] = strings.Join(controllerSet.UnsortedList(), ".") - if err := c.Update(context.TODO(), work); err != nil { + if err := c.Update(ctx, work); err != nil { klog.Errorf("Failed to update work(%s/%s): %v", work.Namespace, work.Name, err) return err } return nil } - if err := c.Delete(context.TODO(), work); err != nil { + if err := c.Delete(ctx, work); err != nil { klog.Errorf("Failed to delete work(%s/%s), Error: %v", work.Namespace, work.Name, err) return err } diff --git a/pkg/controllers/mcs/service_import_controller.go b/pkg/controllers/mcs/service_import_controller.go index cde4cbe41e39..9e7c96c9ac6e 100644 --- a/pkg/controllers/mcs/service_import_controller.go +++ b/pkg/controllers/mcs/service_import_controller.go @@ -51,7 +51,7 @@ func (c *ServiceImportController) Reconcile(ctx context.Context, req controllerr svcImport := &mcsv1alpha1.ServiceImport{} if err := c.Client.Get(ctx, req.NamespacedName, svcImport); err != nil { if apierrors.IsNotFound(err) { - return c.deleteDerivedService(req.NamespacedName) + return c.deleteDerivedService(ctx, req.NamespacedName) } return controllerruntime.Result{}, err @@ -61,7 +61,7 @@ func (c *ServiceImportController) Reconcile(ctx context.Context, req controllerr return controllerruntime.Result{}, nil } - if err := c.deriveServiceFromServiceImport(svcImport); err != nil { + if err := c.deriveServiceFromServiceImport(ctx, svcImport); err != nil { c.EventRecorder.Eventf(svcImport, corev1.EventTypeWarning, events.EventReasonSyncDerivedServiceFailed, err.Error()) return controllerruntime.Result{}, err } @@ -74,13 +74,13 @@ func (c *ServiceImportController) SetupWithManager(mgr controllerruntime.Manager return controllerruntime.NewControllerManagedBy(mgr).For(&mcsv1alpha1.ServiceImport{}).Complete(c) } -func (c *ServiceImportController) deleteDerivedService(svcImport types.NamespacedName) (controllerruntime.Result, error) { +func (c *ServiceImportController) deleteDerivedService(ctx context.Context, svcImport types.NamespacedName) (controllerruntime.Result, error) { derivedSvc := &corev1.Service{} derivedSvcNamespacedName := types.NamespacedName{ Namespace: svcImport.Namespace, Name: names.GenerateDerivedServiceName(svcImport.Name), } - err := c.Client.Get(context.TODO(), derivedSvcNamespacedName, derivedSvc) + err := c.Client.Get(ctx, derivedSvcNamespacedName, derivedSvc) if err != nil { if apierrors.IsNotFound(err) { return controllerruntime.Result{}, nil @@ -89,7 +89,7 @@ func (c *ServiceImportController) deleteDerivedService(svcImport types.Namespace return controllerruntime.Result{}, err } - err = c.Client.Delete(context.TODO(), derivedSvc) + err = c.Client.Delete(ctx, derivedSvc) if err != nil && !apierrors.IsNotFound(err) { klog.Errorf("Delete derived service(%s) failed, Error: %v", derivedSvcNamespacedName, err) return controllerruntime.Result{}, err @@ -98,7 +98,7 @@ func (c *ServiceImportController) deleteDerivedService(svcImport types.Namespace return controllerruntime.Result{}, nil } -func (c *ServiceImportController) deriveServiceFromServiceImport(svcImport *mcsv1alpha1.ServiceImport) error { +func (c *ServiceImportController) deriveServiceFromServiceImport(ctx context.Context, svcImport *mcsv1alpha1.ServiceImport) error { newDerivedService := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ Namespace: svcImport.Namespace, @@ -111,18 +111,18 @@ func (c *ServiceImportController) deriveServiceFromServiceImport(svcImport *mcsv } oldDerivedService := &corev1.Service{} - err := c.Client.Get(context.TODO(), types.NamespacedName{ + err := c.Client.Get(ctx, types.NamespacedName{ Name: names.GenerateDerivedServiceName(svcImport.Name), Namespace: svcImport.Namespace, }, oldDerivedService) if err != nil { if apierrors.IsNotFound(err) { - if err = c.Client.Create(context.TODO(), newDerivedService); err != nil { + if err = c.Client.Create(ctx, newDerivedService); err != nil { klog.Errorf("Create derived service(%s/%s) failed, Error: %v", newDerivedService.Namespace, newDerivedService.Name, err) return err } - return c.updateServiceStatus(svcImport, newDerivedService) + return c.updateServiceStatus(ctx, svcImport, newDerivedService) } return err @@ -131,17 +131,17 @@ func (c *ServiceImportController) deriveServiceFromServiceImport(svcImport *mcsv // retain necessary fields with old service retainServiceFields(oldDerivedService, newDerivedService) - err = c.Client.Update(context.TODO(), newDerivedService) + err = c.Client.Update(ctx, newDerivedService) if err != nil { klog.Errorf("Update derived service(%s/%s) failed, Error: %v", newDerivedService.Namespace, newDerivedService.Name, err) return err } - return c.updateServiceStatus(svcImport, newDerivedService) + return c.updateServiceStatus(ctx, svcImport, newDerivedService) } // updateServiceStatus update loadbalanacer status with provided clustersetIPs -func (c *ServiceImportController) updateServiceStatus(svcImport *mcsv1alpha1.ServiceImport, derivedService *corev1.Service) error { +func (c *ServiceImportController) updateServiceStatus(ctx context.Context, svcImport *mcsv1alpha1.ServiceImport, derivedService *corev1.Service) error { ingress := make([]corev1.LoadBalancerIngress, 0) for _, ip := range svcImport.Spec.IPs { ingress = append(ingress, corev1.LoadBalancerIngress{ @@ -150,7 +150,7 @@ func (c *ServiceImportController) updateServiceStatus(svcImport *mcsv1alpha1.Ser } err := retry.RetryOnConflict(retry.DefaultRetry, func() (err error) { - _, err = helper.UpdateStatus(context.Background(), c.Client, derivedService, func() error { + _, err = helper.UpdateStatus(ctx, c.Client, derivedService, func() error { derivedService.Status = corev1.ServiceStatus{ LoadBalancer: corev1.LoadBalancerStatus{ Ingress: ingress, diff --git a/pkg/controllers/multiclusterservice/endpointslice_collect_controller.go b/pkg/controllers/multiclusterservice/endpointslice_collect_controller.go index bac9792936e5..c326723d6774 100644 --- a/pkg/controllers/multiclusterservice/endpointslice_collect_controller.go +++ b/pkg/controllers/multiclusterservice/endpointslice_collect_controller.go @@ -105,7 +105,7 @@ func (c *EndpointSliceCollectController) Reconcile(ctx context.Context, req cont return controllerruntime.Result{}, err } - if err = c.collectTargetEndpointSlice(work, clusterName); err != nil { + if err = c.collectTargetEndpointSlice(ctx, work, clusterName); err != nil { return controllerruntime.Result{}, err } @@ -130,6 +130,7 @@ func (c *EndpointSliceCollectController) RunWorkQueue() { } func (c *EndpointSliceCollectController) collectEndpointSlice(key util.QueueKey) error { + ctx := context.Background() fedKey, ok := key.(keys.FederatedKey) if !ok { klog.Errorf("Failed to collect endpointslice as invalid key: %v", key) @@ -137,7 +138,7 @@ func (c *EndpointSliceCollectController) collectEndpointSlice(key util.QueueKey) } klog.V(4).Infof("Begin to collect %s %s.", fedKey.Kind, fedKey.NamespaceKey()) - if err := c.handleEndpointSliceEvent(fedKey); err != nil { + if err := c.handleEndpointSliceEvent(ctx, fedKey); err != nil { klog.Errorf("Failed to handle endpointSlice(%s) event, Error: %v", fedKey.NamespaceKey(), err) return err @@ -276,11 +277,11 @@ func (c *EndpointSliceCollectController) genHandlerDeleteFunc(clusterName string // handleEndpointSliceEvent syncs EndPointSlice objects to control-plane according to EndpointSlice event. // For EndpointSlice create or update event, reports the EndpointSlice when referencing service has been exported. // For EndpointSlice delete event, cleanup the previously reported EndpointSlice. -func (c *EndpointSliceCollectController) handleEndpointSliceEvent(endpointSliceKey keys.FederatedKey) error { +func (c *EndpointSliceCollectController) handleEndpointSliceEvent(ctx context.Context, endpointSliceKey keys.FederatedKey) error { endpointSliceObj, err := helper.GetObjectFromCache(c.RESTMapper, c.InformerManager, endpointSliceKey) if err != nil { if apierrors.IsNotFound(err) { - return cleanupWorkWithEndpointSliceDelete(c.Client, endpointSliceKey) + return cleanupWorkWithEndpointSliceDelete(ctx, c.Client, endpointSliceKey) } return err } @@ -290,7 +291,7 @@ func (c *EndpointSliceCollectController) handleEndpointSliceEvent(endpointSliceK } workList := &workv1alpha1.WorkList{} - if err := c.Client.List(context.TODO(), workList, &client.ListOptions{ + if err := c.Client.List(ctx, workList, &client.ListOptions{ Namespace: names.GenerateExecutionSpaceName(endpointSliceKey.Cluster), LabelSelector: labels.SelectorFromSet(labels.Set{ util.MultiClusterServiceNamespaceLabel: endpointSliceKey.Namespace, @@ -311,7 +312,7 @@ func (c *EndpointSliceCollectController) handleEndpointSliceEvent(endpointSliceK return nil } - if err = c.reportEndpointSliceWithEndpointSliceCreateOrUpdate(endpointSliceKey.Cluster, endpointSliceObj); err != nil { + if err = c.reportEndpointSliceWithEndpointSliceCreateOrUpdate(ctx, endpointSliceKey.Cluster, endpointSliceObj); err != nil { klog.Errorf("Failed to handle endpointSlice(%s) event, Error: %v", endpointSliceKey.NamespaceKey(), err) return err @@ -320,7 +321,7 @@ func (c *EndpointSliceCollectController) handleEndpointSliceEvent(endpointSliceK return nil } -func (c *EndpointSliceCollectController) collectTargetEndpointSlice(work *workv1alpha1.Work, clusterName string) error { +func (c *EndpointSliceCollectController) collectTargetEndpointSlice(ctx context.Context, work *workv1alpha1.Work, clusterName string) error { manager := c.InformerManager.GetSingleClusterManager(clusterName) if manager == nil { err := fmt.Errorf("failed to get informer manager for cluster %s", clusterName) @@ -352,7 +353,7 @@ func (c *EndpointSliceCollectController) collectTargetEndpointSlice(work *workv1 klog.Errorf("Failed to convert EndpointSlice %s/%s to unstructured, error: %v", eps.GetNamespace(), eps.GetName(), err) return err } - if err = c.reportEndpointSliceWithEndpointSliceCreateOrUpdate(clusterName, epsUnstructured); err != nil { + if err = c.reportEndpointSliceWithEndpointSliceCreateOrUpdate(ctx, clusterName, epsUnstructured); err != nil { return err } } @@ -361,8 +362,8 @@ func (c *EndpointSliceCollectController) collectTargetEndpointSlice(work *workv1 } // reportEndpointSliceWithEndpointSliceCreateOrUpdate reports the EndpointSlice when referencing service has been exported. -func (c *EndpointSliceCollectController) reportEndpointSliceWithEndpointSliceCreateOrUpdate(clusterName string, endpointSlice *unstructured.Unstructured) error { - if err := reportEndpointSlice(c.Client, endpointSlice, clusterName); err != nil { +func (c *EndpointSliceCollectController) reportEndpointSliceWithEndpointSliceCreateOrUpdate(ctx context.Context, clusterName string, endpointSlice *unstructured.Unstructured) error { + if err := reportEndpointSlice(ctx, c.Client, endpointSlice, clusterName); err != nil { return fmt.Errorf("failed to report EndpointSlice(%s/%s) from cluster(%s) to control-plane", endpointSlice.GetNamespace(), endpointSlice.GetName(), clusterName) } @@ -371,16 +372,16 @@ func (c *EndpointSliceCollectController) reportEndpointSliceWithEndpointSliceCre } // reportEndpointSlice report EndPointSlice objects to control-plane. -func reportEndpointSlice(c client.Client, endpointSlice *unstructured.Unstructured, clusterName string) error { +func reportEndpointSlice(ctx context.Context, c client.Client, endpointSlice *unstructured.Unstructured, clusterName string) error { executionSpace := names.GenerateExecutionSpaceName(clusterName) workName := names.GenerateWorkName(endpointSlice.GetKind(), endpointSlice.GetName(), endpointSlice.GetNamespace()) - workMeta, err := getEndpointSliceWorkMeta(c, executionSpace, workName, endpointSlice) + workMeta, err := getEndpointSliceWorkMeta(ctx, c, executionSpace, workName, endpointSlice) if err != nil { return err } - if err := helper.CreateOrUpdateWork(c, workMeta, endpointSlice, nil); err != nil { + if err := helper.CreateOrUpdateWork(ctx, c, workMeta, endpointSlice, nil); err != nil { klog.Errorf("Failed to create or update work(%s/%s), Error: %v", workMeta.Namespace, workMeta.Name, err) return err } @@ -388,10 +389,10 @@ func reportEndpointSlice(c client.Client, endpointSlice *unstructured.Unstructur return nil } -func getEndpointSliceWorkMeta(c client.Client, ns string, workName string, endpointSlice *unstructured.Unstructured) (metav1.ObjectMeta, error) { +func getEndpointSliceWorkMeta(ctx context.Context, c client.Client, ns string, workName string, endpointSlice *unstructured.Unstructured) (metav1.ObjectMeta, error) { existWork := &workv1alpha1.Work{} var err error - if err = c.Get(context.Background(), types.NamespacedName{ + if err = c.Get(ctx, types.NamespacedName{ Namespace: ns, Name: workName, }, existWork); err != nil && !apierrors.IsNotFound(err) { @@ -426,7 +427,7 @@ func getEndpointSliceWorkMeta(c client.Client, ns string, workName string, endpo }, nil } -func cleanupWorkWithEndpointSliceDelete(c client.Client, endpointSliceKey keys.FederatedKey) error { +func cleanupWorkWithEndpointSliceDelete(ctx context.Context, c client.Client, endpointSliceKey keys.FederatedKey) error { executionSpace := names.GenerateExecutionSpaceName(endpointSliceKey.Cluster) workNamespaceKey := types.NamespacedName{ @@ -434,7 +435,7 @@ func cleanupWorkWithEndpointSliceDelete(c client.Client, endpointSliceKey keys.F Name: names.GenerateWorkName(endpointSliceKey.Kind, endpointSliceKey.Name, endpointSliceKey.Namespace), } work := &workv1alpha1.Work{} - if err := c.Get(context.TODO(), workNamespaceKey, work); err != nil { + if err := c.Get(ctx, workNamespaceKey, work); err != nil { if apierrors.IsNotFound(err) { return nil } @@ -442,7 +443,7 @@ func cleanupWorkWithEndpointSliceDelete(c client.Client, endpointSliceKey keys.F return err } - return cleanProviderClustersEndpointSliceWork(c, work.DeepCopy()) + return cleanProviderClustersEndpointSliceWork(ctx, c, work.DeepCopy()) } // TBD: Currently, the EndpointSlice work can be handled by both service-export-controller and endpointslice-collect-controller. @@ -450,7 +451,7 @@ func cleanupWorkWithEndpointSliceDelete(c client.Client, endpointSliceKey keys.F // if managed by both controllers, simply remove each controller's respective labels. // If managed solely by its own controller, delete the work accordingly. // This logic should be deleted after the conflict is fixed. -func cleanProviderClustersEndpointSliceWork(c client.Client, work *workv1alpha1.Work) error { +func cleanProviderClustersEndpointSliceWork(ctx context.Context, c client.Client, work *workv1alpha1.Work) error { controllers := util.GetLabelValue(work.Labels, util.EndpointSliceWorkManagedByLabel) controllerSet := sets.New[string]() controllerSet.Insert(strings.Split(controllers, ".")...) @@ -460,14 +461,14 @@ func cleanProviderClustersEndpointSliceWork(c client.Client, work *workv1alpha1. delete(work.Labels, util.MultiClusterServiceNamespaceLabel) work.Labels[util.EndpointSliceWorkManagedByLabel] = strings.Join(controllerSet.UnsortedList(), ".") - if err := c.Update(context.TODO(), work); err != nil { + if err := c.Update(ctx, work); err != nil { klog.Errorf("Failed to update work(%s/%s): %v", work.Namespace, work.Name, err) return err } return nil } - if err := c.Delete(context.TODO(), work); err != nil { + if err := c.Delete(ctx, work); err != nil { klog.Errorf("Failed to delete work(%s/%s): %v", work.Namespace, work.Name, err) return err } diff --git a/pkg/controllers/multiclusterservice/endpointslice_dispatch_controller.go b/pkg/controllers/multiclusterservice/endpointslice_dispatch_controller.go index 905029bc1791..85a1d96c88c3 100644 --- a/pkg/controllers/multiclusterservice/endpointslice_dispatch_controller.go +++ b/pkg/controllers/multiclusterservice/endpointslice_dispatch_controller.go @@ -98,11 +98,11 @@ func (c *EndpointsliceDispatchController) Reconcile(ctx context.Context, req con var err error defer func() { if err != nil { - _ = c.updateEndpointSliceDispatched(mcs, metav1.ConditionFalse, "EndpointSliceDispatchedFailed", err.Error()) + _ = c.updateEndpointSliceDispatched(ctx, mcs, metav1.ConditionFalse, "EndpointSliceDispatchedFailed", err.Error()) c.EventRecorder.Eventf(mcs, corev1.EventTypeWarning, events.EventReasonDispatchEndpointSliceFailed, err.Error()) return } - _ = c.updateEndpointSliceDispatched(mcs, metav1.ConditionTrue, "EndpointSliceDispatchedSucceed", "EndpointSlice are dispatched successfully") + _ = c.updateEndpointSliceDispatched(ctx, mcs, metav1.ConditionTrue, "EndpointSliceDispatchedSucceed", "EndpointSlice are dispatched successfully") c.EventRecorder.Eventf(mcs, corev1.EventTypeNormal, events.EventReasonDispatchEndpointSliceSucceed, "EndpointSlice are dispatched successfully") }() @@ -117,7 +117,7 @@ func (c *EndpointsliceDispatchController) Reconcile(ctx context.Context, req con return controllerruntime.Result{}, nil } -func (c *EndpointsliceDispatchController) updateEndpointSliceDispatched(mcs *networkingv1alpha1.MultiClusterService, status metav1.ConditionStatus, reason, message string) error { +func (c *EndpointsliceDispatchController) updateEndpointSliceDispatched(ctx context.Context, mcs *networkingv1alpha1.MultiClusterService, status metav1.ConditionStatus, reason, message string) error { EndpointSliceCollected := metav1.Condition{ Type: networkingv1alpha1.EndpointSliceDispatched, Status: status, @@ -127,7 +127,7 @@ func (c *EndpointsliceDispatchController) updateEndpointSliceDispatched(mcs *net } return retry.RetryOnConflict(retry.DefaultRetry, func() (err error) { - _, err = helper.UpdateStatus(context.Background(), c.Client, mcs, func() error { + _, err = helper.UpdateStatus(ctx, c.Client, mcs, func() error { meta.SetStatusCondition(&mcs.Status.Conditions, EndpointSliceCollected) return nil }) @@ -167,7 +167,7 @@ func (c *EndpointsliceDispatchController) SetupWithManager(mgr controllerruntime } func (c *EndpointsliceDispatchController) newClusterFunc() handler.MapFunc { - return func(_ context.Context, a client.Object) []reconcile.Request { + return func(ctx context.Context, a client.Object) []reconcile.Request { var clusterName string switch t := a.(type) { case *clusterv1alpha1.Cluster: @@ -177,7 +177,7 @@ func (c *EndpointsliceDispatchController) newClusterFunc() handler.MapFunc { } mcsList := &networkingv1alpha1.MultiClusterServiceList{} - if err := c.Client.List(context.TODO(), mcsList, &client.ListOptions{}); err != nil { + if err := c.Client.List(ctx, mcsList, &client.ListOptions{}); err != nil { klog.Errorf("Failed to list MultiClusterService, error: %v", err) return nil } @@ -194,7 +194,7 @@ func (c *EndpointsliceDispatchController) newClusterFunc() handler.MapFunc { continue } - workList, err := c.getClusterEndpointSliceWorks(mcs.Namespace, mcs.Name) + workList, err := c.getClusterEndpointSliceWorks(ctx, mcs.Namespace, mcs.Name) if err != nil { klog.Errorf("Failed to list work, error: %v", err) continue @@ -214,9 +214,9 @@ func (c *EndpointsliceDispatchController) newClusterFunc() handler.MapFunc { } } -func (c *EndpointsliceDispatchController) getClusterEndpointSliceWorks(mcsNamespace, mcsName string) ([]workv1alpha1.Work, error) { +func (c *EndpointsliceDispatchController) getClusterEndpointSliceWorks(ctx context.Context, mcsNamespace, mcsName string) ([]workv1alpha1.Work, error) { workList := &workv1alpha1.WorkList{} - if err := c.Client.List(context.TODO(), workList, &client.ListOptions{ + if err := c.Client.List(ctx, workList, &client.ListOptions{ LabelSelector: labels.SelectorFromSet(map[string]string{ util.MultiClusterServiceNameLabel: mcsName, util.MultiClusterServiceNamespaceLabel: mcsNamespace, @@ -230,7 +230,7 @@ func (c *EndpointsliceDispatchController) getClusterEndpointSliceWorks(mcsNamesp } func (c *EndpointsliceDispatchController) newMultiClusterServiceFunc() handler.MapFunc { - return func(_ context.Context, a client.Object) []reconcile.Request { + return func(ctx context.Context, a client.Object) []reconcile.Request { var mcsName, mcsNamespace string switch t := a.(type) { case *networkingv1alpha1.MultiClusterService: @@ -240,7 +240,7 @@ func (c *EndpointsliceDispatchController) newMultiClusterServiceFunc() handler.M return nil } - workList, err := c.getClusterEndpointSliceWorks(mcsNamespace, mcsName) + workList, err := c.getClusterEndpointSliceWorks(ctx, mcsNamespace, mcsName) if err != nil { klog.Errorf("Failed to list work, error: %v", err) return nil @@ -301,7 +301,7 @@ func (c *EndpointsliceDispatchController) cleanOrphanDispatchedEndpointSlice(ctx return nil } -func (c *EndpointsliceDispatchController) dispatchEndpointSlice(_ context.Context, work *workv1alpha1.Work, mcs *networkingv1alpha1.MultiClusterService) error { +func (c *EndpointsliceDispatchController) dispatchEndpointSlice(ctx context.Context, work *workv1alpha1.Work, mcs *networkingv1alpha1.MultiClusterService) error { epsSourceCluster, err := names.GetClusterName(work.Namespace) if err != nil { klog.Errorf("Failed to get EndpointSlice source cluster name for work %s/%s", work.Namespace, work.Name) @@ -336,14 +336,14 @@ func (c *EndpointsliceDispatchController) dispatchEndpointSlice(_ context.Contex continue } - if err = c.ensureEndpointSliceWork(mcs, work, epsSourceCluster, clusterName); err != nil { + if err = c.ensureEndpointSliceWork(ctx, mcs, work, epsSourceCluster, clusterName); err != nil { return err } } return nil } -func (c *EndpointsliceDispatchController) ensureEndpointSliceWork(mcs *networkingv1alpha1.MultiClusterService, +func (c *EndpointsliceDispatchController) ensureEndpointSliceWork(ctx context.Context, mcs *networkingv1alpha1.MultiClusterService, work *workv1alpha1.Work, providerCluster, consumerCluster string) error { // It couldn't happen here if len(work.Spec.Workload.Manifests) == 0 { @@ -393,7 +393,7 @@ func (c *EndpointsliceDispatchController) ensureEndpointSliceWork(mcs *networkin klog.Errorf("Failed to convert typed object to unstructured object, error is: %v", err) return err } - if err := helper.CreateOrUpdateWork(c.Client, workMeta, unstructuredEPS, nil); err != nil { + if err := helper.CreateOrUpdateWork(ctx, c.Client, workMeta, unstructuredEPS, nil); err != nil { klog.Errorf("Failed to dispatch EndpointSlice %s/%s from %s to cluster %s:%v", work.GetNamespace(), work.GetName(), providerCluster, consumerCluster, err) return err diff --git a/pkg/controllers/multiclusterservice/mcs_controller.go b/pkg/controllers/multiclusterservice/mcs_controller.go index bc385ca05961..be70d9d653a5 100644 --- a/pkg/controllers/multiclusterservice/mcs_controller.go +++ b/pkg/controllers/multiclusterservice/mcs_controller.go @@ -81,43 +81,43 @@ func (c *MCSController) Reconcile(ctx context.Context, req controllerruntime.Req } if !mcs.DeletionTimestamp.IsZero() { - return c.handleMultiClusterServiceDelete(mcs.DeepCopy()) + return c.handleMultiClusterServiceDelete(ctx, mcs.DeepCopy()) } var err error defer func() { if err != nil { - _ = c.updateMultiClusterServiceStatus(mcs, metav1.ConditionFalse, "ServiceAppliedFailed", err.Error()) + _ = c.updateMultiClusterServiceStatus(ctx, mcs, metav1.ConditionFalse, "ServiceAppliedFailed", err.Error()) c.EventRecorder.Eventf(mcs, corev1.EventTypeWarning, events.EventReasonSyncServiceFailed, err.Error()) return } - _ = c.updateMultiClusterServiceStatus(mcs, metav1.ConditionTrue, "ServiceAppliedSucceed", "Service is propagated to target clusters.") + _ = c.updateMultiClusterServiceStatus(ctx, mcs, metav1.ConditionTrue, "ServiceAppliedSucceed", "Service is propagated to target clusters.") c.EventRecorder.Eventf(mcs, corev1.EventTypeNormal, events.EventReasonSyncServiceSucceed, "Service is propagated to target clusters.") }() - if err = c.handleMultiClusterServiceCreateOrUpdate(mcs.DeepCopy()); err != nil { + if err = c.handleMultiClusterServiceCreateOrUpdate(ctx, mcs.DeepCopy()); err != nil { return controllerruntime.Result{}, err } return controllerruntime.Result{}, nil } -func (c *MCSController) handleMultiClusterServiceDelete(mcs *networkingv1alpha1.MultiClusterService) (controllerruntime.Result, error) { +func (c *MCSController) handleMultiClusterServiceDelete(ctx context.Context, mcs *networkingv1alpha1.MultiClusterService) (controllerruntime.Result, error) { klog.V(4).Infof("Begin to handle MultiClusterService(%s/%s) delete event", mcs.Namespace, mcs.Name) - if err := c.retrieveService(mcs); err != nil { + if err := c.retrieveService(ctx, mcs); err != nil { c.EventRecorder.Event(mcs, corev1.EventTypeWarning, events.EventReasonSyncServiceFailed, fmt.Sprintf("failed to delete service work :%v", err)) return controllerruntime.Result{}, err } - if err := c.retrieveMultiClusterService(mcs, nil); err != nil { + if err := c.retrieveMultiClusterService(ctx, mcs, nil); err != nil { c.EventRecorder.Event(mcs, corev1.EventTypeWarning, events.EventReasonSyncServiceFailed, fmt.Sprintf("failed to delete MultiClusterService work :%v", err)) return controllerruntime.Result{}, err } if controllerutil.RemoveFinalizer(mcs, util.MCSControllerFinalizer) { - err := c.Client.Update(context.Background(), mcs) + err := c.Client.Update(ctx, mcs) if err != nil { klog.Errorf("Failed to update MultiClusterService(%s/%s) with finalizer:%v", mcs.Namespace, mcs.Name, err) return controllerruntime.Result{}, err @@ -128,9 +128,9 @@ func (c *MCSController) handleMultiClusterServiceDelete(mcs *networkingv1alpha1. return controllerruntime.Result{}, nil } -func (c *MCSController) retrieveMultiClusterService(mcs *networkingv1alpha1.MultiClusterService, providerClusters sets.Set[string]) error { +func (c *MCSController) retrieveMultiClusterService(ctx context.Context, mcs *networkingv1alpha1.MultiClusterService, providerClusters sets.Set[string]) error { mcsID := util.GetLabelValue(mcs.Labels, networkingv1alpha1.MultiClusterServicePermanentIDLabel) - workList, err := helper.GetWorksByLabelsSet(c, labels.Set{ + workList, err := helper.GetWorksByLabelsSet(ctx, c, labels.Set{ networkingv1alpha1.MultiClusterServicePermanentIDLabel: mcsID, }) if err != nil { @@ -148,16 +148,16 @@ func (c *MCSController) retrieveMultiClusterService(mcs *networkingv1alpha1.Mult continue } - if providerClusters.Has(clusterName) && c.IsClusterReady(clusterName) { + if providerClusters.Has(clusterName) && c.IsClusterReady(ctx, clusterName) { continue } - if err = c.cleanProviderEndpointSliceWork(work.DeepCopy()); err != nil { + if err = c.cleanProviderEndpointSliceWork(ctx, work.DeepCopy()); err != nil { klog.Errorf("Failed to clean provider EndpointSlice work(%s/%s):%v", work.Namespace, work.Name, err) return err } - if err = c.Client.Delete(context.TODO(), work.DeepCopy()); err != nil && !apierrors.IsNotFound(err) { + if err = c.Client.Delete(ctx, work.DeepCopy()); err != nil && !apierrors.IsNotFound(err) { klog.Errorf("Error while deleting work(%s/%s): %v", work.Namespace, work.Name, err) return err } @@ -167,9 +167,9 @@ func (c *MCSController) retrieveMultiClusterService(mcs *networkingv1alpha1.Mult return nil } -func (c *MCSController) cleanProviderEndpointSliceWork(work *workv1alpha1.Work) error { +func (c *MCSController) cleanProviderEndpointSliceWork(ctx context.Context, work *workv1alpha1.Work) error { workList := &workv1alpha1.WorkList{} - if err := c.List(context.TODO(), workList, &client.ListOptions{ + if err := c.List(ctx, workList, &client.ListOptions{ Namespace: work.Namespace, LabelSelector: labels.SelectorFromSet(labels.Set{ util.MultiClusterServiceNameLabel: util.GetLabelValue(work.Labels, util.MultiClusterServiceNameLabel), @@ -191,7 +191,7 @@ func (c *MCSController) cleanProviderEndpointSliceWork(work *workv1alpha1.Work) continue } - if err := cleanProviderClustersEndpointSliceWork(c.Client, work.DeepCopy()); err != nil { + if err := cleanProviderClustersEndpointSliceWork(ctx, c.Client, work.DeepCopy()); err != nil { errs = append(errs, err) } } @@ -202,7 +202,7 @@ func (c *MCSController) cleanProviderEndpointSliceWork(work *workv1alpha1.Work) return nil } -func (c *MCSController) handleMultiClusterServiceCreateOrUpdate(mcs *networkingv1alpha1.MultiClusterService) error { +func (c *MCSController) handleMultiClusterServiceCreateOrUpdate(ctx context.Context, mcs *networkingv1alpha1.MultiClusterService) error { klog.V(4).Infof("Begin to handle MultiClusterService(%s/%s) create or update event", mcs.Namespace, mcs.Name) providerClusters, err := helper.GetProviderClusters(c.Client, mcs) @@ -218,14 +218,14 @@ func (c *MCSController) handleMultiClusterServiceCreateOrUpdate(mcs *networkingv // 1. if mcs not contain CrossCluster type, delete service work if needed if !helper.MultiClusterServiceCrossClusterEnabled(mcs) { - if err = c.retrieveService(mcs); err != nil { + if err = c.retrieveService(ctx, mcs); err != nil { return err } - if err = c.retrieveMultiClusterService(mcs, providerClusters); err != nil { + if err = c.retrieveMultiClusterService(ctx, mcs, providerClusters); err != nil { return err } if controllerutil.RemoveFinalizer(mcs, util.MCSControllerFinalizer) { - err := c.Client.Update(context.Background(), mcs) + err := c.Client.Update(ctx, mcs) if err != nil { klog.Errorf("Failed to remove finalizer(%s) from MultiClusterService(%s/%s):%v", util.MCSControllerFinalizer, mcs.Namespace, mcs.Name, err) return err @@ -236,7 +236,7 @@ func (c *MCSController) handleMultiClusterServiceCreateOrUpdate(mcs *networkingv // 2. add finalizer if needed if controllerutil.AddFinalizer(mcs, util.MCSControllerFinalizer) { - err = c.Client.Update(context.Background(), mcs) + err = c.Client.Update(ctx, mcs) if err != nil { klog.Errorf("Failed to add finalizer(%s) to MultiClusterService(%s/%s): %v ", util.MCSControllerFinalizer, mcs.Namespace, mcs.Name, err) return err @@ -244,18 +244,18 @@ func (c *MCSController) handleMultiClusterServiceCreateOrUpdate(mcs *networkingv } // 3. Generate the MCS work in target clusters' namespace - if err = c.propagateMultiClusterService(mcs, providerClusters); err != nil { + if err = c.propagateMultiClusterService(ctx, mcs, providerClusters); err != nil { return err } // 4. delete MultiClusterService work not in provider clusters and in the unready clusters - if err = c.retrieveMultiClusterService(mcs, providerClusters); err != nil { + if err = c.retrieveMultiClusterService(ctx, mcs, providerClusters); err != nil { return err } // 5. make sure service exist svc := &corev1.Service{} - err = c.Client.Get(context.Background(), types.NamespacedName{Namespace: mcs.Namespace, Name: mcs.Name}, svc) + err = c.Client.Get(ctx, types.NamespacedName{Namespace: mcs.Namespace, Name: mcs.Name}, svc) // If the Service is deleted, the Service's ResourceBinding will be cleaned by GC if err != nil { klog.Errorf("Failed to get service(%s/%s):%v", mcs.Namespace, mcs.Name, err) @@ -263,7 +263,7 @@ func (c *MCSController) handleMultiClusterServiceCreateOrUpdate(mcs *networkingv } // 6. if service exists, create or update corresponding ResourceBinding - if err = c.propagateService(context.Background(), mcs, svc, providerClusters, consumerClusters); err != nil { + if err = c.propagateService(ctx, mcs, svc, providerClusters, consumerClusters); err != nil { return err } @@ -271,7 +271,7 @@ func (c *MCSController) handleMultiClusterServiceCreateOrUpdate(mcs *networkingv return nil } -func (c *MCSController) propagateMultiClusterService(mcs *networkingv1alpha1.MultiClusterService, providerClusters sets.Set[string]) error { +func (c *MCSController) propagateMultiClusterService(ctx context.Context, mcs *networkingv1alpha1.MultiClusterService, providerClusters sets.Set[string]) error { for clusterName := range providerClusters { clusterObj, err := util.GetCluster(c.Client, clusterName) if err != nil { @@ -309,7 +309,7 @@ func (c *MCSController) propagateMultiClusterService(mcs *networkingv1alpha1.Mul klog.Errorf("Failed to convert MultiClusterService(%s/%s) to unstructured object, err is %v", mcs.Namespace, mcs.Name, err) return err } - if err = helper.CreateOrUpdateWork(c, workMeta, mcsObj, nil); err != nil { + if err = helper.CreateOrUpdateWork(ctx, c, workMeta, mcsObj, nil); err != nil { klog.Errorf("Failed to create or update MultiClusterService(%s/%s) work in the given member cluster %s, err is %v", mcs.Namespace, mcs.Name, clusterName, err) return err @@ -319,9 +319,9 @@ func (c *MCSController) propagateMultiClusterService(mcs *networkingv1alpha1.Mul return nil } -func (c *MCSController) retrieveService(mcs *networkingv1alpha1.MultiClusterService) error { +func (c *MCSController) retrieveService(ctx context.Context, mcs *networkingv1alpha1.MultiClusterService) error { svc := &corev1.Service{} - err := c.Client.Get(context.Background(), types.NamespacedName{Namespace: mcs.Namespace, Name: mcs.Name}, svc) + err := c.Client.Get(ctx, types.NamespacedName{Namespace: mcs.Namespace, Name: mcs.Name}, svc) if err != nil && !apierrors.IsNotFound(err) { klog.Errorf("Failed to get service(%s/%s):%v", mcs.Namespace, mcs.Name, err) return err @@ -337,13 +337,13 @@ func (c *MCSController) retrieveService(mcs *networkingv1alpha1.MultiClusterServ delete(svcCopy.Labels, networkingv1alpha1.MultiClusterServicePermanentIDLabel) } - if err = c.Client.Update(context.Background(), svcCopy); err != nil { + if err = c.Client.Update(ctx, svcCopy); err != nil { klog.Errorf("Failed to update service(%s/%s):%v", mcs.Namespace, mcs.Name, err) return err } rb := &workv1alpha2.ResourceBinding{} - err = c.Client.Get(context.Background(), types.NamespacedName{Namespace: mcs.Namespace, Name: names.GenerateBindingName(svc.Kind, svc.Name)}, rb) + err = c.Client.Get(ctx, types.NamespacedName{Namespace: mcs.Namespace, Name: names.GenerateBindingName(svc.Kind, svc.Name)}, rb) if err != nil { if apierrors.IsNotFound(err) { return nil @@ -363,7 +363,7 @@ func (c *MCSController) retrieveService(mcs *networkingv1alpha1.MultiClusterServ delete(rbCopy.Labels, workv1alpha2.BindingManagedByLabel) delete(rbCopy.Labels, networkingv1alpha1.MultiClusterServicePermanentIDLabel) } - if err := c.Client.Update(context.Background(), rbCopy); err != nil { + if err := c.Client.Update(ctx, rbCopy); err != nil { klog.Errorf("Failed to update ResourceBinding(%s/%s):%v", mcs.Namespace, names.GenerateBindingName(svc.Kind, svc.Name), err) return err } @@ -373,7 +373,7 @@ func (c *MCSController) retrieveService(mcs *networkingv1alpha1.MultiClusterServ func (c *MCSController) propagateService(ctx context.Context, mcs *networkingv1alpha1.MultiClusterService, svc *corev1.Service, providerClusters, consumerClusters sets.Set[string]) error { - if err := c.claimMultiClusterServiceForService(svc, mcs); err != nil { + if err := c.claimMultiClusterServiceForService(ctx, svc, mcs); err != nil { klog.Errorf("Failed to claim for Service(%s/%s), err is %v", svc.Namespace, svc.Name, err) return err } @@ -470,7 +470,7 @@ func (c *MCSController) buildResourceBinding(svc *corev1.Service, mcs *networkin return propagationBinding, nil } -func (c *MCSController) claimMultiClusterServiceForService(svc *corev1.Service, mcs *networkingv1alpha1.MultiClusterService) error { +func (c *MCSController) claimMultiClusterServiceForService(ctx context.Context, svc *corev1.Service, mcs *networkingv1alpha1.MultiClusterService) error { svcCopy := svc.DeepCopy() if svcCopy.Labels == nil { svcCopy.Labels = map[string]string{} @@ -493,7 +493,7 @@ func (c *MCSController) claimMultiClusterServiceForService(svc *corev1.Service, svcCopy.Annotations[networkingv1alpha1.MultiClusterServiceNameAnnotation] = mcs.Name svcCopy.Annotations[networkingv1alpha1.MultiClusterServiceNamespaceAnnotation] = mcs.Namespace - if err := c.Client.Update(context.Background(), svcCopy); err != nil { + if err := c.Client.Update(ctx, svcCopy); err != nil { klog.Errorf("Failed to update service(%s/%s):%v ", svc.Namespace, svc.Name, err) return err } @@ -501,7 +501,7 @@ func (c *MCSController) claimMultiClusterServiceForService(svc *corev1.Service, return nil } -func (c *MCSController) updateMultiClusterServiceStatus(mcs *networkingv1alpha1.MultiClusterService, status metav1.ConditionStatus, reason, message string) error { +func (c *MCSController) updateMultiClusterServiceStatus(ctx context.Context, mcs *networkingv1alpha1.MultiClusterService, status metav1.ConditionStatus, reason, message string) error { serviceAppliedCondition := metav1.Condition{ Type: networkingv1alpha1.MCSServiceAppliedConditionType, Status: status, @@ -511,7 +511,7 @@ func (c *MCSController) updateMultiClusterServiceStatus(mcs *networkingv1alpha1. } return retry.RetryOnConflict(retry.DefaultRetry, func() (err error) { - _, err = helper.UpdateStatus(context.Background(), c.Client, mcs, func() error { + _, err = helper.UpdateStatus(ctx, c.Client, mcs, func() error { meta.SetStatusCondition(&mcs.Status.Conditions, serviceAppliedCondition) return nil }) @@ -520,9 +520,9 @@ func (c *MCSController) updateMultiClusterServiceStatus(mcs *networkingv1alpha1. } // IsClusterReady checks whether the cluster is ready. -func (c *MCSController) IsClusterReady(clusterName string) bool { +func (c *MCSController) IsClusterReady(ctx context.Context, clusterName string) bool { cluster := &clusterv1alpha1.Cluster{} - if err := c.Client.Get(context.TODO(), types.NamespacedName{Name: clusterName}, cluster); err != nil { + if err := c.Client.Get(ctx, types.NamespacedName{Name: clusterName}, cluster); err != nil { klog.Errorf("Failed to get cluster object(%s):%v", clusterName, err) return false } @@ -621,7 +621,7 @@ func (c *MCSController) serviceHasCrossClusterMultiClusterService(svc *corev1.Se } func (c *MCSController) clusterMapFunc() handler.MapFunc { - return func(_ context.Context, a client.Object) []reconcile.Request { + return func(ctx context.Context, a client.Object) []reconcile.Request { var clusterName string switch t := a.(type) { case *clusterv1alpha1.Cluster: @@ -632,7 +632,7 @@ func (c *MCSController) clusterMapFunc() handler.MapFunc { klog.V(4).Infof("Begin to sync mcs with cluster %s.", clusterName) mcsList := &networkingv1alpha1.MultiClusterServiceList{} - if err := c.Client.List(context.TODO(), mcsList, &client.ListOptions{}); err != nil { + if err := c.Client.List(ctx, mcsList, &client.ListOptions{}); err != nil { klog.Errorf("Failed to list MultiClusterService, error: %v", err) return nil } diff --git a/pkg/controllers/namespace/namespace_sync_controller.go b/pkg/controllers/namespace/namespace_sync_controller.go index 016901b861b8..43ceeb809796 100644 --- a/pkg/controllers/namespace/namespace_sync_controller.go +++ b/pkg/controllers/namespace/namespace_sync_controller.go @@ -97,7 +97,7 @@ func (c *Controller) Reconcile(ctx context.Context, req controllerruntime.Reques return controllerruntime.Result{}, err } - err := c.buildWorks(namespace, clusterList.Items) + err := c.buildWorks(ctx, namespace, clusterList.Items) if err != nil { klog.Errorf("Failed to build work for namespace %s. Error: %v.", namespace.GetName(), err) return controllerruntime.Result{}, err @@ -119,7 +119,7 @@ func (c *Controller) namespaceShouldBeSynced(namespace string) bool { return true } -func (c *Controller) buildWorks(namespace *corev1.Namespace, clusters []clusterv1alpha1.Cluster) error { +func (c *Controller) buildWorks(ctx context.Context, namespace *corev1.Namespace, clusters []clusterv1alpha1.Cluster) error { namespaceObj, err := helper.ToUnstructured(namespace) if err != nil { klog.Errorf("Failed to transform namespace %s. Error: %v", namespace.GetName(), err) @@ -157,7 +157,7 @@ func (c *Controller) buildWorks(namespace *corev1.Namespace, clusters []clusterv Annotations: annotations, } - if err = helper.CreateOrUpdateWork(c.Client, objectMeta, clonedNamespaced, nil); err != nil { + if err = helper.CreateOrUpdateWork(ctx, c.Client, objectMeta, clonedNamespaced, nil); err != nil { ch <- fmt.Errorf("sync namespace(%s) to cluster(%s) failed due to: %v", clonedNamespaced.GetName(), cluster.GetName(), err) return } @@ -178,10 +178,10 @@ func (c *Controller) buildWorks(namespace *corev1.Namespace, clusters []clusterv // SetupWithManager creates a controller and register to controller manager. func (c *Controller) SetupWithManager(mgr controllerruntime.Manager) error { clusterNamespaceFn := handler.MapFunc( - func(_ context.Context, _ client.Object) []reconcile.Request { + func(ctx context.Context, _ client.Object) []reconcile.Request { var requests []reconcile.Request namespaceList := &corev1.NamespaceList{} - if err := c.Client.List(context.TODO(), namespaceList); err != nil { + if err := c.Client.List(ctx, namespaceList); err != nil { klog.Errorf("Failed to list namespace, error: %v", err) return nil } diff --git a/pkg/controllers/namespace/namespace_sync_controller_test.go b/pkg/controllers/namespace/namespace_sync_controller_test.go new file mode 100644 index 000000000000..20b6fc6f1f5d --- /dev/null +++ b/pkg/controllers/namespace/namespace_sync_controller_test.go @@ -0,0 +1,422 @@ +/* +Copyright 2024 The Karmada 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 namespace + +import ( + "context" + "regexp" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/record" + controllerruntime "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1" + policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1" + workv1alpha1 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha1" + "github.com/karmada-io/karmada/pkg/util/names" + "github.com/karmada-io/karmada/pkg/util/overridemanager" +) + +func TestController_namespaceShouldBeSynced(t *testing.T) { + tests := []struct { + name string + namespace string + skipped []*regexp.Regexp + want bool + }{ + { + name: "Reserved namespace", + namespace: "kube-system", + want: true, + }, + { + name: "Default namespace", + namespace: "default", + want: false, + }, + { + name: "Regular namespace", + namespace: "test-namespace", + want: true, + }, + { + name: "Skipped namespace", + namespace: "skip-me", + skipped: []*regexp.Regexp{regexp.MustCompile("skip-.*")}, + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &Controller{ + SkippedPropagatingNamespaces: tt.skipped, + } + got := c.namespaceShouldBeSynced(tt.namespace) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestController_Reconcile(t *testing.T) { + scheme := runtime.NewScheme() + _ = corev1.AddToScheme(scheme) + _ = clusterv1alpha1.Install(scheme) + _ = policyv1alpha1.Install(scheme) + _ = workv1alpha1.Install(scheme) + + tests := []struct { + name string + namespace *corev1.Namespace + clusters []clusterv1alpha1.Cluster + expectedResult controllerruntime.Result + expectedError bool + expectWorkCreated bool + namespaceNotFound bool + namespaceDeleting bool + }{ + { + name: "Namespace should be synced", + namespace: &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-namespace", + }, + }, + clusters: []clusterv1alpha1.Cluster{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster1", + }, + }, + }, + expectedResult: controllerruntime.Result{}, + expectedError: false, + expectWorkCreated: true, + }, + { + name: "Namespace should not be synced", + namespace: &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "kube-system", + }, + }, + expectedResult: controllerruntime.Result{}, + expectedError: false, + expectWorkCreated: false, + }, + { + name: "Namespace with skip auto propagation label", + namespace: &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "skip-namespace", + Labels: map[string]string{ + policyv1alpha1.NamespaceSkipAutoPropagationLabel: "true", + }, + }, + }, + expectedResult: controllerruntime.Result{}, + expectedError: false, + }, + { + name: "Namespace should not be synced - kube-public", + namespace: &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "kube-public", + }, + }, + expectedResult: controllerruntime.Result{}, + expectedError: false, + expectWorkCreated: false, + }, + { + name: "Namespace not found", + namespace: &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "non-existent"}}, + namespaceNotFound: true, + expectedResult: controllerruntime.Result{}, + expectedError: false, + expectWorkCreated: false, + }, + { + name: "Namespace is being deleted", + namespace: &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "deleting-namespace", + DeletionTimestamp: &metav1.Time{Time: time.Now()}, + Finalizers: []string{"some-finalizer"}, + }, + }, + namespaceDeleting: true, + expectedResult: controllerruntime.Result{}, + expectedError: false, + expectWorkCreated: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fakeClientBuilder := fake.NewClientBuilder().WithScheme(scheme) + + if !tt.namespaceNotFound { + fakeClientBuilder = fakeClientBuilder.WithObjects(tt.namespace) + } + + fakeClientBuilder = fakeClientBuilder.WithLists(&clusterv1alpha1.ClusterList{Items: tt.clusters}) + fakeClient := fakeClientBuilder.Build() + fakeRecorder := record.NewFakeRecorder(100) + + c := &Controller{ + Client: fakeClient, + EventRecorder: fakeRecorder, + OverrideManager: overridemanager.New(fakeClient, fakeRecorder), + } + + req := controllerruntime.Request{ + NamespacedName: types.NamespacedName{ + Name: tt.namespace.Name, + }, + } + + result, err := c.Reconcile(context.Background(), req) + assert.Equal(t, tt.expectedResult, result) + assert.Equal(t, tt.expectedError, err != nil) + + if tt.namespaceNotFound { + ns := &corev1.Namespace{} + err := fakeClient.Get(context.Background(), types.NamespacedName{Name: tt.namespace.Name}, ns) + assert.True(t, apierrors.IsNotFound(err)) + } else if tt.namespaceDeleting { + ns := &corev1.Namespace{} + err := fakeClient.Get(context.Background(), types.NamespacedName{Name: tt.namespace.Name}, ns) + assert.NoError(t, err) + assert.NotNil(t, ns.DeletionTimestamp) + } + + if tt.expectWorkCreated { + if len(tt.clusters) == 0 { + t.Fatal("Test case expects work to be created but no clusters are defined") + } + work := &workv1alpha1.Work{} + err = fakeClient.Get(context.Background(), types.NamespacedName{ + Namespace: names.GenerateExecutionSpaceName(tt.clusters[0].Name), + Name: names.GenerateWorkName(tt.namespace.Kind, tt.namespace.Name, tt.namespace.Namespace), + }, work) + assert.NoError(t, err) + assert.NotNil(t, work) + } else if len(tt.clusters) > 0 { + work := &workv1alpha1.Work{} + err = fakeClient.Get(context.Background(), types.NamespacedName{ + Namespace: names.GenerateExecutionSpaceName(tt.clusters[0].Name), + Name: names.GenerateWorkName(tt.namespace.Kind, tt.namespace.Name, tt.namespace.Namespace), + }, work) + assert.Error(t, err) + assert.True(t, apierrors.IsNotFound(err)) + } + }) + } +} + +func TestController_buildWorks(t *testing.T) { + scheme := runtime.NewScheme() + _ = corev1.AddToScheme(scheme) + _ = clusterv1alpha1.Install(scheme) + _ = workv1alpha1.Install(scheme) + _ = policyv1alpha1.Install(scheme) + + namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-namespace", + }, + } + + clusters := []clusterv1alpha1.Cluster{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster1", + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster2", + }, + }, + } + + overridePolicy := &policyv1alpha1.ClusterOverridePolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-override", + }, + Spec: policyv1alpha1.OverrideSpec{ + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "v1", + Kind: "Namespace", + Name: "test-namespace", + }, + }, + OverrideRules: []policyv1alpha1.RuleWithCluster{ + { + TargetCluster: &policyv1alpha1.ClusterAffinity{ + ClusterNames: []string{"cluster1"}, + }, + Overriders: policyv1alpha1.Overriders{ + Plaintext: []policyv1alpha1.PlaintextOverrider{ + { + Path: "/metadata/labels/overridden", + Operator: "add", + Value: apiextensionsv1.JSON{ + Raw: []byte(`"true"`), + }, + }, + }, + }, + }, + }, + }, + } + + tests := []struct { + name string + withOverride bool + }{ + { + name: "Build works without override", + withOverride: false, + }, + { + name: "Build works with override", + withOverride: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fakeClientBuilder := fake.NewClientBuilder().WithScheme(scheme).WithObjects(namespace, &clusters[0], &clusters[1]) + if tt.withOverride { + fakeClientBuilder = fakeClientBuilder.WithObjects(overridePolicy) + } + fakeClient := fakeClientBuilder.Build() + fakeRecorder := record.NewFakeRecorder(100) + + c := &Controller{ + Client: fakeClient, + EventRecorder: fakeRecorder, + OverrideManager: overridemanager.New(fakeClient, fakeRecorder), + } + + err := c.buildWorks(context.Background(), namespace, clusters) + assert.NoError(t, err) + + for _, cluster := range clusters { + work := &workv1alpha1.Work{} + err = fakeClient.Get(context.Background(), types.NamespacedName{ + Namespace: names.GenerateExecutionSpaceName(cluster.Name), + Name: names.GenerateWorkName(namespace.Kind, namespace.Name, namespace.Namespace), + }, work) + assert.NoError(t, err) + assert.NotNil(t, work) + assert.Equal(t, namespace.Name, work.OwnerReferences[0].Name) + + assert.NotEmpty(t, work.Spec.Workload.Manifests) + } + }) + } +} + +func TestController_SetupWithManager(t *testing.T) { + tests := []struct { + name string + setupScheme func(*runtime.Scheme) + concurrentRuns int + expectError bool + }{ + { + name: "Successful setup", + setupScheme: func(scheme *runtime.Scheme) { + _ = corev1.AddToScheme(scheme) + _ = clusterv1alpha1.Install(scheme) + _ = workv1alpha1.Install(scheme) + _ = policyv1alpha1.Install(scheme) + }, + concurrentRuns: 1, + expectError: false, + }, + { + name: "Concurrent setup", + setupScheme: func(scheme *runtime.Scheme) { + _ = corev1.AddToScheme(scheme) + _ = clusterv1alpha1.Install(scheme) + _ = workv1alpha1.Install(scheme) + _ = policyv1alpha1.Install(scheme) + }, + concurrentRuns: 10, + expectError: false, + }, + { + name: "Setup with error", + setupScheme: func(_ *runtime.Scheme) {}, // Intentionally empty to trigger error + concurrentRuns: 1, + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + scheme := runtime.NewScheme() + tt.setupScheme(scheme) + + cfg := &rest.Config{Host: "http://localhost:8080"} + mgr, err := controllerruntime.NewManager(cfg, controllerruntime.Options{ + Scheme: scheme, + }) + assert.NoError(t, err) + + var wg sync.WaitGroup + for i := 0; i < tt.concurrentRuns; i++ { + wg.Add(1) + go func() { + defer wg.Done() + c := &Controller{ + Client: mgr.GetClient(), + EventRecorder: mgr.GetEventRecorderFor("test-controller"), + OverrideManager: overridemanager.New(mgr.GetClient(), mgr.GetEventRecorderFor("test-controller")), + } + err := c.SetupWithManager(mgr) + if tt.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.NotNil(t, c.Client, "Controller's Client should not be nil") + assert.NotNil(t, c.EventRecorder, "Controller's EventRecorder should not be nil") + assert.NotNil(t, c.OverrideManager, "Controller's OverrideManager should not be nil") + } + }() + } + wg.Wait() + }) + } +} diff --git a/pkg/controllers/status/cluster_condition_cache_test.go b/pkg/controllers/status/cluster_condition_cache_test.go index aed6f985de89..11747d581047 100644 --- a/pkg/controllers/status/cluster_condition_cache_test.go +++ b/pkg/controllers/status/cluster_condition_cache_test.go @@ -176,6 +176,60 @@ func TestThresholdAdjustedReadyCondition(t *testing.T) { Status: metav1.ConditionTrue, }, }, + { + name: "ready condition changes from true to false", + clusterData: &clusterData{ + readyCondition: metav1.ConditionTrue, + thresholdStartTime: time.Now().Add(-10 * time.Minute), + }, + currentCondition: &metav1.Condition{ + Type: clusterv1alpha1.ClusterConditionReady, + Status: metav1.ConditionTrue, + }, + observedCondition: &metav1.Condition{ + Type: clusterv1alpha1.ClusterConditionReady, + Status: metav1.ConditionFalse, + }, + expectedCondition: &metav1.Condition{ + Type: clusterv1alpha1.ClusterConditionReady, + Status: metav1.ConditionTrue, + }, + }, + { + name: "ready condition changes from false to true", + clusterData: &clusterData{ + readyCondition: metav1.ConditionFalse, + thresholdStartTime: time.Now().Add(-10 * time.Minute), + }, + currentCondition: &metav1.Condition{ + Type: clusterv1alpha1.ClusterConditionReady, + Status: metav1.ConditionFalse, + }, + observedCondition: &metav1.Condition{ + Type: clusterv1alpha1.ClusterConditionReady, + Status: metav1.ConditionTrue, + }, + expectedCondition: &metav1.Condition{ + Type: clusterv1alpha1.ClusterConditionReady, + Status: metav1.ConditionFalse, + }, + }, + { + name: "current condition is nil, should return observed condition", + clusterData: &clusterData{ + readyCondition: metav1.ConditionFalse, + thresholdStartTime: time.Now().Add(-clusterFailureThreshold), + }, + currentCondition: nil, + observedCondition: &metav1.Condition{ + Type: clusterv1alpha1.ClusterConditionReady, + Status: metav1.ConditionTrue, + }, + expectedCondition: &metav1.Condition{ + Type: clusterv1alpha1.ClusterConditionReady, + Status: metav1.ConditionTrue, + }, + }, } for _, tt := range tests { diff --git a/pkg/controllers/status/cluster_status_controller.go b/pkg/controllers/status/cluster_status_controller.go index 44afe1ee1009..fff3bfb0953e 100644 --- a/pkg/controllers/status/cluster_status_controller.go +++ b/pkg/controllers/status/cluster_status_controller.go @@ -153,7 +153,11 @@ func (c *ClusterStatusController) Reconcile(ctx context.Context, req controllerr return controllerruntime.Result{Requeue: true}, nil } - return c.syncClusterStatus(cluster) + err := c.syncClusterStatus(ctx, cluster) + if err != nil { + return controllerruntime.Result{}, err + } + return controllerruntime.Result{RequeueAfter: c.ClusterStatusUpdateFrequency.Duration}, nil } // SetupWithManager creates a controller and register to controller manager. @@ -169,7 +173,7 @@ func (c *ClusterStatusController) SetupWithManager(mgr controllerruntime.Manager }).Complete(c) } -func (c *ClusterStatusController) syncClusterStatus(cluster *clusterv1alpha1.Cluster) (controllerruntime.Result, error) { +func (c *ClusterStatusController) syncClusterStatus(ctx context.Context, cluster *clusterv1alpha1.Cluster) error { start := time.Now() defer func() { metrics.RecordClusterStatus(cluster) @@ -182,7 +186,7 @@ func (c *ClusterStatusController) syncClusterStatus(cluster *clusterv1alpha1.Clu clusterClient, err := c.ClusterClientSetFunc(cluster.Name, c.Client, c.ClusterClientOption) if err != nil { klog.Errorf("Failed to create a ClusterClient for the given member cluster: %v, err is : %v", cluster.Name, err) - return c.setStatusCollectionFailedCondition(cluster, currentClusterStatus, fmt.Sprintf("failed to create a ClusterClient: %v", err)) + return setStatusCollectionFailedCondition(ctx, c.Client, cluster, fmt.Sprintf("failed to create a ClusterClient: %v", err)) } online, healthy := getClusterHealthStatus(clusterClient) @@ -193,8 +197,7 @@ func (c *ClusterStatusController) syncClusterStatus(cluster *clusterv1alpha1.Clu if !online && readyCondition.Status != metav1.ConditionTrue { klog.V(2).Infof("Cluster(%s) still offline after %s, ensuring offline is set.", cluster.Name, c.ClusterFailureThreshold.Duration) - meta.SetStatusCondition(¤tClusterStatus.Conditions, *readyCondition) - return c.updateStatusIfNeeded(cluster, currentClusterStatus) + return updateStatusCondition(ctx, c.Client, cluster, *readyCondition) } // skip collecting cluster status if not ready @@ -211,15 +214,13 @@ func (c *ClusterStatusController) syncClusterStatus(cluster *clusterv1alpha1.Clu // can be safely removed from current controller. c.initializeGenericInformerManagerForCluster(clusterClient) - err := c.setCurrentClusterStatus(clusterClient, cluster, ¤tClusterStatus) + err = c.setCurrentClusterStatus(clusterClient, cluster, ¤tClusterStatus) if err != nil { - return controllerruntime.Result{}, err + return err } } - meta.SetStatusCondition(¤tClusterStatus.Conditions, *readyCondition) - - return c.updateStatusIfNeeded(cluster, currentClusterStatus) + return c.updateStatusIfNeeded(ctx, cluster, currentClusterStatus, *readyCondition) } func (c *ClusterStatusController) setCurrentClusterStatus(clusterClient *util.ClusterClient, cluster *clusterv1alpha1.Cluster, currentClusterStatus *clusterv1alpha1.ClusterStatus) error { @@ -266,34 +267,56 @@ func (c *ClusterStatusController) setCurrentClusterStatus(clusterClient *util.Cl return nil } -func (c *ClusterStatusController) setStatusCollectionFailedCondition(cluster *clusterv1alpha1.Cluster, currentClusterStatus clusterv1alpha1.ClusterStatus, message string) (controllerruntime.Result, error) { +func setStatusCollectionFailedCondition(ctx context.Context, c client.Client, cluster *clusterv1alpha1.Cluster, message string) error { readyCondition := util.NewCondition(clusterv1alpha1.ClusterConditionReady, statusCollectionFailed, message, metav1.ConditionFalse) - meta.SetStatusCondition(¤tClusterStatus.Conditions, readyCondition) - return c.updateStatusIfNeeded(cluster, currentClusterStatus) + return updateStatusCondition(ctx, c, cluster, readyCondition) } // updateStatusIfNeeded calls updateStatus only if the status of the member cluster is not the same as the old status -func (c *ClusterStatusController) updateStatusIfNeeded(cluster *clusterv1alpha1.Cluster, currentClusterStatus clusterv1alpha1.ClusterStatus) (controllerruntime.Result, error) { +func (c *ClusterStatusController) updateStatusIfNeeded(ctx context.Context, cluster *clusterv1alpha1.Cluster, currentClusterStatus clusterv1alpha1.ClusterStatus, conditions ...metav1.Condition) error { + for _, condition := range conditions { + meta.SetStatusCondition(¤tClusterStatus.Conditions, condition) + } if !equality.Semantic.DeepEqual(cluster.Status, currentClusterStatus) { klog.V(4).Infof("Start to update cluster status: %s", cluster.Name) err := retry.RetryOnConflict(retry.DefaultRetry, func() (err error) { - _, err = helper.UpdateStatus(context.Background(), c.Client, cluster, func() error { + _, err = helper.UpdateStatus(ctx, c.Client, cluster, func() error { cluster.Status.KubernetesVersion = currentClusterStatus.KubernetesVersion cluster.Status.APIEnablements = currentClusterStatus.APIEnablements - cluster.Status.Conditions = currentClusterStatus.Conditions cluster.Status.NodeSummary = currentClusterStatus.NodeSummary cluster.Status.ResourceSummary = currentClusterStatus.ResourceSummary + for _, condition := range conditions { + meta.SetStatusCondition(&cluster.Status.Conditions, condition) + } return nil }) return err }) if err != nil { klog.Errorf("Failed to update health status of the member cluster: %v, err is : %v", cluster.Name, err) - return controllerruntime.Result{}, err + return err } } - return controllerruntime.Result{RequeueAfter: c.ClusterStatusUpdateFrequency.Duration}, nil + return nil +} + +func updateStatusCondition(ctx context.Context, c client.Client, cluster *clusterv1alpha1.Cluster, conditions ...metav1.Condition) error { + klog.V(4).Infof("Start to update cluster(%s) status condition", cluster.Name) + err := retry.RetryOnConflict(retry.DefaultRetry, func() (err error) { + _, err = helper.UpdateStatus(ctx, c, cluster, func() error { + for _, condition := range conditions { + meta.SetStatusCondition(&cluster.Status.Conditions, condition) + } + return nil + }) + return err + }) + if err != nil { + klog.Errorf("Failed to update status condition of the member cluster: %v, err is : %v", cluster.Name, err) + return err + } + return nil } func (c *ClusterStatusController) initializeGenericInformerManagerForCluster(clusterClient *util.ClusterClient) { diff --git a/pkg/controllers/status/cluster_status_controller_test.go b/pkg/controllers/status/cluster_status_controller_test.go index 55fdd091a11b..c6221228aac6 100644 --- a/pkg/controllers/status/cluster_status_controller_test.go +++ b/pkg/controllers/status/cluster_status_controller_test.go @@ -228,9 +228,7 @@ func TestClusterStatusController_syncClusterStatus(t *testing.T) { if err := c.Client.Create(context.Background(), cluster); err != nil { t.Fatalf("Failed to create cluster: %v", err) } - res, err := c.syncClusterStatus(cluster) - expect := controllerruntime.Result{} - assert.Equal(t, expect, res) + err := c.syncClusterStatus(context.Background(), cluster) assert.Empty(t, err) }) t.Run("online is false, readyCondition.Status isn't true", func(t *testing.T) { @@ -275,9 +273,7 @@ func TestClusterStatusController_syncClusterStatus(t *testing.T) { t.Fatalf("Failed to create cluster: %v", err) } - res, err := c.syncClusterStatus(cluster) - expect := controllerruntime.Result{} - assert.Equal(t, expect, res) + err := c.syncClusterStatus(context.Background(), cluster) assert.Empty(t, err) }) @@ -322,9 +318,7 @@ func TestClusterStatusController_syncClusterStatus(t *testing.T) { if err := c.Client.Create(context.Background(), cluster); err != nil { t.Fatalf("Failed to create cluster: %v", err) } - res, err := c.syncClusterStatus(cluster) - expect := controllerruntime.Result{} - assert.Equal(t, expect, res) + err := c.syncClusterStatus(context.Background(), cluster) assert.Empty(t, err) }) } @@ -913,8 +907,7 @@ func TestClusterStatusController_updateStatusIfNeeded(t *testing.T) { ClusterClientSetFunc: util.NewClusterClientSet, } - actual, err := c.updateStatusIfNeeded(cluster, currentClusterStatus) - assert.Equal(t, controllerruntime.Result{}, actual) + err := c.updateStatusIfNeeded(context.Background(), cluster, currentClusterStatus) assert.Empty(t, err, "updateStatusIfNeeded returns error") }) @@ -978,9 +971,7 @@ func TestClusterStatusController_updateStatusIfNeeded(t *testing.T) { ClusterClientSetFunc: util.NewClusterClientSet, } - actual, err := c.updateStatusIfNeeded(cluster, currentClusterStatus) - expect := controllerruntime.Result{} - assert.Equal(t, expect, actual) + err := c.updateStatusIfNeeded(context.Background(), cluster, currentClusterStatus) assert.NotEmpty(t, err, "updateStatusIfNeeded doesn't return error") }) } diff --git a/pkg/controllers/status/common.go b/pkg/controllers/status/common.go index ebeb97ceb527..9a78a688f2d1 100644 --- a/pkg/controllers/status/common.go +++ b/pkg/controllers/status/common.go @@ -20,12 +20,15 @@ import ( "context" "reflect" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/dynamic" + "k8s.io/client-go/tools/record" + "k8s.io/client-go/util/retry" "k8s.io/klog/v2" "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/event" @@ -34,8 +37,8 @@ import ( configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1" workv1alpha1 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha1" workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" + "github.com/karmada-io/karmada/pkg/events" "github.com/karmada-io/karmada/pkg/resourceinterpreter" - "github.com/karmada-io/karmada/pkg/util/helper" "github.com/karmada-io/karmada/pkg/util/restmapper" ) @@ -101,46 +104,71 @@ var workPredicateFn = builder.WithPredicates(predicate.Funcs{ // updateResourceStatus will try to calculate the summary status and // update to original object that the ResourceBinding refer to. func updateResourceStatus( + ctx context.Context, dynamicClient dynamic.Interface, restMapper meta.RESTMapper, interpreter resourceinterpreter.ResourceInterpreter, - resource *unstructured.Unstructured, + eventRecorder record.EventRecorder, + objRef workv1alpha2.ObjectReference, bindingStatus workv1alpha2.ResourceBindingStatus, ) error { - gvr, err := restmapper.GetGroupVersionResource(restMapper, schema.FromAPIVersionAndKind(resource.GetAPIVersion(), resource.GetKind())) + gvr, err := restmapper.GetGroupVersionResource(restMapper, schema.FromAPIVersionAndKind(objRef.APIVersion, objRef.Kind)) if err != nil { - klog.Errorf("Failed to get GVR from GVK(%s/%s), Error: %v", resource.GetAPIVersion(), resource.GetKind(), err) + klog.Errorf("Failed to get GVR from GVK(%s/%s), Error: %v", objRef.APIVersion, objRef.Kind, err) return err } - if !interpreter.HookEnabled(resource.GroupVersionKind(), configv1alpha1.InterpreterOperationAggregateStatus) { + gvk := schema.GroupVersionKind{Group: gvr.Group, Version: gvr.Version, Kind: objRef.Kind} + if !interpreter.HookEnabled(gvk, configv1alpha1.InterpreterOperationAggregateStatus) { return nil } - newObj, err := interpreter.AggregateStatus(resource, bindingStatus.AggregatedStatus) - if err != nil { - klog.Errorf("Failed to aggregate status for resource(%s/%s/%s, Error: %v", gvr, resource.GetNamespace(), resource.GetName(), err) - return err - } - oldStatus, _, _ := unstructured.NestedFieldNoCopy(resource.Object, "status") - newStatus, _, _ := unstructured.NestedFieldNoCopy(newObj.Object, "status") - if reflect.DeepEqual(oldStatus, newStatus) { - klog.V(3).Infof("Ignore update resource(%s/%s/%s) status as up to date.", gvr, resource.GetNamespace(), resource.GetName()) - return nil - } + var resource *unstructured.Unstructured + if err = retry.RetryOnConflict(retry.DefaultRetry, func() error { + // Fetch resource template from karmada-apiserver instead of informer cache, to avoid retry due to + // resource conflict which often happens, especially with a huge amount of resource templates and + // the informer cache doesn't sync quickly enough. + // For more details refer to https://github.com/karmada-io/karmada/issues/5285. + resource, err = dynamicClient.Resource(gvr).Namespace(objRef.Namespace).Get(ctx, objRef.Name, metav1.GetOptions{}) + if err != nil { + if apierrors.IsNotFound(err) { + // It might happen when the resource template has been removed but the garbage collector hasn't removed + // the ResourceBinding which dependent on resource template. + // So, just return without retry(requeue) would save unnecessary loop. + return nil + } + klog.Errorf("Failed to fetch resource template(%s/%s/%s), Error: %v.", gvr, objRef.Namespace, objRef.Name, err) + return err + } - patchBytes, err := helper.GenReplaceFieldJSONPatch("/status", oldStatus, newStatus) - if err != nil { - klog.Errorf("Failed to gen patch bytes for resource(%s/%s/%s, Error: %v", gvr, resource.GetNamespace(), resource.GetName(), err) - return err - } + newObj, err := interpreter.AggregateStatus(resource, bindingStatus.AggregatedStatus) + if err != nil { + klog.Errorf("Failed to aggregate status for resource template(%s/%s/%s), Error: %v", gvr, resource.GetNamespace(), resource.GetName(), err) + return err + } - _, err = dynamicClient.Resource(gvr).Namespace(resource.GetNamespace()). - Patch(context.TODO(), resource.GetName(), types.JSONPatchType, patchBytes, metav1.PatchOptions{}, "status") - if err != nil { - klog.Errorf("Failed to update resource(%s/%s/%s), Error: %v", gvr, resource.GetNamespace(), resource.GetName(), err) + oldStatus, _, _ := unstructured.NestedFieldNoCopy(resource.Object, "status") + newStatus, _, _ := unstructured.NestedFieldNoCopy(newObj.Object, "status") + if reflect.DeepEqual(oldStatus, newStatus) { + klog.V(3).Infof("Ignore update resource(%s/%s/%s) status as up to date.", gvr, resource.GetNamespace(), resource.GetName()) + return nil + } + + if _, err = dynamicClient.Resource(gvr).Namespace(resource.GetNamespace()).UpdateStatus(ctx, newObj, metav1.UpdateOptions{}); err != nil { + klog.Errorf("Failed to update resource(%s/%s/%s), Error: %v", gvr, resource.GetNamespace(), resource.GetName(), err) + return err + } + + eventRecorder.Event(resource, corev1.EventTypeNormal, events.EventReasonAggregateStatusSucceed, "Update Resource with AggregatedStatus successfully.") + klog.V(3).Infof("Update resource(%s/%s/%s) status successfully.", gvr, resource.GetNamespace(), resource.GetName()) + + return nil + }); err != nil { + if resource != nil { + eventRecorder.Event(resource, corev1.EventTypeWarning, events.EventReasonAggregateStatusFailed, err.Error()) + } return err } - klog.V(3).Infof("Update resource(%s/%s/%s) status successfully.", gvr, resource.GetNamespace(), resource.GetName()) + return nil } diff --git a/pkg/controllers/status/crb_status_controller.go b/pkg/controllers/status/crb_status_controller.go index ed3cd096b8c7..79a11fb76cbc 100644 --- a/pkg/controllers/status/crb_status_controller.go +++ b/pkg/controllers/status/crb_status_controller.go @@ -75,7 +75,7 @@ func (c *CRBStatusController) Reconcile(ctx context.Context, req controllerrunti return controllerruntime.Result{}, nil } - err := c.syncBindingStatus(binding) + err := c.syncBindingStatus(ctx, binding) if err != nil { return controllerruntime.Result{}, err } @@ -108,28 +108,15 @@ func (c *CRBStatusController) SetupWithManager(mgr controllerruntime.Manager) er Complete(c) } -func (c *CRBStatusController) syncBindingStatus(binding *workv1alpha2.ClusterResourceBinding) error { - resource, err := helper.FetchResourceTemplate(c.DynamicClient, c.InformerManager, c.RESTMapper, binding.Spec.Resource) - if err != nil { - if apierrors.IsNotFound(err) { - // It might happen when the resource template has been removed but the garbage collector hasn't removed - // the ResourceBinding which dependent on resource template. - // So, just return without retry(requeue) would save unnecessary loop. - return nil - } - klog.Errorf("Failed to fetch workload for clusterResourceBinding(%s). Error: %v", - binding.GetName(), err) - return err - } - - err = helper.AggregateClusterResourceBindingWorkStatus(c.Client, binding, resource, c.EventRecorder) +func (c *CRBStatusController) syncBindingStatus(ctx context.Context, binding *workv1alpha2.ClusterResourceBinding) error { + err := helper.AggregateClusterResourceBindingWorkStatus(ctx, c.Client, binding, c.EventRecorder) if err != nil { klog.Errorf("Failed to aggregate workStatues to clusterResourceBinding(%s), Error: %v", binding.Name, err) return err } - err = updateResourceStatus(c.DynamicClient, c.RESTMapper, c.ResourceInterpreter, resource, binding.Status) + err = updateResourceStatus(ctx, c.DynamicClient, c.RESTMapper, c.ResourceInterpreter, c.EventRecorder, binding.Spec.Resource, binding.Status) if err != nil { return err } diff --git a/pkg/controllers/status/crb_status_controller_test.go b/pkg/controllers/status/crb_status_controller_test.go index 6c3ccc454e15..9c44efa45364 100644 --- a/pkg/controllers/status/crb_status_controller_test.go +++ b/pkg/controllers/status/crb_status_controller_test.go @@ -34,6 +34,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/fake" workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" + "github.com/karmada-io/karmada/pkg/resourceinterpreter/default/native" "github.com/karmada-io/karmada/pkg/util/fedinformer/genericmanager" "github.com/karmada-io/karmada/pkg/util/gclient" ) @@ -98,8 +99,11 @@ func TestCRBStatusController_Reconcile(t *testing.T) { name: "failed in syncBindingStatus", binding: &workv1alpha2.ClusterResourceBinding{ ObjectMeta: metav1.ObjectMeta{ - Name: "binding", - Namespace: "default", + Name: "binding", + Namespace: "default", + // finalizers field is required when deletionTimestamp is defined, otherwise will encounter the + // error: `refusing to create obj binding with metadata.deletionTimestamp but no finalizers`. + Finalizers: []string{"test"}, DeletionTimestamp: &preTime, }, Spec: workv1alpha2.ResourceBindingSpec{ @@ -119,6 +123,7 @@ func TestCRBStatusController_Reconcile(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := generateCRBStatusController() + c.ResourceInterpreter = FakeResourceInterpreter{DefaultInterpreter: native.NewDefaultInterpreter()} // Prepare req req := controllerruntime.Request{ @@ -130,9 +135,7 @@ func TestCRBStatusController_Reconcile(t *testing.T) { // Prepare binding and create it in client if tt.binding != nil { - if err := c.Client.Create(context.Background(), tt.binding); err != nil { - t.Fatalf("Failed to create binding: %v", err) - } + c.Client = fake.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects(tt.binding).WithStatusSubresource(tt.binding).Build() } res, err := c.Reconcile(context.Background(), req) @@ -192,6 +195,7 @@ func TestCRBStatusController_syncBindingStatus(t *testing.T) { c := generateCRBStatusController() c.DynamicClient = dynamicfake.NewSimpleDynamicClient(scheme.Scheme, &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: tt.podNameInDynamicClient, Namespace: "default"}}) + c.ResourceInterpreter = FakeResourceInterpreter{DefaultInterpreter: native.NewDefaultInterpreter()} binding := &workv1alpha2.ClusterResourceBinding{ ObjectMeta: metav1.ObjectMeta{ @@ -204,12 +208,10 @@ func TestCRBStatusController_syncBindingStatus(t *testing.T) { } if tt.resourceExistInClient { - if err := c.Client.Create(context.Background(), binding); err != nil { - t.Fatalf("Failed to create binding: %v", err) - } + c.Client = fake.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects(binding).WithStatusSubresource(binding).Build() } - err := c.syncBindingStatus(binding) + err := c.syncBindingStatus(context.Background(), binding) if tt.expectedError { assert.Error(t, err) diff --git a/pkg/controllers/status/rb_status_controller.go b/pkg/controllers/status/rb_status_controller.go index ebe206b0073f..d5f1b8989732 100644 --- a/pkg/controllers/status/rb_status_controller.go +++ b/pkg/controllers/status/rb_status_controller.go @@ -75,7 +75,7 @@ func (c *RBStatusController) Reconcile(ctx context.Context, req controllerruntim return controllerruntime.Result{}, nil } - err := c.syncBindingStatus(binding) + err := c.syncBindingStatus(ctx, binding) if err != nil { return controllerruntime.Result{}, err } @@ -110,30 +110,18 @@ func (c *RBStatusController) SetupWithManager(mgr controllerruntime.Manager) err Complete(c) } -func (c *RBStatusController) syncBindingStatus(binding *workv1alpha2.ResourceBinding) error { - resourceTemplate, err := helper.FetchResourceTemplate(c.DynamicClient, c.InformerManager, c.RESTMapper, binding.Spec.Resource) +func (c *RBStatusController) syncBindingStatus(ctx context.Context, binding *workv1alpha2.ResourceBinding) error { + err := helper.AggregateResourceBindingWorkStatus(ctx, c.Client, binding, c.EventRecorder) if err != nil { - if apierrors.IsNotFound(err) { - // It might happen when the resource template has been removed but the garbage collector hasn't removed - // the ResourceBinding which dependent on resource template. - // So, just return without retry(requeue) would save unnecessary loop. - return nil - } - klog.Errorf("Failed to fetch workload for resourceBinding(%s/%s). Error: %v.", - binding.GetNamespace(), binding.GetName(), err) - return err - } - - err = helper.AggregateResourceBindingWorkStatus(c.Client, binding, resourceTemplate, c.EventRecorder) - if err != nil { - klog.Errorf("Failed to aggregate workStatues to resourceBinding(%s/%s), Error: %v", + klog.Errorf("Failed to aggregate workStatus to resourceBinding(%s/%s), Error: %v", binding.Namespace, binding.Name, err) return err } - err = updateResourceStatus(c.DynamicClient, c.RESTMapper, c.ResourceInterpreter, resourceTemplate, binding.Status) + err = updateResourceStatus(ctx, c.DynamicClient, c.RESTMapper, c.ResourceInterpreter, c.EventRecorder, binding.Spec.Resource, binding.Status) if err != nil { return err } + return nil } diff --git a/pkg/controllers/status/rb_status_controller_test.go b/pkg/controllers/status/rb_status_controller_test.go index 3cb946925dd8..537a07e8560e 100644 --- a/pkg/controllers/status/rb_status_controller_test.go +++ b/pkg/controllers/status/rb_status_controller_test.go @@ -34,6 +34,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/fake" workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" + "github.com/karmada-io/karmada/pkg/resourceinterpreter" + "github.com/karmada-io/karmada/pkg/resourceinterpreter/default/native" "github.com/karmada-io/karmada/pkg/util/fedinformer/genericmanager" "github.com/karmada-io/karmada/pkg/util/gclient" ) @@ -98,8 +100,11 @@ func TestRBStatusController_Reconcile(t *testing.T) { name: "failed in syncBindingStatus", binding: &workv1alpha2.ResourceBinding{ ObjectMeta: metav1.ObjectMeta{ - Name: "binding", - Namespace: "default", + Name: "binding", + Namespace: "default", + // finalizers field is required when deletionTimestamp is defined, otherwise will encounter the + // error: `refusing to create obj binding with metadata.deletionTimestamp but no finalizers`. + Finalizers: []string{"test"}, DeletionTimestamp: &preTime, }, Spec: workv1alpha2.ResourceBindingSpec{ @@ -119,6 +124,7 @@ func TestRBStatusController_Reconcile(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := generateRBStatusController() + c.ResourceInterpreter = FakeResourceInterpreter{DefaultInterpreter: native.NewDefaultInterpreter()} // Prepare req req := controllerruntime.Request{ @@ -130,9 +136,7 @@ func TestRBStatusController_Reconcile(t *testing.T) { // Prepare binding and create it in client if tt.binding != nil { - if err := c.Client.Create(context.Background(), tt.binding); err != nil { - t.Fatalf("Failed to create binding: %v", err) - } + c.Client = fake.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects(tt.binding).WithStatusSubresource(tt.binding).Build() } res, err := c.Reconcile(context.Background(), req) @@ -192,6 +196,7 @@ func TestRBStatusController_syncBindingStatus(t *testing.T) { c := generateRBStatusController() c.DynamicClient = dynamicfake.NewSimpleDynamicClient(scheme.Scheme, &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: tt.podNameInDynamicClient, Namespace: "default"}}) + c.ResourceInterpreter = FakeResourceInterpreter{DefaultInterpreter: native.NewDefaultInterpreter()} binding := &workv1alpha2.ResourceBinding{ ObjectMeta: metav1.ObjectMeta{ @@ -204,12 +209,10 @@ func TestRBStatusController_syncBindingStatus(t *testing.T) { } if tt.resourceExistInClient { - if err := c.Client.Create(context.Background(), binding); err != nil { - t.Fatalf("Failed to create binding: %v", err) - } + c.Client = fake.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects(binding).WithStatusSubresource(binding).Build() } - err := c.syncBindingStatus(binding) + err := c.syncBindingStatus(context.Background(), binding) if tt.expectedError { assert.Error(t, err) @@ -219,3 +222,13 @@ func TestRBStatusController_syncBindingStatus(t *testing.T) { }) } } + +var _ resourceinterpreter.ResourceInterpreter = &FakeResourceInterpreter{} + +type FakeResourceInterpreter struct { + *native.DefaultInterpreter +} + +func (f FakeResourceInterpreter) Start(_ context.Context) (err error) { + return nil +} diff --git a/pkg/controllers/status/work_status_controller.go b/pkg/controllers/status/work_status_controller.go index 670cf35aa476..90a21237ead9 100644 --- a/pkg/controllers/status/work_status_controller.go +++ b/pkg/controllers/status/work_status_controller.go @@ -183,6 +183,7 @@ func getClusterNameFromAnnotation(resource *unstructured.Unstructured) (string, // syncWorkStatus will collect status of object referencing by key and update to work which holds the object. func (c *WorkStatusController) syncWorkStatus(key util.QueueKey) error { + ctx := context.Background() fedKey, ok := key.(keys.FederatedKey) if !ok { klog.Errorf("Failed to sync status as invalid key: %v", key) @@ -192,7 +193,7 @@ func (c *WorkStatusController) syncWorkStatus(key util.QueueKey) error { observedObj, err := helper.GetObjectFromCache(c.RESTMapper, c.InformerManager, fedKey) if err != nil { if apierrors.IsNotFound(err) { - return c.handleDeleteEvent(fedKey) + return c.handleDeleteEvent(ctx, fedKey) } return err } @@ -206,7 +207,7 @@ func (c *WorkStatusController) syncWorkStatus(key util.QueueKey) error { } workObject := &workv1alpha1.Work{} - if err := c.Client.Get(context.TODO(), client.ObjectKey{Namespace: workNamespace, Name: workName}, workObject); err != nil { + if err := c.Client.Get(ctx, client.ObjectKey{Namespace: workNamespace, Name: workName}, workObject); err != nil { // Stop processing if the resource no longer exists. if apierrors.IsNotFound(err) { return nil @@ -221,12 +222,25 @@ func (c *WorkStatusController) syncWorkStatus(key util.QueueKey) error { return nil } + if err := c.updateResource(ctx, observedObj, workObject, fedKey); err != nil { + return err + } + + klog.Infof("Reflecting the resource(kind=%s, %s/%s) status to the Work(%s/%s).", observedObj.GetKind(), observedObj.GetNamespace(), observedObj.GetName(), workNamespace, workName) + return c.reflectStatus(ctx, workObject, observedObj) +} + +func (c *WorkStatusController) updateResource(ctx context.Context, observedObj *unstructured.Unstructured, workObject *workv1alpha1.Work, fedKey keys.FederatedKey) error { + if helper.IsWorkSuspendDispatching(workObject) { + return nil + } + desiredObj, err := c.getRawManifest(workObject.Spec.Workload.Manifests, observedObj) if err != nil { return err } - clusterName, err := names.GetClusterName(workNamespace) + clusterName, err := names.GetClusterName(workObject.Namespace) if err != nil { klog.Errorf("Failed to get member cluster name: %v", err) return err @@ -240,7 +254,7 @@ func (c *WorkStatusController) syncWorkStatus(key util.QueueKey) error { } if needUpdate { - updateErr := c.ObjectWatcher.Update(clusterName, desiredObj, observedObj) + updateErr := c.ObjectWatcher.Update(ctx, clusterName, desiredObj, observedObj) metrics.CountUpdateResourceToCluster(updateErr, desiredObj.GetAPIVersion(), desiredObj.GetKind(), clusterName) if updateErr != nil { klog.Errorf("Updating %s failed: %v", fedKey.String(), updateErr) @@ -254,19 +268,17 @@ func (c *WorkStatusController) syncWorkStatus(key util.QueueKey) error { // also needs to update again. The update operation will be a non-operation if the event triggered by Service's // status changes. } - - klog.Infof("Reflecting the resource(kind=%s, %s/%s) status to the Work(%s/%s).", observedObj.GetKind(), observedObj.GetNamespace(), observedObj.GetName(), workNamespace, workName) - return c.reflectStatus(workObject, observedObj) + return nil } -func (c *WorkStatusController) handleDeleteEvent(key keys.FederatedKey) error { +func (c *WorkStatusController) handleDeleteEvent(ctx context.Context, key keys.FederatedKey) error { executionSpace := names.GenerateExecutionSpaceName(key.Cluster) // Given the workload might have been deleted from informer cache, so that we can't get work object by its label, // we have to get work by naming rule as the work's name is generated by the workload's kind, name and namespace. workName := names.GenerateWorkName(key.Kind, key.Name, key.Namespace) work := &workv1alpha1.Work{} - if err := c.Client.Get(context.TODO(), client.ObjectKey{Namespace: executionSpace, Name: workName}, work); err != nil { + if err := c.Client.Get(ctx, client.ObjectKey{Namespace: executionSpace, Name: workName}, work); err != nil { // stop processing as the work object has been removed, assume it's a normal delete operation. if apierrors.IsNotFound(err) { return nil @@ -285,17 +297,17 @@ func (c *WorkStatusController) handleDeleteEvent(key keys.FederatedKey) error { return nil } - reCreateErr := c.recreateResourceIfNeeded(work, key) + reCreateErr := c.recreateResourceIfNeeded(ctx, work, key) metrics.CountRecreateResourceToCluster(reCreateErr, key.GroupVersion().String(), key.Kind, key.Cluster) if reCreateErr != nil { - c.updateAppliedCondition(work, metav1.ConditionFalse, "ReCreateFailed", reCreateErr.Error()) + c.updateAppliedCondition(ctx, work, metav1.ConditionFalse, "ReCreateFailed", reCreateErr.Error()) return reCreateErr } - c.updateAppliedCondition(work, metav1.ConditionTrue, "ReCreateSuccessful", "Manifest has been successfully applied") + c.updateAppliedCondition(ctx, work, metav1.ConditionTrue, "ReCreateSuccessful", "Manifest has been successfully applied") return nil } -func (c *WorkStatusController) recreateResourceIfNeeded(work *workv1alpha1.Work, workloadKey keys.FederatedKey) error { +func (c *WorkStatusController) recreateResourceIfNeeded(ctx context.Context, work *workv1alpha1.Work, workloadKey keys.FederatedKey) error { for _, rawManifest := range work.Spec.Workload.Manifests { manifest := &unstructured.Unstructured{} if err := manifest.UnmarshalJSON(rawManifest.Raw); err != nil { @@ -307,7 +319,7 @@ func (c *WorkStatusController) recreateResourceIfNeeded(work *workv1alpha1.Work, manifest.GetNamespace() == workloadKey.Namespace && manifest.GetName() == workloadKey.Name { klog.Infof("Recreating resource(%s).", workloadKey.String()) - err := c.ObjectWatcher.Create(workloadKey.Cluster, manifest) + err := c.ObjectWatcher.Create(ctx, workloadKey.Cluster, manifest) if err != nil { c.eventf(manifest, corev1.EventTypeWarning, events.EventReasonSyncWorkloadFailed, "Failed to create or update resource(%s/%s) in member cluster(%s): %v", manifest.GetNamespace(), manifest.GetName(), workloadKey.Cluster, err) return err @@ -320,7 +332,7 @@ func (c *WorkStatusController) recreateResourceIfNeeded(work *workv1alpha1.Work, } // updateAppliedCondition update the condition for the given Work -func (c *WorkStatusController) updateAppliedCondition(work *workv1alpha1.Work, status metav1.ConditionStatus, reason, message string) { +func (c *WorkStatusController) updateAppliedCondition(ctx context.Context, work *workv1alpha1.Work, status metav1.ConditionStatus, reason, message string) { newWorkAppliedCondition := metav1.Condition{ Type: workv1alpha1.WorkApplied, Status: status, @@ -330,7 +342,7 @@ func (c *WorkStatusController) updateAppliedCondition(work *workv1alpha1.Work, s } err := retry.RetryOnConflict(retry.DefaultRetry, func() (err error) { - _, err = helper.UpdateStatus(context.Background(), c.Client, work, func() error { + _, err = helper.UpdateStatus(ctx, c.Client, work, func() error { meta.SetStatusCondition(&work.Status.Conditions, newWorkAppliedCondition) return nil }) @@ -343,7 +355,7 @@ func (c *WorkStatusController) updateAppliedCondition(work *workv1alpha1.Work, s } // reflectStatus grabs cluster object's running status then updates to its owner object(Work). -func (c *WorkStatusController) reflectStatus(work *workv1alpha1.Work, clusterObj *unstructured.Unstructured) error { +func (c *WorkStatusController) reflectStatus(ctx context.Context, work *workv1alpha1.Work, clusterObj *unstructured.Unstructured) error { statusRaw, err := c.ResourceInterpreter.ReflectStatus(clusterObj) if err != nil { klog.Errorf("Failed to reflect status for object(%s/%s/%s) with resourceInterpreter, err: %v", @@ -380,7 +392,7 @@ func (c *WorkStatusController) reflectStatus(work *workv1alpha1.Work, clusterObj } return retry.RetryOnConflict(retry.DefaultRetry, func() (err error) { - _, err = helper.UpdateStatus(context.Background(), c.Client, work, func() error { + _, err = helper.UpdateStatus(ctx, c.Client, work, func() error { work.Status.ManifestStatuses = c.mergeStatus(work.Status.ManifestStatuses, manifestStatus) return nil }) @@ -389,7 +401,9 @@ func (c *WorkStatusController) reflectStatus(work *workv1alpha1.Work, clusterObj } func (c *WorkStatusController) buildStatusIdentifier(work *workv1alpha1.Work, clusterObj *unstructured.Unstructured) (*workv1alpha1.ResourceIdentifier, error) { - ordinal, err := helper.GetManifestIndex(work.Spec.Workload.Manifests, clusterObj) + manifestRef := helper.ManifestReference{APIVersion: clusterObj.GetAPIVersion(), Kind: clusterObj.GetKind(), + Namespace: clusterObj.GetNamespace(), Name: clusterObj.GetName()} + ordinal, err := helper.GetManifestIndex(work.Spec.Workload.Manifests, &manifestRef) if err != nil { return nil, err } diff --git a/pkg/controllers/status/work_status_controller_test.go b/pkg/controllers/status/work_status_controller_test.go index 5e5f6bb6b49a..11563539d767 100644 --- a/pkg/controllers/status/work_status_controller_test.go +++ b/pkg/controllers/status/work_status_controller_test.go @@ -32,16 +32,16 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" dynamicfake "k8s.io/client-go/dynamic/fake" - "k8s.io/client-go/informers" - kubernetesfake "k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/tools/record" + "k8s.io/utils/ptr" controllerruntime "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client/fake" clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1" workv1alpha1 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha1" workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" - "github.com/karmada-io/karmada/pkg/resourceinterpreter" + "github.com/karmada-io/karmada/pkg/resourceinterpreter/default/native" "github.com/karmada-io/karmada/pkg/sharedcli/ratelimiterflag" "github.com/karmada-io/karmada/pkg/util" "github.com/karmada-io/karmada/pkg/util/fedinformer/genericmanager" @@ -571,10 +571,9 @@ func TestWorkStatusController_syncWorkStatus(t *testing.T) { pod *corev1.Pod raw []byte controllerWithoutInformer bool - workWithRightNS bool expectedError bool - workWithDeletionTimestamp bool wrongWorkNS bool + workApplyFunc func(work *workv1alpha1.Work) }{ { name: "failed to exec NeedUpdate", @@ -582,7 +581,6 @@ func TestWorkStatusController_syncWorkStatus(t *testing.T) { pod: newPod(workNs, workName), raw: []byte(`{"apiVersion":"v1","kind":"Pod","metadata":{"name":"pod","namespace":"default"}}`), controllerWithoutInformer: true, - workWithRightNS: true, expectedError: true, }, { @@ -591,7 +589,6 @@ func TestWorkStatusController_syncWorkStatus(t *testing.T) { pod: newPod(workNs, workName), raw: []byte(`{"apiVersion":"v1","kind":"Pod","metadata":{"name":"pod","namespace":"default"}}`), controllerWithoutInformer: true, - workWithRightNS: true, expectedError: true, }, { @@ -600,7 +597,6 @@ func TestWorkStatusController_syncWorkStatus(t *testing.T) { pod: newPod(workNs, workName), raw: []byte(`{"apiVersion":"v1","kind":"Pod","metadata":{"name":"pod","namespace":"default"}}`), controllerWithoutInformer: false, - workWithRightNS: true, expectedError: true, }, { @@ -608,7 +604,6 @@ func TestWorkStatusController_syncWorkStatus(t *testing.T) { obj: newPodObj("karmada-es-cluster"), raw: []byte(`{"apiVersion":"v1","kind":"Pod","metadata":{"name":"pod","namespace":"default"}}`), controllerWithoutInformer: true, - workWithRightNS: true, expectedError: false, }, { @@ -617,7 +612,6 @@ func TestWorkStatusController_syncWorkStatus(t *testing.T) { pod: newPod(workNs, workName, true), raw: []byte(`{"apiVersion":"v1","kind":"Pod","metadata":{"name":"pod","namespace":"default"}}`), controllerWithoutInformer: true, - workWithRightNS: true, expectedError: false, }, { @@ -626,8 +620,10 @@ func TestWorkStatusController_syncWorkStatus(t *testing.T) { pod: newPod(workNs, workName), raw: []byte(`{"apiVersion":"v1","kind":"Pod","metadata":{"name":"pod","namespace":"default"}}`), controllerWithoutInformer: true, - workWithRightNS: false, expectedError: false, + workApplyFunc: func(work *workv1alpha1.Work) { + work.SetName(fmt.Sprintf("%v-test", workNs)) + }, }, { name: "failed to getRawManifest, wrong Manifests in work", @@ -635,7 +631,6 @@ func TestWorkStatusController_syncWorkStatus(t *testing.T) { pod: newPod(workNs, workName), raw: []byte(`{"apiVersion":"v1","kind":"Pod","metadata":{"name":"pod1","namespace":"default"}}`), controllerWithoutInformer: true, - workWithRightNS: true, expectedError: true, }, { @@ -644,10 +639,31 @@ func TestWorkStatusController_syncWorkStatus(t *testing.T) { pod: newPod(workNs, workName), raw: []byte(`{"apiVersion":"v1","kind":"Pod","metadata":{"name":"pod","namespace":"default"}}`), controllerWithoutInformer: true, - workWithRightNS: true, expectedError: true, wrongWorkNS: true, }, + { + name: "skips work with suspend dispatching", + obj: newPodObj("karmada-es-cluster"), + pod: newPod(workNs, workName), + raw: []byte(`{"apiVersion":"v1","kind":"Pod","metadata":{"name":"pod","namespace":"default"}}`), + controllerWithoutInformer: true, + expectedError: false, + workApplyFunc: func(work *workv1alpha1.Work) { + work.Spec.SuspendDispatching = ptr.To(true) + }, + }, + { + name: "skips work with deletion timestamp", + obj: newPodObj("karmada-es-cluster"), + pod: newPod(workNs, workName), + raw: []byte(`{"apiVersion":"v1","kind":"Pod","metadata":{"name":"pod","namespace":"default"}}`), + controllerWithoutInformer: true, + expectedError: false, + workApplyFunc: func(work *workv1alpha1.Work) { + work.SetDeletionTimestamp(ptr.To(metav1.Now())) + }, + }, } for _, tt := range tests { @@ -671,11 +687,9 @@ func TestWorkStatusController_syncWorkStatus(t *testing.T) { c = newWorkStatusController(cluster) } - var work *workv1alpha1.Work - if tt.workWithRightNS { - work = testhelper.NewWork(workName, workNs, workUID, tt.raw) - } else { - work = testhelper.NewWork(workName, fmt.Sprintf("%v-test", workNs), workUID, tt.raw) + work := testhelper.NewWork(workName, workNs, workUID, tt.raw) + if tt.workApplyFunc != nil { + tt.workApplyFunc(work) } key, _ := generateKey(tt.obj) @@ -686,9 +700,9 @@ func TestWorkStatusController_syncWorkStatus(t *testing.T) { err := c.syncWorkStatus(key) if tt.expectedError { - assert.NotEmpty(t, err) + assert.Error(t, err) } else { - assert.Empty(t, err) + assert.NoError(t, err) } }) } @@ -696,13 +710,14 @@ func TestWorkStatusController_syncWorkStatus(t *testing.T) { func newWorkStatusController(cluster *clusterv1alpha1.Cluster, dynamicClientSets ...*dynamicfake.FakeDynamicClient) WorkStatusController { c := WorkStatusController{ - Client: fake.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects(cluster).Build(), + Client: fake.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects(cluster).WithStatusSubresource().Build(), InformerManager: genericmanager.GetInstance(), PredicateFunc: helper.NewClusterPredicateOnAgent("test"), ClusterDynamicClientSetFunc: util.NewClusterDynamicClientSetForAgent, ClusterCacheSyncTimeout: metav1.Duration{}, RateLimiterOptions: ratelimiterflag.Options{}, eventHandler: nil, + EventRecorder: record.NewFakeRecorder(1024), RESTMapper: func() meta.RESTMapper { m := meta.NewDefaultRESTMapper([]schema.GroupVersion{corev1.SchemeGroupVersion}) m.Add(corev1.SchemeGroupVersion.WithKind("Pod"), meta.RESTScopeNamespace) @@ -711,21 +726,15 @@ func newWorkStatusController(cluster *clusterv1alpha1.Cluster, dynamicClientSets } if len(dynamicClientSets) > 0 { + c.ResourceInterpreter = FakeResourceInterpreter{DefaultInterpreter: native.NewDefaultInterpreter()} + c.ObjectWatcher = objectwatcher.NewObjectWatcher(c.Client, c.RESTMapper, util.NewClusterDynamicClientSetForAgent, c.ResourceInterpreter) + + // Generate InformerManager clusterName := cluster.Name dynamicClientSet := dynamicClientSets[0] // Generate ResourceInterpreter and ObjectWatcher stopCh := make(chan struct{}) defer close(stopCh) - - controlPlaneInformerManager := genericmanager.NewSingleClusterInformerManager(dynamicClientSet, 0, stopCh) - controlPlaneKubeClientSet := kubernetesfake.NewSimpleClientset() - sharedFactory := informers.NewSharedInformerFactory(controlPlaneKubeClientSet, 0) - serviceLister := sharedFactory.Core().V1().Services().Lister() - - c.ResourceInterpreter = resourceinterpreter.NewResourceInterpreter(controlPlaneInformerManager, serviceLister) - c.ObjectWatcher = objectwatcher.NewObjectWatcher(c.Client, c.RESTMapper, util.NewClusterDynamicClientSetForAgent, c.ResourceInterpreter) - - // Generate InformerManager m := genericmanager.NewMultiClusterInformerManager(stopCh) m.ForCluster(clusterName, dynamicClientSet, 0).Lister(corev1.SchemeGroupVersion.WithResource("pods")) // register pod informer m.Start(clusterName) @@ -866,13 +875,13 @@ func TestWorkStatusController_recreateResourceIfNeeded(t *testing.T) { } t.Run("normal case", func(t *testing.T) { - err := c.recreateResourceIfNeeded(work, fedKey) + err := c.recreateResourceIfNeeded(context.Background(), work, fedKey) assert.Empty(t, err) }) t.Run("failed to UnmarshalJSON", func(t *testing.T) { work.Spec.Workload.Manifests[0].RawExtension.Raw = []byte(`{"apiVersion":"v1","kind":"Pod","metadata":{"name":"pod","namespace":"default"}},`) - err := c.recreateResourceIfNeeded(work, fedKey) + err := c.recreateResourceIfNeeded(context.Background(), work, fedKey) assert.NotEmpty(t, err) }) } diff --git a/pkg/controllers/unifiedauth/unified_auth_controller.go b/pkg/controllers/unifiedauth/unified_auth_controller.go index d5b6814a7d87..e645da0aeb25 100644 --- a/pkg/controllers/unifiedauth/unified_auth_controller.go +++ b/pkg/controllers/unifiedauth/unified_auth_controller.go @@ -86,7 +86,7 @@ func (c *Controller) Reconcile(ctx context.Context, req controllerruntime.Reques return controllerruntime.Result{}, nil } - err := c.syncImpersonationConfig(cluster) + err := c.syncImpersonationConfig(ctx, cluster) if err != nil { klog.Errorf("Failed to sync impersonation config for cluster %s. Error: %v.", cluster.Name, err) c.EventRecorder.Eventf(cluster, corev1.EventTypeWarning, events.EventReasonSyncImpersonationConfigFailed, err.Error()) @@ -97,9 +97,9 @@ func (c *Controller) Reconcile(ctx context.Context, req controllerruntime.Reques return controllerruntime.Result{}, nil } -func (c *Controller) syncImpersonationConfig(cluster *clusterv1alpha1.Cluster) error { +func (c *Controller) syncImpersonationConfig(ctx context.Context, cluster *clusterv1alpha1.Cluster) error { // step1: find out target RBAC subjects. - targetSubjects, err := findRBACSubjectsWithCluster(c.Client, cluster.Name) + targetSubjects, err := findRBACSubjectsWithCluster(ctx, c.Client, cluster.Name) if err != nil { return err } @@ -108,13 +108,13 @@ func (c *Controller) syncImpersonationConfig(cluster *clusterv1alpha1.Cluster) e rules := util.GenerateImpersonationRules(targetSubjects) // step3: sync ClusterRole to cluster for impersonation - if err := c.buildImpersonationClusterRole(cluster, rules); err != nil { + if err := c.buildImpersonationClusterRole(ctx, cluster, rules); err != nil { klog.Errorf("Failed to sync impersonate ClusterRole to cluster(%s): %v", cluster.Name, err) return err } // step4: sync ClusterRoleBinding to cluster for impersonation - if err := c.buildImpersonationClusterRoleBinding(cluster); err != nil { + if err := c.buildImpersonationClusterRoleBinding(ctx, cluster); err != nil { klog.Errorf("Failed to sync impersonate ClusterRoleBinding to cluster(%s): %v", cluster.Name, err) return err } @@ -122,9 +122,9 @@ func (c *Controller) syncImpersonationConfig(cluster *clusterv1alpha1.Cluster) e return nil } -func findRBACSubjectsWithCluster(c client.Client, cluster string) ([]rbacv1.Subject, error) { +func findRBACSubjectsWithCluster(ctx context.Context, c client.Client, cluster string) ([]rbacv1.Subject, error) { clusterRoleList := &rbacv1.ClusterRoleList{} - if err := c.List(context.TODO(), clusterRoleList); err != nil { + if err := c.List(ctx, clusterRoleList); err != nil { klog.Errorf("Failed to list ClusterRoles, error: %v", err) return nil, err } @@ -153,7 +153,7 @@ func findRBACSubjectsWithCluster(c client.Client, cluster string) ([]rbacv1.Subj } clusterRoleBindings := &rbacv1.ClusterRoleBindingList{} - if err := c.List(context.TODO(), clusterRoleBindings); err != nil { + if err := c.List(ctx, clusterRoleBindings); err != nil { klog.Errorf("Failed to list ClusterRoleBindings, error: %v", err) return nil, err } @@ -168,7 +168,7 @@ func findRBACSubjectsWithCluster(c client.Client, cluster string) ([]rbacv1.Subj return targetSubjects, nil } -func (c *Controller) buildImpersonationClusterRole(cluster *clusterv1alpha1.Cluster, rules []rbacv1.PolicyRule) error { +func (c *Controller) buildImpersonationClusterRole(ctx context.Context, cluster *clusterv1alpha1.Cluster, rules []rbacv1.PolicyRule) error { impersonationClusterRole := &rbacv1.ClusterRole{ TypeMeta: metav1.TypeMeta{ APIVersion: rbacv1.SchemeGroupVersion.String(), @@ -189,10 +189,10 @@ func (c *Controller) buildImpersonationClusterRole(cluster *clusterv1alpha1.Clus return err } - return c.buildWorks(cluster, clusterRoleObj) + return c.buildWorks(ctx, cluster, clusterRoleObj) } -func (c *Controller) buildImpersonationClusterRoleBinding(cluster *clusterv1alpha1.Cluster) error { +func (c *Controller) buildImpersonationClusterRoleBinding(ctx context.Context, cluster *clusterv1alpha1.Cluster) error { impersonatorClusterRoleBinding := &rbacv1.ClusterRoleBinding{ TypeMeta: metav1.TypeMeta{ APIVersion: rbacv1.SchemeGroupVersion.String(), @@ -224,10 +224,10 @@ func (c *Controller) buildImpersonationClusterRoleBinding(cluster *clusterv1alph return err } - return c.buildWorks(cluster, clusterRoleBindingObj) + return c.buildWorks(ctx, cluster, clusterRoleBindingObj) } -func (c *Controller) buildWorks(cluster *clusterv1alpha1.Cluster, obj *unstructured.Unstructured) error { +func (c *Controller) buildWorks(ctx context.Context, cluster *clusterv1alpha1.Cluster, obj *unstructured.Unstructured) error { objectMeta := metav1.ObjectMeta{ Name: names.GenerateWorkName(obj.GetKind(), obj.GetName(), obj.GetNamespace()), Namespace: names.GenerateExecutionSpaceName(cluster.Name), @@ -237,7 +237,7 @@ func (c *Controller) buildWorks(cluster *clusterv1alpha1.Cluster, obj *unstructu }, } - if err := helper.CreateOrUpdateWork(c.Client, objectMeta, obj, nil); err != nil { + if err := helper.CreateOrUpdateWork(ctx, c.Client, objectMeta, obj, nil); err != nil { return err } @@ -262,32 +262,32 @@ func (c *Controller) SetupWithManager(mgr controllerruntime.Manager) error { } func (c *Controller) newClusterRoleMapFunc() handler.MapFunc { - return func(_ context.Context, a client.Object) []reconcile.Request { + return func(ctx context.Context, a client.Object) []reconcile.Request { clusterRole := a.(*rbacv1.ClusterRole) - return c.generateRequestsFromClusterRole(clusterRole) + return c.generateRequestsFromClusterRole(ctx, clusterRole) } } func (c *Controller) newClusterRoleBindingMapFunc() handler.MapFunc { - return func(_ context.Context, a client.Object) []reconcile.Request { + return func(ctx context.Context, a client.Object) []reconcile.Request { clusterRoleBinding := a.(*rbacv1.ClusterRoleBinding) if clusterRoleBinding.RoleRef.Kind != util.ClusterRoleKind { return nil } clusterRole := &rbacv1.ClusterRole{} - if err := c.Client.Get(context.TODO(), types.NamespacedName{Name: clusterRoleBinding.RoleRef.Name}, clusterRole); err != nil { + if err := c.Client.Get(ctx, types.NamespacedName{Name: clusterRoleBinding.RoleRef.Name}, clusterRole); err != nil { klog.Errorf("Failed to get reference ClusterRole, error: %v", err) return nil } - return c.generateRequestsFromClusterRole(clusterRole) + return c.generateRequestsFromClusterRole(ctx, clusterRole) } } // generateRequestsFromClusterRole generates the requests for which clusters need be synced with impersonation config. -func (c *Controller) generateRequestsFromClusterRole(clusterRole *rbacv1.ClusterRole) []reconcile.Request { +func (c *Controller) generateRequestsFromClusterRole(ctx context.Context, clusterRole *rbacv1.ClusterRole) []reconcile.Request { clusterList := &clusterv1alpha1.ClusterList{} - if err := c.Client.List(context.TODO(), clusterList); err != nil { + if err := c.Client.List(ctx, clusterList); err != nil { klog.Errorf("Failed to list existing clusters, error: %v", err) return nil } diff --git a/pkg/controllers/unifiedauth/unified_auth_controller_test.go b/pkg/controllers/unifiedauth/unified_auth_controller_test.go index b5932937ee0d..7122af35c8ca 100644 --- a/pkg/controllers/unifiedauth/unified_auth_controller_test.go +++ b/pkg/controllers/unifiedauth/unified_auth_controller_test.go @@ -17,6 +17,7 @@ limitations under the License. package unifiedauth import ( + "context" "reflect" "testing" @@ -104,7 +105,7 @@ func Test_findRBACSubjectsWithCluster(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := findRBACSubjectsWithCluster(tt.args.c, tt.args.cluster) + got, err := findRBACSubjectsWithCluster(context.Background(), tt.args.c, tt.args.cluster) if (err != nil) != tt.wantErr { t.Errorf("findRBACSubjectsWithCluster() error = %v, wantErr %v", err, tt.wantErr) return @@ -267,7 +268,7 @@ func TestController_generateRequestsFromClusterRole(t *testing.T) { Client: tt.fields.Client, EventRecorder: tt.fields.EventRecorder, } - if got := c.generateRequestsFromClusterRole(tt.args.clusterRole); !reflect.DeepEqual(got, tt.want) { + if got := c.generateRequestsFromClusterRole(context.Background(), tt.args.clusterRole); !reflect.DeepEqual(got, tt.want) { t.Errorf("generateRequestsFromClusterRole() = %v, want %v", got, tt.want) } }) diff --git a/pkg/dependenciesdistributor/dependencies_distributor.go b/pkg/dependenciesdistributor/dependencies_distributor.go index 981b9bc60149..7dad0ba3c149 100644 --- a/pkg/dependenciesdistributor/dependencies_distributor.go +++ b/pkg/dependenciesdistributor/dependencies_distributor.go @@ -258,7 +258,7 @@ func (d *DependenciesDistributor) Reconcile(ctx context.Context, request reconci return reconcile.Result{}, d.removeFinalizer(ctx, bindingObject) } - workload, err := helper.FetchResourceTemplate(d.DynamicClient, d.InformerManager, d.RESTMapper, bindingObject.Spec.Resource) + workload, err := helper.FetchResourceTemplate(ctx, d.DynamicClient, d.InformerManager, d.RESTMapper, bindingObject.Spec.Resource) if err != nil { klog.Errorf("Failed to fetch workload for resourceBinding(%s): %v.", request.NamespacedName, err) return reconcile.Result{}, err @@ -280,7 +280,7 @@ func (d *DependenciesDistributor) Reconcile(ctx context.Context, request reconci klog.Errorf("Failed to add finalizer(%s) for ResourceBinding(%s): %v", util.BindingDependenciesDistributorFinalizer, request.NamespacedName, err) return reconcile.Result{}, err } - return reconcile.Result{}, d.syncScheduleResultToAttachedBindings(bindingObject, dependencies) + return reconcile.Result{}, d.syncScheduleResultToAttachedBindings(ctx, bindingObject, dependencies) } func (d *DependenciesDistributor) addFinalizer(ctx context.Context, independentBinding *workv1alpha2.ResourceBinding) error { @@ -306,9 +306,9 @@ func (d *DependenciesDistributor) handleIndependentBindingDeletion(id, namespace return d.removeScheduleResultFromAttachedBindings(namespace, name, attachedBindings) } -func (d *DependenciesDistributor) removeOrphanAttachedBindings(independentBinding *workv1alpha2.ResourceBinding, dependencies []configv1alpha1.DependentObjectReference) error { +func (d *DependenciesDistributor) removeOrphanAttachedBindings(ctx context.Context, independentBinding *workv1alpha2.ResourceBinding, dependencies []configv1alpha1.DependentObjectReference) error { // remove orphan attached bindings - orphanBindings, err := d.findOrphanAttachedBindings(independentBinding, dependencies) + orphanBindings, err := d.findOrphanAttachedBindings(ctx, independentBinding, dependencies) if err != nil { klog.Errorf("Failed to find orphan attached bindings for resourceBinding(%s/%s). Error: %v.", independentBinding.GetNamespace(), independentBinding.GetName(), err) @@ -324,6 +324,7 @@ func (d *DependenciesDistributor) removeOrphanAttachedBindings(independentBindin } func (d *DependenciesDistributor) handleDependentResource( + ctx context.Context, independentBinding *workv1alpha2.ResourceBinding, dependent configv1alpha1.DependentObjectReference) error { objRef := workv1alpha2.ObjectReference{ @@ -335,7 +336,7 @@ func (d *DependenciesDistributor) handleDependentResource( switch { case len(dependent.Name) != 0: - rawObject, err := helper.FetchResourceTemplate(d.DynamicClient, d.InformerManager, d.RESTMapper, objRef) + rawObject, err := helper.FetchResourceTemplate(ctx, d.DynamicClient, d.InformerManager, d.RESTMapper, objRef) if err != nil { // do nothing if resource template not exist. if apierrors.IsNotFound(err) { @@ -367,7 +368,7 @@ func (d *DependenciesDistributor) handleDependentResource( return fmt.Errorf("the Name and LabelSelector in the DependentObjectReference cannot be empty at the same time") } -func (d *DependenciesDistributor) syncScheduleResultToAttachedBindings(independentBinding *workv1alpha2.ResourceBinding, dependencies []configv1alpha1.DependentObjectReference) (err error) { +func (d *DependenciesDistributor) syncScheduleResultToAttachedBindings(ctx context.Context, independentBinding *workv1alpha2.ResourceBinding, dependencies []configv1alpha1.DependentObjectReference) (err error) { defer func() { if err != nil { d.EventRecorder.Eventf(independentBinding, corev1.EventTypeWarning, events.EventReasonSyncScheduleResultToDependenciesFailed, err.Error()) @@ -376,10 +377,10 @@ func (d *DependenciesDistributor) syncScheduleResultToAttachedBindings(independe } }() - if err = d.recordDependencies(independentBinding, dependencies); err != nil { + if err = d.recordDependencies(ctx, independentBinding, dependencies); err != nil { return err } - if err = d.removeOrphanAttachedBindings(independentBinding, dependencies); err != nil { + if err = d.removeOrphanAttachedBindings(ctx, independentBinding, dependencies); err != nil { return err } @@ -396,7 +397,7 @@ func (d *DependenciesDistributor) syncScheduleResultToAttachedBindings(independe d.InformerManager.ForResource(gvr, d.eventHandler) startInformerManager = true } - errs = append(errs, d.handleDependentResource(independentBinding, dependent)) + errs = append(errs, d.handleDependentResource(ctx, independentBinding, dependent)) } if startInformerManager { d.InformerManager.Start() @@ -405,7 +406,7 @@ func (d *DependenciesDistributor) syncScheduleResultToAttachedBindings(independe return utilerrors.NewAggregate(errs) } -func (d *DependenciesDistributor) recordDependencies(independentBinding *workv1alpha2.ResourceBinding, dependencies []configv1alpha1.DependentObjectReference) error { +func (d *DependenciesDistributor) recordDependencies(ctx context.Context, independentBinding *workv1alpha2.ResourceBinding, dependencies []configv1alpha1.DependentObjectReference) error { bindingKey := client.ObjectKey{Namespace: independentBinding.Namespace, Name: independentBinding.Name} dependenciesBytes, err := json.Marshal(dependencies) @@ -428,13 +429,13 @@ func (d *DependenciesDistributor) recordDependencies(independentBinding *workv1a return retry.RetryOnConflict(retry.DefaultRetry, func() (err error) { independentBinding.SetAnnotations(objectAnnotation) - updateErr := d.Client.Update(context.TODO(), independentBinding) + updateErr := d.Client.Update(ctx, independentBinding) if updateErr == nil { return nil } updated := &workv1alpha2.ResourceBinding{} - if err = d.Client.Get(context.TODO(), bindingKey, updated); err == nil { + if err = d.Client.Get(ctx, bindingKey, updated); err == nil { independentBinding = updated } else { klog.Errorf("Failed to get updated binding(%s): %v", bindingKey, err) @@ -443,7 +444,7 @@ func (d *DependenciesDistributor) recordDependencies(independentBinding *workv1a }) } -func (d *DependenciesDistributor) findOrphanAttachedBindings(independentBinding *workv1alpha2.ResourceBinding, dependencies []configv1alpha1.DependentObjectReference) ([]*workv1alpha2.ResourceBinding, error) { +func (d *DependenciesDistributor) findOrphanAttachedBindings(ctx context.Context, independentBinding *workv1alpha2.ResourceBinding, dependencies []configv1alpha1.DependentObjectReference) ([]*workv1alpha2.ResourceBinding, error) { attachedBindings, err := d.listAttachedBindings(independentBinding.Labels[workv1alpha2.ResourceBindingPermanentIDLabel], independentBinding.Namespace, independentBinding.Name) if err != nil { @@ -464,7 +465,7 @@ func (d *DependenciesDistributor) findOrphanAttachedBindings(independentBinding orphanAttachedBindings = append(orphanAttachedBindings, attachedBinding) continue } - isOrphanAttachedBinding, err := d.isOrphanAttachedBindings(dependencies, dependencyIndexes, attachedBinding) + isOrphanAttachedBinding, err := d.isOrphanAttachedBindings(ctx, dependencies, dependencyIndexes, attachedBinding) if err != nil { return nil, err } @@ -476,6 +477,7 @@ func (d *DependenciesDistributor) findOrphanAttachedBindings(independentBinding } func (d *DependenciesDistributor) isOrphanAttachedBindings( + ctx context.Context, dependencies []configv1alpha1.DependentObjectReference, dependencyIndexes []int, attachedBinding *workv1alpha2.ResourceBinding) (bool, error) { @@ -493,7 +495,7 @@ func (d *DependenciesDistributor) isOrphanAttachedBindings( if selector, err = metav1.LabelSelectorAsSelector(dependency.LabelSelector); err != nil { return false, err } - rawObject, err := helper.FetchResourceTemplate(d.DynamicClient, d.InformerManager, d.RESTMapper, workv1alpha2.ObjectReference{ + rawObject, err := helper.FetchResourceTemplate(ctx, d.DynamicClient, d.InformerManager, d.RESTMapper, workv1alpha2.ObjectReference{ APIVersion: resource.APIVersion, Kind: resource.Kind, Namespace: resource.Namespace, diff --git a/pkg/dependenciesdistributor/dependencies_distributor_test.go b/pkg/dependenciesdistributor/dependencies_distributor_test.go index 4e57622ffa42..4637901009d3 100644 --- a/pkg/dependenciesdistributor/dependencies_distributor_test.go +++ b/pkg/dependenciesdistributor/dependencies_distributor_test.go @@ -24,13 +24,19 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/client-go/dynamic" dynamicfake "k8s.io/client-go/dynamic/fake" "k8s.io/client-go/kubernetes/scheme" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1" workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" + "github.com/karmada-io/karmada/pkg/util" "github.com/karmada-io/karmada/pkg/util/fedinformer/genericmanager" "github.com/karmada-io/karmada/pkg/util/fedinformer/keys" ) @@ -246,7 +252,7 @@ func TestDependenciesDistributor_findOrphanAttachedBindingsByDependencies(t *tes InformerManager: tt.fields.InformerManager, RESTMapper: tt.fields.RESTMapper, } - got, err := d.isOrphanAttachedBindings(tt.args.dependencies, tt.args.dependencyIndexes, tt.args.attachedBinding) + got, err := d.isOrphanAttachedBindings(context.Background(), tt.args.dependencies, tt.args.dependencyIndexes, tt.args.attachedBinding) if (err != nil) != tt.wantErr { t.Errorf("findOrphanAttachedBindingsByDependencies() error = %v, wantErr %v", err, tt.wantErr) return @@ -257,3 +263,1228 @@ func TestDependenciesDistributor_findOrphanAttachedBindingsByDependencies(t *tes }) } } + +func Test_listAttachedBindings(t *testing.T) { + Scheme := runtime.NewScheme() + utilruntime.Must(scheme.AddToScheme(Scheme)) + utilruntime.Must(workv1alpha2.Install(Scheme)) + tests := []struct { + name string + bindingID string + bindingNamespace string + bindingName string + wantErr bool + wantBindings []*workv1alpha2.ResourceBinding + setupClient func() client.Client + }{ + { + name: "list attached bindings", + bindingID: "93162d3c-ee8e-4995-9034-05f4d5d2c2b9", + bindingNamespace: "test", + bindingName: "test-binding", + wantErr: false, + wantBindings: []*workv1alpha2.ResourceBinding{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-binding", + Namespace: "test", + ResourceVersion: "1000", + Labels: map[string]string{ + "app": "nginx", + "resourcebinding.karmada.io/depended-by-5dbb6dc9c8": "93162d3c-ee8e-4995-9034-05f4d5d2c2b9", + }, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "fake-ns", + Name: "demo-app", + ResourceVersion: "22222", + }, + RequiredBy: []workv1alpha2.BindingSnapshot{ + { + Namespace: "test", + Name: "test-binding", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "foo", + Replicas: 1, + }, + }, + }, + { + Namespace: "default-1", + Name: "default-binding-1", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member1", + Replicas: 2, + }, + }, + }, + { + Namespace: "test", + Name: "test-binding", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "bar", + Replicas: 1, + }, + }, + }, + }, + }, + }, + }, + setupClient: func() client.Client { + rb := &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-binding", + Namespace: "test", + ResourceVersion: "1000", + Labels: map[string]string{ + "app": "nginx", + "resourcebinding.karmada.io/depended-by-5dbb6dc9c8": "93162d3c-ee8e-4995-9034-05f4d5d2c2b9", + }, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "fake-ns", + Name: "demo-app", + ResourceVersion: "22222", + }, + RequiredBy: []workv1alpha2.BindingSnapshot{ + { + Namespace: "test", + Name: "test-binding", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "foo", + Replicas: 1, + }, + }, + }, + { + Namespace: "default-1", + Name: "default-binding-1", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member1", + Replicas: 2, + }, + }, + }, + { + Namespace: "test", + Name: "test-binding", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "bar", + Replicas: 1, + }, + }, + }, + }, + }, + } + return fake.NewClientBuilder().WithScheme(Scheme).WithObjects(rb).Build() + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + d := &DependenciesDistributor{ + Client: tt.setupClient(), + } + gotBindings, err := d.listAttachedBindings(tt.bindingID, tt.bindingNamespace, tt.bindingName) + if (err != nil) != tt.wantErr { + t.Errorf("listAttachedBindings() error = %v, wantErr %v", err, tt.wantErr) + } + if !reflect.DeepEqual(gotBindings, tt.wantBindings) { + t.Errorf("listAttachedBindings() = %v, want %v", gotBindings, tt.wantBindings) + } + }) + } +} + +func Test_removeScheduleResultFromAttachedBindings(t *testing.T) { + Scheme := runtime.NewScheme() + utilruntime.Must(scheme.AddToScheme(Scheme)) + utilruntime.Must(workv1alpha2.Install(Scheme)) + tests := []struct { + name string + bindingNamespace string + bindingName string + attachedBindings []*workv1alpha2.ResourceBinding + wantErr bool + wantBindings *workv1alpha2.ResourceBindingList + setupClient func() client.Client + }{ + { + name: "remove schedule result from attached bindings", + bindingNamespace: "test", + bindingName: "test-binding", + attachedBindings: []*workv1alpha2.ResourceBinding{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-binding", + Namespace: "test", + ResourceVersion: "1000", + Labels: map[string]string{ + "app": "nginx", + "resourcebinding.karmada.io/depended-by-5dbb6dc9c8": "93162d3c-ee8e-4995-9034-05f4d5d2c2b9", + }, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "fake-ns", + Name: "demo-app", + ResourceVersion: "22222", + }, + RequiredBy: []workv1alpha2.BindingSnapshot{ + { + Namespace: "test", + Name: "test-binding", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "foo", + Replicas: 1, + }, + }, + }, + { + Namespace: "default-1", + Name: "default-binding-1", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member1", + Replicas: 2, + }, + }, + }, + { + Namespace: "test", + Name: "test-binding", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "bar", + Replicas: 1, + }, + }, + }, + }, + }, + }, + }, + wantErr: false, + wantBindings: &workv1alpha2.ResourceBindingList{ + Items: []workv1alpha2.ResourceBinding{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-binding", + Namespace: "test", + ResourceVersion: "1001", + Labels: map[string]string{ + "app": "nginx", + }, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "fake-ns", + Name: "demo-app", + ResourceVersion: "22222", + }, + RequiredBy: []workv1alpha2.BindingSnapshot{ + { + Namespace: "default-1", + Name: "default-binding-1", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member1", + Replicas: 2, + }, + }, + }, + }, + }, + }, + }, + }, + setupClient: func() client.Client { + rb := &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-binding", + Namespace: "test", + ResourceVersion: "1000", + Labels: map[string]string{ + "app": "nginx", + "resourcebinding.karmada.io/depended-by-5dbb6dc9c8": "93162d3c-ee8e-4995-9034-05f4d5d2c2b9", + }, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "fake-ns", + Name: "demo-app", + ResourceVersion: "22222", + }, + RequiredBy: []workv1alpha2.BindingSnapshot{ + { + Namespace: "test", + Name: "test-binding", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "foo", + Replicas: 1, + }, + }, + }, + { + Namespace: "default-1", + Name: "default-binding-1", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member1", + Replicas: 2, + }, + }, + }, + { + Namespace: "test", + Name: "test-binding", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "bar", + Replicas: 1, + }, + }, + }, + }, + }, + } + return fake.NewClientBuilder().WithScheme(Scheme).WithObjects(rb).Build() + }, + }, + { + name: "empty attached bindings", + bindingNamespace: "test", + bindingName: "test-binding", + attachedBindings: []*workv1alpha2.ResourceBinding{}, + wantErr: false, + wantBindings: &workv1alpha2.ResourceBindingList{ + Items: []workv1alpha2.ResourceBinding{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-binding", + Namespace: "test", + ResourceVersion: "1000", + Labels: map[string]string{ + "app": "nginx", + "resourcebinding.karmada.io/depended-by-5dbb6dc9c8": "93162d3c-ee8e-4995-9034-05f4d5d2c2b9", + }, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "fake-ns", + Name: "demo-app", + ResourceVersion: "22222", + }, + RequiredBy: []workv1alpha2.BindingSnapshot{ + { + Namespace: "test", + Name: "test-binding", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "foo", + Replicas: 1, + }, + }, + }, + { + Namespace: "default-1", + Name: "default-binding-1", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member1", + Replicas: 2, + }, + }, + }, + { + Namespace: "test", + Name: "test-binding", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "bar", + Replicas: 1, + }, + }, + }, + }, + }, + }, + }, + }, + setupClient: func() client.Client { + rb := &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-binding", + Namespace: "test", + ResourceVersion: "1000", + Labels: map[string]string{ + "app": "nginx", + "resourcebinding.karmada.io/depended-by-5dbb6dc9c8": "93162d3c-ee8e-4995-9034-05f4d5d2c2b9", + }, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "fake-ns", + Name: "demo-app", + ResourceVersion: "22222", + }, + RequiredBy: []workv1alpha2.BindingSnapshot{ + { + Namespace: "test", + Name: "test-binding", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "foo", + Replicas: 1, + }, + }, + }, + { + Namespace: "default-1", + Name: "default-binding-1", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member1", + Replicas: 2, + }, + }, + }, + { + Namespace: "test", + Name: "test-binding", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "bar", + Replicas: 1, + }, + }, + }, + }, + }, + } + return fake.NewClientBuilder().WithScheme(Scheme).WithObjects(rb).Build() + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + d := &DependenciesDistributor{ + Client: tt.setupClient(), + } + err := d.removeScheduleResultFromAttachedBindings(tt.bindingNamespace, tt.bindingName, tt.attachedBindings) + if (err != nil) != tt.wantErr { + t.Errorf("removeScheduleResultFromAttachedBindings() error = %v, wantErr %v", err, tt.wantErr) + } + existBindings := &workv1alpha2.ResourceBindingList{} + err = d.Client.List(context.TODO(), existBindings) + if (err != nil) != tt.wantErr { + t.Errorf("removeScheduleResultFromAttachedBindings(), Client.List() error = %v, wantErr %v", err, tt.wantErr) + } + if !reflect.DeepEqual(existBindings, tt.wantBindings) { + t.Errorf("removeScheduleResultFromAttachedBindings(), Client.List() = %v, want %v", existBindings, tt.wantBindings) + } + }) + } +} + +func Test_createOrUpdateAttachedBinding(t *testing.T) { + Scheme := runtime.NewScheme() + utilruntime.Must(scheme.AddToScheme(Scheme)) + utilruntime.Must(workv1alpha2.Install(Scheme)) + tests := []struct { + name string + attachedBinding *workv1alpha2.ResourceBinding + wantErr bool + wantBinding *workv1alpha2.ResourceBinding + setupClient func() client.Client + }{ + { + name: "update attached binding", + attachedBinding: &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-binding", + Namespace: "test", + ResourceVersion: "1000", + Labels: map[string]string{"app": "nginx"}, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "fake-ns", + Name: "demo-app", + ResourceVersion: "22222", + }, + RequiredBy: []workv1alpha2.BindingSnapshot{ + { + Namespace: "test-1", + Name: "test-binding-1", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "foo", + Replicas: 1, + }, + }, + }, + { + Namespace: "default-2", + Name: "default-binding-2", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member2", + Replicas: 4, + }, + }, + }, + { + Namespace: "test-2", + Name: "test-binding-2", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "bar", + Replicas: 1, + }, + }, + }, + }, + }, + }, + wantErr: false, + wantBinding: &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-binding", + Namespace: "test", + ResourceVersion: "1001", + Labels: map[string]string{"app": "nginx", "foo": "bar"}, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "fake-ns", + Name: "demo-app", + ResourceVersion: "22222", + }, + RequiredBy: []workv1alpha2.BindingSnapshot{ + { + Namespace: "default-1", + Name: "default-binding-1", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member1", + Replicas: 2, + }, + }, + }, + { + Namespace: "default-2", + Name: "default-binding-2", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member2", + Replicas: 4, + }, + }, + }, + { + Namespace: "default-3", + Name: "default-binding-3", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member3", + Replicas: 4, + }, + }, + }, + { + Namespace: "test-1", + Name: "test-binding-1", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "foo", + Replicas: 1, + }, + }, + }, + { + Namespace: "test-2", + Name: "test-binding-2", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "bar", + Replicas: 1, + }, + }, + }, + }, + }, + }, + setupClient: func() client.Client { + rb := &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-binding", + Namespace: "test", + ResourceVersion: "1000", + Labels: map[string]string{"foo": "bar"}, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + RequiredBy: []workv1alpha2.BindingSnapshot{ + { + Namespace: "default-1", + Name: "default-binding-1", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member1", + Replicas: 2, + }, + }, + }, + { + Namespace: "default-2", + Name: "default-binding-2", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member2", + Replicas: 3, + }, + }, + }, + { + Namespace: "default-3", + Name: "default-binding-3", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member3", + Replicas: 4, + }, + }, + }, + }, + }, + } + return fake.NewClientBuilder().WithScheme(Scheme).WithObjects(rb).Build() + }, + }, + { + name: "create attached binding", + attachedBinding: &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-binding", + Namespace: "test", + Labels: map[string]string{"app": "nginx"}, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "fake-ns", + Name: "demo-app", + ResourceVersion: "22222", + }, + RequiredBy: []workv1alpha2.BindingSnapshot{ + { + Namespace: "test-1", + Name: "test-binding-1", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "foo", + Replicas: 1, + }, + }, + }, + { + Namespace: "default-2", + Name: "default-binding-2", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member2", + Replicas: 4, + }, + }, + }, + { + Namespace: "test-2", + Name: "test-binding-2", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "bar", + Replicas: 1, + }, + }, + }, + }, + }, + }, + wantErr: false, + wantBinding: &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-binding", + Namespace: "test", + ResourceVersion: "1", + Labels: map[string]string{"app": "nginx"}, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "fake-ns", + Name: "demo-app", + ResourceVersion: "22222", + }, + RequiredBy: []workv1alpha2.BindingSnapshot{ + { + Namespace: "test-1", + Name: "test-binding-1", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "foo", + Replicas: 1, + }, + }, + }, + { + Namespace: "default-2", + Name: "default-binding-2", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member2", + Replicas: 4, + }, + }, + }, + { + Namespace: "test-2", + Name: "test-binding-2", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "bar", + Replicas: 1, + }, + }, + }, + }, + }, + }, + setupClient: func() client.Client { + return fake.NewClientBuilder().WithScheme(Scheme).Build() + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + d := &DependenciesDistributor{ + Client: tt.setupClient(), + } + err := d.createOrUpdateAttachedBinding(tt.attachedBinding) + if (err != nil) != tt.wantErr { + t.Errorf("createOrUpdateAttachedBinding() error = %v, wantErr %v", err, tt.wantErr) + } + existBinding := &workv1alpha2.ResourceBinding{} + bindingKey := client.ObjectKeyFromObject(tt.attachedBinding) + err = d.Client.Get(context.TODO(), bindingKey, existBinding) + if (err != nil) != tt.wantErr { + t.Errorf("createOrUpdateAttachedBinding(), Client.Get() error = %v, wantErr %v", err, tt.wantErr) + } + if !reflect.DeepEqual(existBinding, tt.wantBinding) { + t.Errorf("createOrUpdateAttachedBinding(), Client.Get() = %v, want %v", existBinding, tt.wantBinding) + } + }) + } +} + +func Test_buildAttachedBinding(t *testing.T) { + blockOwnerDeletion := true + isController := true + tests := []struct { + name string + independentBinding *workv1alpha2.ResourceBinding + object *unstructured.Unstructured + wantAttachedBinding *workv1alpha2.ResourceBinding + }{ + { + name: "build attached binding", + independentBinding: &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-binding", + Namespace: "test", + Labels: map[string]string{workv1alpha2.ResourceBindingPermanentIDLabel: "93162d3c-ee8e-4995-9034-05f4d5d2c2b9"}, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member1", + Replicas: 2, + }, + }, + }, + }, + object: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "demo-app", + "namespace": "fake-ns", + "resourceVersion": "22222", + "uid": "db56a4a6-0dff-465a-b046-2c1dea42a42b", + }, + }, + }, + wantAttachedBinding: &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "demo-app-deployment", + Namespace: "test", + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Name: "demo-app", + UID: "db56a4a6-0dff-465a-b046-2c1dea42a42b", + BlockOwnerDeletion: &blockOwnerDeletion, + Controller: &isController, + }, + }, + Labels: map[string]string{"resourcebinding.karmada.io/depended-by-5dbb6dc9c8": "93162d3c-ee8e-4995-9034-05f4d5d2c2b9"}, + Finalizers: []string{util.BindingControllerFinalizer}, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "fake-ns", + Name: "demo-app", + ResourceVersion: "22222", + }, + RequiredBy: []workv1alpha2.BindingSnapshot{ + { + Namespace: "test", + Name: "test-binding", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member1", + Replicas: 2, + }, + }, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotAttachedBinding := buildAttachedBinding(tt.independentBinding, tt.object) + if !reflect.DeepEqual(gotAttachedBinding, tt.wantAttachedBinding) { + t.Errorf("buildAttachedBinding() = %v, want %v", gotAttachedBinding, tt.wantAttachedBinding) + } + }) + } +} + +func Test_mergeBindingSnapshot(t *testing.T) { + tests := []struct { + name string + existSnapshot []workv1alpha2.BindingSnapshot + newSnapshot []workv1alpha2.BindingSnapshot + expectExistSnapshot []workv1alpha2.BindingSnapshot + }{ + { + name: "merge binding snapshot", + existSnapshot: []workv1alpha2.BindingSnapshot{ + { + Namespace: "default-1", + Name: "default-binding-1", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member1", + Replicas: 2, + }, + }, + }, + { + Namespace: "default-2", + Name: "default-binding-2", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member2", + Replicas: 3, + }, + }, + }, + { + Namespace: "default-3", + Name: "default-binding-3", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member3", + Replicas: 4, + }, + }, + }, + }, + newSnapshot: []workv1alpha2.BindingSnapshot{ + { + Namespace: "test-1", + Name: "test-binding-1", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "foo", + Replicas: 1, + }, + }, + }, + { + Namespace: "default-2", + Name: "default-binding-2", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member2", + Replicas: 4, + }, + }, + }, + { + Namespace: "test-2", + Name: "test-binding-2", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "bar", + Replicas: 1, + }, + }, + }, + }, + expectExistSnapshot: []workv1alpha2.BindingSnapshot{ + { + Namespace: "default-1", + Name: "default-binding-1", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member1", + Replicas: 2, + }, + }, + }, + { + Namespace: "default-2", + Name: "default-binding-2", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member2", + Replicas: 4, + }, + }, + }, + { + Namespace: "default-3", + Name: "default-binding-3", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member3", + Replicas: 4, + }, + }, + }, + { + Namespace: "test-1", + Name: "test-binding-1", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "foo", + Replicas: 1, + }, + }, + }, + { + Namespace: "test-2", + Name: "test-binding-2", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "bar", + Replicas: 1, + }, + }, + }, + }, + }, + { + name: "no existing binding snapshot to merge", + existSnapshot: []workv1alpha2.BindingSnapshot{}, + newSnapshot: []workv1alpha2.BindingSnapshot{ + { + Namespace: "default-1", + Name: "default-binding-1", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member1", + Replicas: 2, + }, + }, + }, + { + Namespace: "default-2", + Name: "default-binding-2", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member2", + Replicas: 3, + }, + }, + }, + { + Namespace: "default-3", + Name: "default-binding-3", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member3", + Replicas: 4, + }, + }, + }, + }, + expectExistSnapshot: []workv1alpha2.BindingSnapshot{ + { + Namespace: "default-1", + Name: "default-binding-1", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member1", + Replicas: 2, + }, + }, + }, + { + Namespace: "default-2", + Name: "default-binding-2", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member2", + Replicas: 3, + }, + }, + }, + { + Namespace: "default-3", + Name: "default-binding-3", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member3", + Replicas: 4, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotExistSnapshot := mergeBindingSnapshot(tt.existSnapshot, tt.newSnapshot) + if !reflect.DeepEqual(gotExistSnapshot, tt.expectExistSnapshot) { + t.Errorf("mergeBindingSnapshot() = %v, want %v", gotExistSnapshot, tt.expectExistSnapshot) + } + }) + } +} + +func Test_deleteBindingFromSnapshot(t *testing.T) { + tests := []struct { + name string + bindingNamespace string + bindingName string + existSnapshot []workv1alpha2.BindingSnapshot + expectExistSnapshot []workv1alpha2.BindingSnapshot + }{ + { + name: "delete matching binding from snapshot", + bindingNamespace: "test", + bindingName: "test-binding", + existSnapshot: []workv1alpha2.BindingSnapshot{ + { + Namespace: "default-1", + Name: "default-binding-1", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member1", + Replicas: 2, + }, + }, + }, + { + Namespace: "test", + Name: "test-binding", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "foo", + Replicas: 1, + }, + }, + }, + { + Namespace: "default-2", + Name: "default-binding-2", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member2", + Replicas: 3, + }, + }, + }, + { + Namespace: "test", + Name: "test-binding", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "bar", + Replicas: 1, + }, + }, + }, + { + Namespace: "default-3", + Name: "default-binding-3", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member3", + Replicas: 4, + }, + }, + }, + }, + expectExistSnapshot: []workv1alpha2.BindingSnapshot{ + { + Namespace: "default-1", + Name: "default-binding-1", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member1", + Replicas: 2, + }, + }, + }, + { + Namespace: "default-2", + Name: "default-binding-2", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member2", + Replicas: 3, + }, + }, + }, + { + Namespace: "default-3", + Name: "default-binding-3", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member3", + Replicas: 4, + }, + }, + }, + }, + }, + { + name: "non-matching binding from snapshot", + bindingNamespace: "test", + bindingName: "test-binding", + existSnapshot: []workv1alpha2.BindingSnapshot{ + { + Namespace: "default-1", + Name: "default-binding-1", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member1", + Replicas: 2, + }, + }, + }, + { + Namespace: "default-2", + Name: "default-binding-2", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member2", + Replicas: 3, + }, + }, + }, + { + Namespace: "default-3", + Name: "default-binding-3", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member3", + Replicas: 4, + }, + }, + }, + }, + expectExistSnapshot: []workv1alpha2.BindingSnapshot{ + { + Namespace: "default-1", + Name: "default-binding-1", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member1", + Replicas: 2, + }, + }, + }, + { + Namespace: "default-2", + Name: "default-binding-2", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member2", + Replicas: 3, + }, + }, + }, + { + Namespace: "default-3", + Name: "default-binding-3", + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "member3", + Replicas: 4, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotExistSnapshot := deleteBindingFromSnapshot(tt.bindingNamespace, tt.bindingName, tt.existSnapshot) + if !reflect.DeepEqual(gotExistSnapshot, tt.expectExistSnapshot) { + t.Errorf("deleteBindingFromSnapshot() = %v, want %v", gotExistSnapshot, tt.expectExistSnapshot) + } + }) + } +} diff --git a/pkg/descheduler/core/filter_test.go b/pkg/descheduler/core/filter_test.go index 380f1b6b322d..4f9c592168e2 100644 --- a/pkg/descheduler/core/filter_test.go +++ b/pkg/descheduler/core/filter_test.go @@ -27,6 +27,49 @@ import ( "github.com/karmada-io/karmada/pkg/util" ) +func TestFilterBindings(t *testing.T) { + tests := []struct { + name string + bindings []*workv1alpha2.ResourceBinding + expected int + }{ + { + name: "No valid bindings", + bindings: []*workv1alpha2.ResourceBinding{ + createBinding("binding1", "v1", "Pod", nil), + createBinding("binding2", "v1", "Service", nil), + }, + expected: 0, + }, + { + name: "Mix of valid and invalid bindings", + bindings: []*workv1alpha2.ResourceBinding{ + createBinding("binding1", "apps/v1", "Deployment", createValidPlacement()), + createBinding("binding2", "v1", "Pod", createValidPlacement()), + createBinding("binding3", "apps/v1", "Deployment", createInvalidPlacement()), + }, + expected: 1, + }, + { + name: "All valid bindings", + bindings: []*workv1alpha2.ResourceBinding{ + createBinding("binding1", "apps/v1", "Deployment", createValidPlacement()), + createBinding("binding2", "apps/v1", "Deployment", createValidPlacement()), + }, + expected: 2, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + filtered := FilterBindings(tt.bindings) + if len(filtered) != tt.expected { + t.Errorf("FilterBindings() returned %d bindings, expected %d", len(filtered), tt.expected) + } + }) + } +} + func TestValidateGVK(t *testing.T) { tests := []struct { name string @@ -34,7 +77,7 @@ func TestValidateGVK(t *testing.T) { expected bool }{ { - name: "supportedGVKs", + name: "Supported GVK - Deployment", reference: &workv1alpha2.ObjectReference{ APIVersion: "apps/v1", Kind: "Deployment", @@ -42,13 +85,29 @@ func TestValidateGVK(t *testing.T) { expected: true, }, { - name: "unsupportedGVKs", + name: "Unsupported GVK - Pod", reference: &workv1alpha2.ObjectReference{ APIVersion: "v1", Kind: "Pod", }, expected: false, }, + { + name: "Unsupported GVK - Custom Resource", + reference: &workv1alpha2.ObjectReference{ + APIVersion: "custom.example.com/v1", + Kind: "MyCustomResource", + }, + expected: false, + }, + { + name: "Unsupported GVK - Different Version of Deployment", + reference: &workv1alpha2.ObjectReference{ + APIVersion: "apps/v2", + Kind: "Deployment", + }, + expected: false, + }, } for _, tt := range tests { @@ -62,95 +121,34 @@ func TestValidateGVK(t *testing.T) { } func TestValidatePlacement(t *testing.T) { - fakePlacement1 := policyv1alpha1.Placement{ - ReplicaScheduling: &policyv1alpha1.ReplicaSchedulingStrategy{ - ReplicaSchedulingType: policyv1alpha1.ReplicaSchedulingTypeDuplicated, - }, - } - marshaledBytes1, _ := json.Marshal(fakePlacement1) - fakePlacement2 := policyv1alpha1.Placement{ - ReplicaScheduling: &policyv1alpha1.ReplicaSchedulingStrategy{ - ReplicaSchedulingType: policyv1alpha1.ReplicaSchedulingTypeDivided, - ReplicaDivisionPreference: policyv1alpha1.ReplicaDivisionPreferenceAggregated, - }, - } - marshaledBytes2, _ := json.Marshal(fakePlacement2) - fakePlacement3 := policyv1alpha1.Placement{ - ReplicaScheduling: &policyv1alpha1.ReplicaSchedulingStrategy{ - ReplicaSchedulingType: policyv1alpha1.ReplicaSchedulingTypeDivided, - ReplicaDivisionPreference: policyv1alpha1.ReplicaDivisionPreferenceWeighted, - WeightPreference: &policyv1alpha1.ClusterPreferences{}, - }, - } - marshaledBytes3, _ := json.Marshal(fakePlacement3) - fakePlacement4 := policyv1alpha1.Placement{ - ReplicaScheduling: &policyv1alpha1.ReplicaSchedulingStrategy{ - ReplicaSchedulingType: policyv1alpha1.ReplicaSchedulingTypeDivided, - ReplicaDivisionPreference: policyv1alpha1.ReplicaDivisionPreferenceWeighted, - WeightPreference: &policyv1alpha1.ClusterPreferences{ - DynamicWeight: policyv1alpha1.DynamicWeightByAvailableReplicas, - }, - }, - } - marshaledBytes4, _ := json.Marshal(fakePlacement4) - tests := []struct { name string binding *workv1alpha2.ResourceBinding expected bool }{ { - name: "no policyPlacementAnnotation", - binding: &workv1alpha2.ResourceBinding{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: "bar", - }, - }, + name: "No policyPlacementAnnotation", + binding: createBinding("binding1", "apps/v1", "Deployment", nil), expected: false, }, { - name: "propagationPolicy schedules replicas as non-dynamic", - binding: &workv1alpha2.ResourceBinding{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: "bar", - Annotations: map[string]string{util.PolicyPlacementAnnotation: string(marshaledBytes1)}, - }, - }, + name: "ReplicaSchedulingType Duplicated", + binding: createBinding("binding2", "apps/v1", "Deployment", createPlacement(policyv1alpha1.ReplicaSchedulingTypeDuplicated, "", nil)), expected: false, }, { - name: "propagationPolicy schedules replicas as dynamic: ReplicaDivisionPreference is Aggregated", - binding: &workv1alpha2.ResourceBinding{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: "bar", - Annotations: map[string]string{util.PolicyPlacementAnnotation: string(marshaledBytes2)}, - }, - }, + name: "ReplicaSchedulingType Divided, Preference Aggregated", + binding: createBinding("binding3", "apps/v1", "Deployment", createPlacement(policyv1alpha1.ReplicaSchedulingTypeDivided, policyv1alpha1.ReplicaDivisionPreferenceAggregated, nil)), expected: true, }, { - name: "propagationPolicy schedules replicas as dynamic: DynamicWeight is null", - binding: &workv1alpha2.ResourceBinding{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: "bar", - Annotations: map[string]string{util.PolicyPlacementAnnotation: string(marshaledBytes3)}, - }, - }, + name: "ReplicaSchedulingType Divided, Preference Weighted, No DynamicWeight", + binding: createBinding("binding4", "apps/v1", "Deployment", createPlacement(policyv1alpha1.ReplicaSchedulingTypeDivided, policyv1alpha1.ReplicaDivisionPreferenceWeighted, &policyv1alpha1.ClusterPreferences{})), expected: false, }, { - name: "propagationPolicy schedules replicas as dynamic: DynamicWeight is not null", - binding: &workv1alpha2.ResourceBinding{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: "bar", - Annotations: map[string]string{util.PolicyPlacementAnnotation: string(marshaledBytes4)}, - }, - }, + name: "ReplicaSchedulingType Divided, Preference Weighted, With DynamicWeight", + binding: createBinding("binding5", "apps/v1", "Deployment", createPlacement(policyv1alpha1.ReplicaSchedulingTypeDivided, policyv1alpha1.ReplicaDivisionPreferenceWeighted, &policyv1alpha1.ClusterPreferences{DynamicWeight: policyv1alpha1.DynamicWeightByAvailableReplicas})), expected: true, }, } @@ -164,3 +162,43 @@ func TestValidatePlacement(t *testing.T) { }) } } + +func createBinding(name, apiVersion, kind string, placement *policyv1alpha1.Placement) *workv1alpha2.ResourceBinding { + binding := &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: "default", + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: apiVersion, + Kind: kind, + }, + }, + } + + if placement != nil { + marshaledBytes, _ := json.Marshal(placement) + binding.Annotations = map[string]string{util.PolicyPlacementAnnotation: string(marshaledBytes)} + } + + return binding +} + +func createPlacement(schedulingType policyv1alpha1.ReplicaSchedulingType, divisionPreference policyv1alpha1.ReplicaDivisionPreference, weightPreference *policyv1alpha1.ClusterPreferences) *policyv1alpha1.Placement { + return &policyv1alpha1.Placement{ + ReplicaScheduling: &policyv1alpha1.ReplicaSchedulingStrategy{ + ReplicaSchedulingType: schedulingType, + ReplicaDivisionPreference: divisionPreference, + WeightPreference: weightPreference, + }, + } +} + +func createValidPlacement() *policyv1alpha1.Placement { + return createPlacement(policyv1alpha1.ReplicaSchedulingTypeDivided, policyv1alpha1.ReplicaDivisionPreferenceAggregated, nil) +} + +func createInvalidPlacement() *policyv1alpha1.Placement { + return createPlacement(policyv1alpha1.ReplicaSchedulingTypeDuplicated, "", nil) +} diff --git a/pkg/descheduler/core/helper_test.go b/pkg/descheduler/core/helper_test.go new file mode 100644 index 000000000000..a0f7fda5ee1e --- /dev/null +++ b/pkg/descheduler/core/helper_test.go @@ -0,0 +1,172 @@ +/* +Copyright 2024 The Karmada 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 core + +import ( + "context" + "reflect" + "testing" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + + workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" + "github.com/karmada-io/karmada/pkg/estimator/client" +) + +func TestNewSchedulingResultHelper(t *testing.T) { + binding := &workv1alpha2.ResourceBinding{ + Spec: workv1alpha2.ResourceBindingSpec{ + Clusters: []workv1alpha2.TargetCluster{ + {Name: "cluster1", Replicas: 3}, + {Name: "cluster2", Replicas: 2}, + }, + }, + Status: workv1alpha2.ResourceBindingStatus{ + AggregatedStatus: []workv1alpha2.AggregatedStatusItem{ + { + ClusterName: "cluster1", + Status: &runtime.RawExtension{Raw: []byte(`{"readyReplicas": 2}`)}, + }, + { + ClusterName: "cluster2", + Status: &runtime.RawExtension{Raw: []byte(`{"readyReplicas": 1}`)}, + }, + }, + }, + } + + helper := NewSchedulingResultHelper(binding) + + expected := &SchedulingResultHelper{ + ResourceBinding: binding, + TargetClusters: []*TargetClusterWrapper{ + {ClusterName: "cluster1", Spec: 3, Ready: 2}, + {ClusterName: "cluster2", Spec: 2, Ready: 1}, + }, + } + + if !reflect.DeepEqual(helper, expected) { + t.Errorf("NewSchedulingResultHelper() = %v, want %v", helper, expected) + } +} + +func TestSchedulingResultHelper_GetUndesiredClusters(t *testing.T) { + helper := &SchedulingResultHelper{ + TargetClusters: []*TargetClusterWrapper{ + {ClusterName: "cluster1", Spec: 3, Ready: 2}, + {ClusterName: "cluster2", Spec: 2, Ready: 2}, + {ClusterName: "cluster3", Spec: 4, Ready: 1}, + }, + } + + clusters, names := helper.GetUndesiredClusters() + + expectedClusters := []*TargetClusterWrapper{ + {ClusterName: "cluster1", Spec: 3, Ready: 2}, + {ClusterName: "cluster3", Spec: 4, Ready: 1}, + } + expectedNames := []string{"cluster1", "cluster3"} + + if !reflect.DeepEqual(clusters, expectedClusters) { + t.Errorf("GetUndesiredClusters() clusters = %v, want %v", clusters, expectedClusters) + } + if !reflect.DeepEqual(names, expectedNames) { + t.Errorf("GetUndesiredClusters() names = %v, want %v", names, expectedNames) + } +} + +func TestSchedulingResultHelper_FillUnschedulableReplicas(t *testing.T) { + mockEstimator := &mockUnschedulableReplicaEstimator{} + client.GetUnschedulableReplicaEstimators()["mock"] = mockEstimator + defer delete(client.GetUnschedulableReplicaEstimators(), "mock") + + helper := &SchedulingResultHelper{ + ResourceBinding: &workv1alpha2.ResourceBinding{ + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Name: "test-deployment", + Namespace: "default", + }, + }, + }, + TargetClusters: []*TargetClusterWrapper{ + {ClusterName: "cluster1", Spec: 3, Ready: 2}, + {ClusterName: "cluster2", Spec: 2, Ready: 1}, + }, + } + + helper.FillUnschedulableReplicas(time.Minute) + + expected := []*TargetClusterWrapper{ + {ClusterName: "cluster1", Spec: 3, Ready: 2, Unschedulable: 1}, + {ClusterName: "cluster2", Spec: 2, Ready: 1, Unschedulable: 1}, + } + + if !reflect.DeepEqual(helper.TargetClusters, expected) { + t.Errorf("FillUnschedulableReplicas() = %v, want %v", helper.TargetClusters, expected) + } +} + +func TestGetReadyReplicas(t *testing.T) { + binding := &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-binding", + Namespace: "default", + }, + Status: workv1alpha2.ResourceBindingStatus{ + AggregatedStatus: []workv1alpha2.AggregatedStatusItem{ + { + ClusterName: "cluster1", + Status: &runtime.RawExtension{Raw: []byte(`{"readyReplicas": 2}`)}, + }, + { + ClusterName: "cluster2", + Status: &runtime.RawExtension{Raw: []byte(`{"readyReplicas": 3}`)}, + }, + { + ClusterName: "cluster3", + Status: &runtime.RawExtension{Raw: []byte(`{"someOtherField": 1}`)}, + }, + }, + }, + } + + result := getReadyReplicas(binding) + + expected := map[string]int32{ + "cluster1": 2, + "cluster2": 3, + } + + if !reflect.DeepEqual(result, expected) { + t.Errorf("getReadyReplicas() = %v, want %v", result, expected) + } +} + +// mockUnschedulableReplicaEstimator is a mock implementation of the UnschedulableReplicaEstimator interface +type mockUnschedulableReplicaEstimator struct{} + +func (m *mockUnschedulableReplicaEstimator) GetUnschedulableReplicas(_ context.Context, _ []string, _ *workv1alpha2.ObjectReference, _ time.Duration) ([]workv1alpha2.TargetCluster, error) { + return []workv1alpha2.TargetCluster{ + {Name: "cluster1", Replicas: 1}, + {Name: "cluster2", Replicas: 1}, + }, nil +} diff --git a/pkg/descheduler/descheduler.go b/pkg/descheduler/descheduler.go index f37d79db5758..8abde7c2bb18 100644 --- a/pkg/descheduler/descheduler.go +++ b/pkg/descheduler/descheduler.go @@ -186,6 +186,10 @@ func (d *Descheduler) worker(key util.QueueKey) error { } return fmt.Errorf("get ResourceBinding(%s) error: %v", namespacedName, err) } + if !binding.DeletionTimestamp.IsZero() { + klog.Infof("ResourceBinding(%s) in work queue is being deleted, ignore.", namespacedName) + return nil + } h := core.NewSchedulingResultHelper(binding) if _, undesiredClusters := h.GetUndesiredClusters(); len(undesiredClusters) == 0 { diff --git a/pkg/descheduler/descheduler_test.go b/pkg/descheduler/descheduler_test.go index 2b4e74822a05..9f77fda6279d 100644 --- a/pkg/descheduler/descheduler_test.go +++ b/pkg/descheduler/descheduler_test.go @@ -22,12 +22,17 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "google.golang.org/grpc" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/record" + "github.com/karmada-io/karmada/cmd/descheduler/app/options" + clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1" workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" estimatorclient "github.com/karmada-io/karmada/pkg/estimator/client" "github.com/karmada-io/karmada/pkg/estimator/pb" @@ -66,6 +71,97 @@ func buildBinding(name, ns string, target, status []workv1alpha2.TargetCluster) }, nil } +func TestNewDescheduler(t *testing.T) { + karmadaClient := fakekarmadaclient.NewSimpleClientset() + kubeClient := fake.NewSimpleClientset() + opts := &options.Options{ + UnschedulableThreshold: metav1.Duration{Duration: 5 * time.Minute}, + DeschedulingInterval: metav1.Duration{Duration: 1 * time.Minute}, + SchedulerEstimatorPort: 8080, + } + + descheduler := NewDescheduler(karmadaClient, kubeClient, opts) + + assert.NotNil(t, descheduler) + assert.Equal(t, karmadaClient, descheduler.KarmadaClient) + assert.Equal(t, kubeClient, descheduler.KubeClient) + assert.Equal(t, opts.UnschedulableThreshold.Duration, descheduler.unschedulableThreshold) + assert.Equal(t, opts.DeschedulingInterval.Duration, descheduler.deschedulingInterval) + assert.NotNil(t, descheduler.schedulerEstimatorCache) + assert.NotNil(t, descheduler.schedulerEstimatorWorker) + assert.NotNil(t, descheduler.deschedulerWorker) +} + +func TestRun(t *testing.T) { + karmadaClient := fakekarmadaclient.NewSimpleClientset() + kubeClient := fake.NewSimpleClientset() + opts := &options.Options{ + UnschedulableThreshold: metav1.Duration{Duration: 5 * time.Minute}, + DeschedulingInterval: metav1.Duration{Duration: 1 * time.Minute}, + SchedulerEstimatorPort: 8080, + } + + descheduler := NewDescheduler(karmadaClient, kubeClient, opts) + + testCluster := &clusterv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{Name: "test-cluster"}, + } + _, err := karmadaClient.ClusterV1alpha1().Clusters().Create(context.TODO(), testCluster, metav1.CreateOptions{}) + assert.NoError(t, err) + + stopCh := make(chan struct{}) + defer close(stopCh) + descheduler.informerFactory.Start(stopCh) + descheduler.informerFactory.WaitForCacheSync(stopCh) + + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + go descheduler.Run(ctx) + + time.Sleep(500 * time.Millisecond) + + cluster, err := descheduler.clusterLister.Get("test-cluster") + assert.NoError(t, err) + assert.NotNil(t, cluster) + assert.Equal(t, "test-cluster", cluster.Name) + + <-ctx.Done() +} + +func TestDescheduleOnce(t *testing.T) { + karmadaClient := fakekarmadaclient.NewSimpleClientset() + kubeClient := fake.NewSimpleClientset() + opts := &options.Options{ + UnschedulableThreshold: metav1.Duration{Duration: 5 * time.Minute}, + DeschedulingInterval: metav1.Duration{Duration: 1 * time.Second}, + SchedulerEstimatorPort: 8080, + } + + descheduler := NewDescheduler(karmadaClient, kubeClient, opts) + + binding1, err := buildBinding("binding1", "default", []workv1alpha2.TargetCluster{{Name: "cluster1", Replicas: 5}}, []workv1alpha2.TargetCluster{{Name: "cluster1", Replicas: 3}}) + assert.NoError(t, err) + binding2, err := buildBinding("binding2", "default", []workv1alpha2.TargetCluster{{Name: "cluster2", Replicas: 3}}, []workv1alpha2.TargetCluster{{Name: "cluster2", Replicas: 3}}) + assert.NoError(t, err) + + _, err = karmadaClient.WorkV1alpha2().ResourceBindings("default").Create(context.TODO(), binding1, metav1.CreateOptions{}) + assert.NoError(t, err) + _, err = karmadaClient.WorkV1alpha2().ResourceBindings("default").Create(context.TODO(), binding2, metav1.CreateOptions{}) + assert.NoError(t, err) + + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + go descheduler.Run(ctx) + + time.Sleep(1 * time.Second) + + descheduler.descheduleOnce() + + bindings, err := descheduler.bindingLister.List(labels.Everything()) + assert.NoError(t, err) + assert.Len(t, bindings, 2) +} + func TestDescheduler_worker(t *testing.T) { type args struct { target []workv1alpha2.TargetCluster diff --git a/pkg/detector/handler_test.go b/pkg/detector/handler_test.go new file mode 100644 index 000000000000..b0e97e59bb12 --- /dev/null +++ b/pkg/detector/handler_test.go @@ -0,0 +1,253 @@ +/* +Copyright 2024 The Karmada 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 detector + +import ( + "reflect" + "testing" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/karmada-io/karmada/pkg/util/fedinformer/keys" +) + +func TestClusterWideKeyFunc(t *testing.T) { + tests := []struct { + name string + object interface{} + expectKey keys.ClusterWideKey + expectErr bool + }{ + { + name: "cluster scoped resource in core group", + object: &corev1.Node{ + TypeMeta: metav1.TypeMeta{ + Kind: "Node", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "bar", + }, + }, + expectKey: keys.ClusterWideKey{ + Version: "v1", + Kind: "Node", + Name: "bar", + }, + expectErr: false, + }, + { + name: "cluster scoped resource not in core group", + object: &rbacv1.ClusterRole{ + TypeMeta: metav1.TypeMeta{ + Kind: "ClusterRole", + APIVersion: "rbac.authorization.k8s.io/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "bar", + }, + }, + expectKey: keys.ClusterWideKey{ + Group: "rbac.authorization.k8s.io", + Version: "v1", + Kind: "ClusterRole", + Name: "bar", + }, + expectErr: false, + }, + { + name: "namespace scoped resource not in core group", + object: &rbacv1.Role{ + TypeMeta: metav1.TypeMeta{ + Kind: "Role", + APIVersion: "rbac.authorization.k8s.io/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "foo", + Name: "bar", + }, + }, + expectKey: keys.ClusterWideKey{ + Group: "rbac.authorization.k8s.io", + Version: "v1", + Kind: "Role", + Name: "bar", + Namespace: "foo", + }, + expectErr: false, + }, + { + name: "nil object should be error", + object: nil, + expectKey: keys.ClusterWideKey{}, + expectErr: true, + }, + { + name: "non apiversion and kind runtime object should be error", + object: appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "foo", + Name: "bar", + }, + }, + expectKey: keys.ClusterWideKey{}, + expectErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + key, err := ClusterWideKeyFunc(tt.object) + if (err != nil) != tt.expectErr { + t.Errorf("ClusterWideKeyFunc() err = %v, wantErr %v", err, tt.expectErr) + } + if !reflect.DeepEqual(key, tt.expectKey) { + t.Errorf("ClusterWideKeyFunc() = '%v', want '%v'", key, tt.expectKey) + } + }) + } +} + +func TestResourceItemKeyFunc(t *testing.T) { + tests := []struct { + name string + object interface{} + expectKey keys.ClusterWideKeyWithConfig + expectErr bool + }{ + { + name: "cluster scoped resource in core group, resource changed by karmada", + object: ResourceItem{ + Obj: &corev1.Node{ + TypeMeta: metav1.TypeMeta{ + Kind: "Node", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "bar", + }, + }, + ResourceChangeByKarmada: true, + }, + expectKey: keys.ClusterWideKeyWithConfig{ + ClusterWideKey: keys.ClusterWideKey{ + Version: "v1", + Kind: "Node", + Name: "bar", + }, + ResourceChangeByKarmada: true, + }, + expectErr: false, + }, + { + name: "cluster scoped resource not in core group, resource not changed by karmada", + object: ResourceItem{ + Obj: &rbacv1.ClusterRole{ + TypeMeta: metav1.TypeMeta{ + Kind: "ClusterRole", + APIVersion: "rbac.authorization.k8s.io/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "bar", + }, + }, + ResourceChangeByKarmada: false, + }, + expectKey: keys.ClusterWideKeyWithConfig{ + ClusterWideKey: keys.ClusterWideKey{ + Group: "rbac.authorization.k8s.io", + Version: "v1", + Kind: "ClusterRole", + Name: "bar", + }, + ResourceChangeByKarmada: false, + }, + expectErr: false, + }, + { + name: "namespace scoped resource not in core group, resource changed by karmada", + object: ResourceItem{ + Obj: &rbacv1.Role{ + TypeMeta: metav1.TypeMeta{ + Kind: "Role", + APIVersion: "rbac.authorization.k8s.io/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "foo", + Name: "bar", + }, + }, + ResourceChangeByKarmada: true, + }, + expectKey: keys.ClusterWideKeyWithConfig{ + ClusterWideKey: keys.ClusterWideKey{ + Group: "rbac.authorization.k8s.io", + Version: "v1", + Kind: "Role", + Name: "bar", + Namespace: "foo", + }, + ResourceChangeByKarmada: true, + }, + expectErr: false, + }, + { + name: "non apiversion and kind runtime object should be error", + object: ResourceItem{ + Obj: &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "foo", + Name: "bar", + }, + }, + ResourceChangeByKarmada: true, + }, + expectKey: keys.ClusterWideKeyWithConfig{ResourceChangeByKarmada: true}, + expectErr: true, + }, + { + name: "not type of resourceitem should be error", + object: &rbacv1.Role{ + TypeMeta: metav1.TypeMeta{ + Kind: "Role", + APIVersion: "rbac.authorization.k8s.io/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "foo", + Name: "bar", + }, + }, + expectKey: keys.ClusterWideKeyWithConfig{}, + expectErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + key, err := ResourceItemKeyFunc(tt.object) + if (err != nil) != tt.expectErr { + t.Errorf("ResourceItemKeyFunc() err = %v, wantErr %v", err, tt.expectErr) + } + if !reflect.DeepEqual(key, tt.expectKey) { + t.Errorf("ResourceItemKeyFunc() = '%v', want '%v'", key, tt.expectKey) + } + }) + } +} diff --git a/pkg/detector/policy_test.go b/pkg/detector/policy_test.go new file mode 100644 index 000000000000..df5722cf48c8 --- /dev/null +++ b/pkg/detector/policy_test.go @@ -0,0 +1,1388 @@ +/* +Copyright 2024 The Karmada 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 detector + +import ( + "reflect" + "testing" + + "github.com/stretchr/testify/assert" + appsv1 "k8s.io/api/apps/v1" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + dynamicfake "k8s.io/client-go/dynamic/fake" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1" + workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" + "github.com/karmada-io/karmada/pkg/util/fedinformer/genericmanager" +) + +func Test_cleanPPUnmatchedRBs(t *testing.T) { + scheme := runtime.NewScheme() + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + utilruntime.Must(appsv1.AddToScheme(scheme)) + utilruntime.Must(workv1alpha2.Install(scheme)) + + restMapper := meta.NewDefaultRESTMapper([]schema.GroupVersion{{Group: "apps", Version: "v1"}}) + deploymentGVK := appsv1.SchemeGroupVersion.WithKind("Deployment") + restMapper.Add(deploymentGVK, meta.RESTScopeNamespace) + tests := []struct { + name string + policyID string + policyName string + policyNamespace string + selectors []policyv1alpha1.ResourceSelector + wantErr bool + setupClient func() *fake.ClientBuilder + existingObject *unstructured.Unstructured + expectedBindings *workv1alpha2.ResourceBindingList + }{ + { + name: "clean unmatched binding resource with policy and namespace", + policyID: "f2507cgb-f3f3-4a4b-b289-5691a4fef979", + policyName: "test-policy-1", + policyNamespace: "fake-namespace-1", + selectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Pod", + Namespace: "default", + }, + }, + wantErr: false, + setupClient: func() *fake.ClientBuilder { + obj := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deployment", + "namespace": "test", + }, + }, + } + rb := &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "binding-1", + ResourceVersion: "999", + Namespace: "fake-namespace-1", + Labels: map[string]string{ + policyv1alpha1.PropagationPolicyPermanentIDLabel: "f2507cgb-f3f3-4a4b-b289-5691a4fef979", + }, + Annotations: map[string]string{ + policyv1alpha1.PropagationPolicyNamespaceAnnotation: "deploy-match-namespace-1", + policyv1alpha1.PropagationPolicyNameAnnotation: "deploy-match-name-1", + }, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + Name: "deployment", + }, + }, + } + return fake.NewClientBuilder().WithScheme(scheme).WithObjects(obj, rb).WithRESTMapper(restMapper) + }, + existingObject: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deployment", + "namespace": "test", + }, + }, + }, + expectedBindings: &workv1alpha2.ResourceBindingList{Items: []workv1alpha2.ResourceBinding{}}, + }, + { + name: "cannot list unmatched binding resource with policy and namespace", + policyID: "f2507cgb-f3f3-4a4b-b289-5691a4fef979", + policyName: "test-policy-2", + policyNamespace: "fake-namespace-2", + selectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Pod", + Namespace: "default", + }, + }, + wantErr: true, + setupClient: func() *fake.ClientBuilder { + return fake.NewClientBuilder().WithRESTMapper(restMapper) + }, + existingObject: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deployment", + "namespace": "test", + }, + }, + }, + expectedBindings: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fakeClient := tt.setupClient().Build() + stopCh := make(chan struct{}) + defer close(stopCh) + fakeDynamicClient := dynamicfake.NewSimpleDynamicClient(scheme, tt.existingObject) + genMgr := genericmanager.NewSingleClusterInformerManager(fakeDynamicClient, 0, stopCh) + resourceDetector := &ResourceDetector{ + Client: fakeClient, + DynamicClient: fakeDynamicClient, + RESTMapper: fakeClient.RESTMapper(), + InformerManager: genMgr, + } + err := resourceDetector.cleanPPUnmatchedRBs(tt.policyID, tt.policyNamespace, tt.policyName, tt.selectors) + if (err != nil) != tt.wantErr { + t.Errorf("cleanPPUnmatchedRBs() error = %v, wantErr %v", err, tt.wantErr) + } + + bindings, err := resourceDetector.listPPDerivedRBs(tt.policyID, tt.policyNamespace, tt.policyName) + if (err != nil) != tt.wantErr { + t.Errorf("listPPDerivedRBs() error = %v, wantErr %v", err, tt.wantErr) + } + + if !reflect.DeepEqual(tt.expectedBindings, bindings) { + t.Errorf("listPPDerivedRBs() = %v, want %v", bindings, tt.expectedBindings) + } + }) + } +} + +func Test_cleanUnmatchedRBs(t *testing.T) { + scheme := runtime.NewScheme() + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + utilruntime.Must(appsv1.AddToScheme(scheme)) + utilruntime.Must(workv1alpha2.Install(scheme)) + + restMapper := meta.NewDefaultRESTMapper([]schema.GroupVersion{{Group: "apps", Version: "v1"}}) + deploymentGVK := appsv1.SchemeGroupVersion.WithKind("Deployment") + restMapper.Add(deploymentGVK, meta.RESTScopeNamespace) + tests := []struct { + name string + policyID string + policyName string + selectors []policyv1alpha1.ResourceSelector + wantErr bool + setupClient func() *fake.ClientBuilder + existingObject *unstructured.Unstructured + expectedBindings *workv1alpha2.ResourceBindingList + }{ + { + name: "clean unmatched binding resource", + policyID: "f2507cgb-f3f3-4a4b-b289-5691a4fef979", + policyName: "test-policy-1", + selectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Pod", + Namespace: "default", + }, + }, + wantErr: false, + setupClient: func() *fake.ClientBuilder { + obj := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deployment", + "namespace": "test", + }, + }, + } + rb := &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "binding-1", + ResourceVersion: "999", + Labels: map[string]string{ + policyv1alpha1.ClusterPropagationPolicyPermanentIDLabel: "f2507cgb-f3f3-4a4b-b289-5691a4fef979", + }, + Annotations: map[string]string{ + policyv1alpha1.ClusterPropagationPolicyAnnotation: "deploy-match-name-1", + }, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + Name: "deployment", + }, + }, + } + return fake.NewClientBuilder().WithScheme(scheme).WithObjects(obj, rb).WithRESTMapper(restMapper) + }, + existingObject: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deployment", + "namespace": "test", + }, + }, + }, + expectedBindings: &workv1alpha2.ResourceBindingList{Items: []workv1alpha2.ResourceBinding{}}, + }, + { + name: "cannot list unmatched binding resource", + policyID: "f2507cgb-f3f3-4a4b-b289-5691a4fef979", + policyName: "test-policy-1", + selectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Pod", + Namespace: "default", + }, + }, + wantErr: true, + setupClient: func() *fake.ClientBuilder { + return fake.NewClientBuilder().WithRESTMapper(restMapper) + }, + existingObject: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deployment", + "namespace": "test", + }, + }, + }, + expectedBindings: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fakeClient := tt.setupClient().Build() + stopCh := make(chan struct{}) + defer close(stopCh) + fakeDynamicClient := dynamicfake.NewSimpleDynamicClient(scheme, tt.existingObject) + genMgr := genericmanager.NewSingleClusterInformerManager(fakeDynamicClient, 0, stopCh) + resourceDetector := &ResourceDetector{ + Client: fakeClient, + DynamicClient: fakeDynamicClient, + RESTMapper: fakeClient.RESTMapper(), + InformerManager: genMgr, + } + err := resourceDetector.cleanCPPUnmatchedRBs(tt.policyID, tt.policyName, tt.selectors) + if (err != nil) != tt.wantErr { + t.Errorf("cleanCPPUnmatchedRBs() error = %v, wantErr %v", err, tt.wantErr) + } + + bindings, err := resourceDetector.listCPPDerivedRBs(tt.policyID, tt.policyName) + if (err != nil) != tt.wantErr { + t.Errorf("listCPPDerivedRBs() error = %v, wantErr %v", err, tt.wantErr) + } + + if !reflect.DeepEqual(tt.expectedBindings, bindings) { + t.Errorf("listCPPDerivedRBs() = %v, want %v", bindings, tt.expectedBindings) + } + }) + } +} + +func Test_cleanUnmatchedCRBs(t *testing.T) { + scheme := runtime.NewScheme() + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + utilruntime.Must(appsv1.AddToScheme(scheme)) + utilruntime.Must(workv1alpha2.Install(scheme)) + + restMapper := meta.NewDefaultRESTMapper([]schema.GroupVersion{{Group: "apps", Version: "v1"}}) + deploymentGVK := appsv1.SchemeGroupVersion.WithKind("Deployment") + restMapper.Add(deploymentGVK, meta.RESTScopeNamespace) + tests := []struct { + name string + policyID string + policyName string + selectors []policyv1alpha1.ResourceSelector + wantErr bool + setupClient func() *fake.ClientBuilder + existingObject *unstructured.Unstructured + expectedBindings *workv1alpha2.ClusterResourceBindingList + }{ + { + name: "clean unmatched cluster binding resource", + policyID: "f2507cgb-f3f3-4a4b-b289-5691a4fef979", + policyName: "test-policy-1", + selectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Pod", + Namespace: "default", + }, + }, + wantErr: false, + setupClient: func() *fake.ClientBuilder { + obj := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deployment", + "namespace": "test", + }, + }, + } + rb := &workv1alpha2.ClusterResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "binding-1", + ResourceVersion: "999", + Labels: map[string]string{ + policyv1alpha1.ClusterPropagationPolicyPermanentIDLabel: "f2507cgb-f3f3-4a4b-b289-5691a4fef979", + }, + Annotations: map[string]string{ + policyv1alpha1.ClusterPropagationPolicyAnnotation: "deploy-match-name-1", + }, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + Name: "deployment", + }, + }, + } + return fake.NewClientBuilder().WithScheme(scheme).WithObjects(obj, rb).WithRESTMapper(restMapper) + }, + existingObject: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deployment", + "namespace": "test", + }, + }, + }, + expectedBindings: &workv1alpha2.ClusterResourceBindingList{Items: []workv1alpha2.ClusterResourceBinding{}}, + }, + { + name: "cannot list unmatched cluster binding resource", + policyID: "f2507cgb-f3f3-4a4b-b289-5691a4fef979", + policyName: "test-policy-1", + selectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Pod", + Namespace: "default", + }, + }, + wantErr: true, + setupClient: func() *fake.ClientBuilder { + return fake.NewClientBuilder().WithRESTMapper(restMapper) + }, + existingObject: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deployment", + "namespace": "test", + }, + }, + }, + expectedBindings: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fakeClient := tt.setupClient().Build() + stopCh := make(chan struct{}) + defer close(stopCh) + fakeDynamicClient := dynamicfake.NewSimpleDynamicClient(scheme, tt.existingObject) + genMgr := genericmanager.NewSingleClusterInformerManager(fakeDynamicClient, 0, stopCh) + resourceDetector := &ResourceDetector{ + Client: fakeClient, + DynamicClient: fakeDynamicClient, + RESTMapper: fakeClient.RESTMapper(), + InformerManager: genMgr, + } + err := resourceDetector.cleanUnmatchedCRBs(tt.policyID, tt.policyName, tt.selectors) + if (err != nil) != tt.wantErr { + t.Errorf("cleanUnmatchedCRBs() error = %v, wantErr %v", err, tt.wantErr) + } + + bindings, err := resourceDetector.listCPPDerivedCRBs(tt.policyID, tt.policyName) + if (err != nil) != tt.wantErr { + t.Errorf("listCPPDerivedCRBs() error = %v, wantErr %v", err, tt.wantErr) + } + + if !reflect.DeepEqual(tt.expectedBindings, bindings) { + t.Errorf("listCPPDerivedCRBs() = %v, want %v", bindings, tt.expectedBindings) + } + }) + } +} + +func Test_removeRBsMarks(t *testing.T) { + scheme := runtime.NewScheme() + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + utilruntime.Must(appsv1.AddToScheme(scheme)) + utilruntime.Must(workv1alpha2.Install(scheme)) + + restMapper := meta.NewDefaultRESTMapper([]schema.GroupVersion{{Group: "apps", Version: "v1"}}) + deploymentGVK := appsv1.SchemeGroupVersion.WithKind("Deployment") + restMapper.Add(deploymentGVK, meta.RESTScopeNamespace) + tests := []struct { + name string + bindings *workv1alpha2.ResourceBindingList + selectors []policyv1alpha1.ResourceSelector + existingObject *unstructured.Unstructured + removeLabels []string + removeAnnotations []string + wantErr bool + setupClient func() *fake.ClientBuilder + }{ + { + name: "cannot remove resource binding with matching selectors", + bindings: &workv1alpha2.ResourceBindingList{ + Items: []workv1alpha2.ResourceBinding{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "binding-1", + Namespace: "fake-namespace-1", + ResourceVersion: "999", + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + Name: "deployment", + }, + }, + }, + }, + }, + selectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + }, + }, + removeLabels: []string{"app"}, + removeAnnotations: []string{"foo"}, + existingObject: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deployment", + "namespace": "test", + "labels": map[string]interface{}{"app": "nginx"}, + "annotations": map[string]interface{}{"foo": "bar"}, + }, + }, + }, + wantErr: false, + setupClient: func() *fake.ClientBuilder { + obj := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deployment", + "namespace": "test", + "labels": map[string]interface{}{"app": "nginx"}, + "annotations": map[string]interface{}{"foo": "bar"}, + }, + }, + } + return fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(obj).WithRESTMapper(restMapper) + }, + }, + { + name: "remove resource binding with non-matching selectors", + bindings: &workv1alpha2.ResourceBindingList{ + Items: []workv1alpha2.ResourceBinding{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "binding-1", + Namespace: "fake-namespace-1", + ResourceVersion: "999", + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + Name: "deployment", + }, + }, + }, + }, + }, + selectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Pod", + Namespace: "default", + }, + }, + removeLabels: []string{"app"}, + removeAnnotations: []string{"foo"}, + existingObject: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deployment", + "namespace": "test", + "labels": map[string]interface{}{"app": "nginx"}, + "annotations": map[string]interface{}{"foo": "bar"}, + }, + }, + }, + wantErr: false, + setupClient: func() *fake.ClientBuilder { + obj := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deployment", + "namespace": "test", + "labels": map[string]interface{}{"app": "nginx"}, + "annotations": map[string]interface{}{"foo": "bar"}, + }, + }, + } + rb := &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "binding-1", + Namespace: "fake-namespace-1", + ResourceVersion: "999", + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + Name: "deployment", + }, + }, + } + return fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(obj, rb).WithRESTMapper(restMapper) + }, + }, + { + name: "failed to remove resource binding with non-matching selectors", + bindings: &workv1alpha2.ResourceBindingList{ + Items: []workv1alpha2.ResourceBinding{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "binding-1", + Namespace: "fake-namespace-1", + ResourceVersion: "999", + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + Name: "deployment", + }, + }, + }, + }, + }, + selectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Pod", + Namespace: "default", + }, + }, + removeLabels: []string{"app"}, + removeAnnotations: []string{"foo"}, + existingObject: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deployment", + "namespace": "test", + "labels": map[string]interface{}{"app": "nginx"}, + "annotations": map[string]interface{}{"foo": "bar"}, + }, + }, + }, + wantErr: true, + setupClient: func() *fake.ClientBuilder { + return fake.NewClientBuilder().WithRESTMapper(restMapper) + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fakeClient := tt.setupClient().Build() + stopCh := make(chan struct{}) + defer close(stopCh) + fakeDynamicClient := dynamicfake.NewSimpleDynamicClient(scheme, tt.existingObject) + genMgr := genericmanager.NewSingleClusterInformerManager(fakeDynamicClient, 0, stopCh) + resourceDetector := &ResourceDetector{ + Client: fakeClient, + DynamicClient: fakeDynamicClient, + RESTMapper: fakeClient.RESTMapper(), + InformerManager: genMgr, + } + err := resourceDetector.removeRBsMarks(tt.bindings, tt.selectors, tt.removeLabels, tt.removeAnnotations) + if (err != nil) != tt.wantErr { + t.Errorf("removeRBsMarks() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func Test_removeCRBsMarks(t *testing.T) { + scheme := runtime.NewScheme() + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + utilruntime.Must(appsv1.AddToScheme(scheme)) + utilruntime.Must(workv1alpha2.Install(scheme)) + + restMapper := meta.NewDefaultRESTMapper([]schema.GroupVersion{{Group: "apps", Version: "v1"}}) + deploymentGVK := appsv1.SchemeGroupVersion.WithKind("Deployment") + restMapper.Add(deploymentGVK, meta.RESTScopeNamespace) + tests := []struct { + name string + bindings *workv1alpha2.ClusterResourceBindingList + selectors []policyv1alpha1.ResourceSelector + existingObject *unstructured.Unstructured + removeLabels []string + removeAnnotations []string + wantErr bool + setupClient func() *fake.ClientBuilder + }{ + { + name: "cannot remove cluster resource binding with matching selectors", + bindings: &workv1alpha2.ClusterResourceBindingList{ + Items: []workv1alpha2.ClusterResourceBinding{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "binding-1", + Namespace: "fake-namespace-1", + ResourceVersion: "999", + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + Name: "deployment", + }, + }, + }, + }, + }, + selectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + }, + }, + removeLabels: []string{"app"}, + removeAnnotations: []string{"foo"}, + existingObject: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deployment", + "namespace": "test", + "labels": map[string]interface{}{"app": "nginx"}, + "annotations": map[string]interface{}{"foo": "bar"}, + }, + }, + }, + wantErr: false, + setupClient: func() *fake.ClientBuilder { + obj := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deployment", + "namespace": "test", + "labels": map[string]interface{}{"app": "nginx"}, + "annotations": map[string]interface{}{"foo": "bar"}, + }, + }, + } + return fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(obj).WithRESTMapper(restMapper) + }, + }, + { + name: "remove cluster resource binding with non-matching selectors", + bindings: &workv1alpha2.ClusterResourceBindingList{ + Items: []workv1alpha2.ClusterResourceBinding{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "binding-1", + Namespace: "fake-namespace-1", + ResourceVersion: "999", + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + Name: "deployment", + }, + }, + }, + }, + }, + selectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Pod", + Namespace: "default", + }, + }, + removeLabels: []string{"app"}, + removeAnnotations: []string{"foo"}, + existingObject: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deployment", + "namespace": "test", + "labels": map[string]interface{}{"app": "nginx"}, + "annotations": map[string]interface{}{"foo": "bar"}, + }, + }, + }, + wantErr: false, + setupClient: func() *fake.ClientBuilder { + obj := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deployment", + "namespace": "test", + "labels": map[string]interface{}{"app": "nginx"}, + "annotations": map[string]interface{}{"foo": "bar"}, + }, + }, + } + crb := &workv1alpha2.ClusterResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "binding-1", + Namespace: "fake-namespace-1", + ResourceVersion: "999", + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + Name: "deployment", + }, + }, + } + return fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(obj, crb).WithRESTMapper(restMapper) + }, + }, + { + name: "failed to remove cluster resource binding with non-matching selectors", + bindings: &workv1alpha2.ClusterResourceBindingList{ + Items: []workv1alpha2.ClusterResourceBinding{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "binding-1", + Namespace: "fake-namespace-1", + ResourceVersion: "999", + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + Name: "deployment", + }, + }, + }, + }, + }, + selectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Pod", + Namespace: "default", + }, + }, + removeLabels: []string{"app"}, + removeAnnotations: []string{"foo"}, + existingObject: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deployment", + "namespace": "test", + "labels": map[string]interface{}{"app": "nginx"}, + "annotations": map[string]interface{}{"foo": "bar"}, + }, + }, + }, + wantErr: true, + setupClient: func() *fake.ClientBuilder { + return fake.NewClientBuilder().WithRESTMapper(restMapper) + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fakeClient := tt.setupClient().Build() + stopCh := make(chan struct{}) + defer close(stopCh) + fakeDynamicClient := dynamicfake.NewSimpleDynamicClient(scheme, tt.existingObject) + genMgr := genericmanager.NewSingleClusterInformerManager(fakeDynamicClient, 0, stopCh) + resourceDetector := &ResourceDetector{ + Client: fakeClient, + DynamicClient: fakeDynamicClient, + RESTMapper: fakeClient.RESTMapper(), + InformerManager: genMgr, + } + err := resourceDetector.removeCRBsMarks(tt.bindings, tt.selectors, tt.removeLabels, tt.removeAnnotations) + if (err != nil) != tt.wantErr { + t.Errorf("removeCRBsMarks() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func Test_removeResourceMarksIfNotMatched(t *testing.T) { + scheme := runtime.NewScheme() + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + utilruntime.Must(appsv1.AddToScheme(scheme)) + + restMapper := meta.NewDefaultRESTMapper([]schema.GroupVersion{{Group: "apps", Version: "v1"}}) + deploymentGVK := appsv1.SchemeGroupVersion.WithKind("Deployment") + restMapper.Add(deploymentGVK, meta.RESTScopeNamespace) + + tests := []struct { + name string + objectReference workv1alpha2.ObjectReference + selectors []policyv1alpha1.ResourceSelector + labels []string + annotations []string + existingObject *unstructured.Unstructured + wantUpdated bool + wantErr bool + setupClient func() *fake.ClientBuilder + }{ + { + name: "update with non matching selectors", + objectReference: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + Name: "deployment", + }, + selectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Pod", + Namespace: "default", + }, + }, + labels: []string{"app"}, + annotations: []string{"foo"}, + existingObject: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deployment", + "namespace": "test", + "labels": map[string]interface{}{"app": "nginx"}, + "annotations": map[string]interface{}{"foo": "bar"}, + }, + }, + }, + wantUpdated: true, + wantErr: false, + setupClient: func() *fake.ClientBuilder { + obj := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deployment", + "namespace": "test", + "labels": map[string]interface{}{"app": "nginx"}, + "annotations": map[string]interface{}{"foo": "bar"}, + }, + }, + } + return fake.NewClientBuilder().WithScheme(scheme).WithObjects(obj).WithRESTMapper(restMapper) + }, + }, + { + name: "cannot update with matching selectors", + objectReference: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + Name: "deployment", + }, + selectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + }, + }, + labels: []string{"app"}, + annotations: []string{"foo"}, + existingObject: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deployment", + "namespace": "test", + "labels": map[string]interface{}{"app": "nginx"}, + "annotations": map[string]interface{}{"foo": "bar"}, + }, + }, + }, + wantUpdated: false, + wantErr: false, + setupClient: func() *fake.ClientBuilder { + obj := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deployment", + "namespace": "test", + "labels": map[string]interface{}{"app": "nginx"}, + "annotations": map[string]interface{}{"foo": "bar"}, + }, + }, + } + return fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(obj).WithRESTMapper(restMapper) + }, + }, + { + name: "failed to update with non matching selectors", + objectReference: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + Name: "deployment", + }, + selectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Pod", + Namespace: "default", + }, + }, + labels: []string{"app"}, + annotations: []string{"foo"}, + existingObject: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deployment", + "namespace": "test", + "labels": map[string]interface{}{"app": "nginx"}, + "annotations": map[string]interface{}{"foo": "bar"}, + }, + }, + }, + wantUpdated: false, + wantErr: true, + setupClient: func() *fake.ClientBuilder { + return fake.NewClientBuilder().WithRESTMapper(restMapper) + }, + }, + { + name: "restmapper does not contain required scheme", + objectReference: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + Name: "deployment", + }, + selectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + }, + }, + labels: []string{"app"}, + annotations: []string{"foo"}, + existingObject: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Pod", + "metadata": map[string]interface{}{ + "name": "pod", + "namespace": "test", + "labels": map[string]interface{}{"app": "nginx"}, + "annotations": map[string]interface{}{"foo": "bar"}, + }, + }, + }, + wantUpdated: false, + wantErr: false, + setupClient: func() *fake.ClientBuilder { + obj := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Pod", + "metadata": map[string]interface{}{ + "name": "pod", + "namespace": "test", + "labels": map[string]interface{}{"app": "nginx"}, + "annotations": map[string]interface{}{"foo": "bar"}, + }, + }, + } + return fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(obj).WithRESTMapper(restMapper) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fakeClient := tt.setupClient().Build() + stopCh := make(chan struct{}) + defer close(stopCh) + fakeDynamicClient := dynamicfake.NewSimpleDynamicClient(scheme, tt.existingObject) + genMgr := genericmanager.NewSingleClusterInformerManager(fakeDynamicClient, 0, stopCh) + resourceDetector := &ResourceDetector{ + Client: fakeClient, + DynamicClient: fakeDynamicClient, + RESTMapper: fakeClient.RESTMapper(), + InformerManager: genMgr, + } + + updated, err := resourceDetector.removeResourceMarksIfNotMatched(tt.objectReference, tt.selectors, tt.labels, tt.annotations) + + if (err != nil) != tt.wantErr { + t.Errorf("removeResourceMarksIfNotMatched() error = %v, wantErr %v", err, tt.wantErr) + } + if updated != tt.wantUpdated { + t.Errorf("removeResourceMarksIfNotMatched() = %v, want %v", updated, tt.wantUpdated) + } + }) + } +} + +func Test_listPPDerivedRBs(t *testing.T) { + scheme := runtime.NewScheme() + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + utilruntime.Must(workv1alpha2.Install(scheme)) + + tests := []struct { + name string + policyID string + policyName string + policyNamespace string + wantErr bool + setupClient func() *fake.ClientBuilder + expectedBindings *workv1alpha2.ResourceBindingList + }{ + { + name: "list resource binding with policy and namespace", + policyID: "f2507cgb-f3f3-4a4b-b289-5691a4fef979", + policyName: "test-policy-1", + policyNamespace: "fake-namespace-1", + wantErr: false, + setupClient: func() *fake.ClientBuilder { + rb := &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "binding-1", + Namespace: "fake-namespace-1", + ResourceVersion: "999", + Labels: map[string]string{ + policyv1alpha1.PropagationPolicyPermanentIDLabel: "f2507cgb-f3f3-4a4b-b289-5691a4fef979", + }, + }, + } + return fake.NewClientBuilder().WithScheme(scheme).WithObjects(rb) + }, + expectedBindings: &workv1alpha2.ResourceBindingList{ + Items: []workv1alpha2.ResourceBinding{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "binding-1", + Namespace: "fake-namespace-1", + ResourceVersion: "999", + Labels: map[string]string{ + policyv1alpha1.PropagationPolicyPermanentIDLabel: "f2507cgb-f3f3-4a4b-b289-5691a4fef979", + }, + }, + }, + }, + }, + }, + { + name: "cannot list resource binding with policy and namespace", + policyID: "g5609cgb-f3f3-4a4b-b289-4512a4fef979", + policyName: "test-policy-2", + policyNamespace: "fake-namespace-2", + wantErr: true, + setupClient: func() *fake.ClientBuilder { + return fake.NewClientBuilder() + }, + expectedBindings: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fakeClient := tt.setupClient().Build() + + resourceDetector := &ResourceDetector{ + Client: fakeClient, + } + + bindings, err := resourceDetector.listPPDerivedRBs(tt.policyID, tt.policyNamespace, tt.policyName) + + if (err != nil) != tt.wantErr { + t.Errorf("listPPDerivedRBs() error = %v, wantErr %v", err, tt.wantErr) + } + + if !reflect.DeepEqual(tt.expectedBindings, bindings) { + t.Errorf("listPPDerivedRBs() = %v, want %v", bindings, tt.expectedBindings) + } + }) + } +} + +func Test_listCPPDerivedRBs(t *testing.T) { + scheme := runtime.NewScheme() + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + utilruntime.Must(workv1alpha2.Install(scheme)) + + tests := []struct { + name string + policyID string + policyName string + wantErr bool + setupClient func() *fake.ClientBuilder + expectedBindings *workv1alpha2.ResourceBindingList + }{ + { + name: "list resource binding with policy", + policyID: "f2507cgb-f3f3-4a4b-b289-5691a4fef979", + policyName: "test-policy-1", + wantErr: false, + setupClient: func() *fake.ClientBuilder { + rb := &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "binding-1", + ResourceVersion: "999", + Labels: map[string]string{ + policyv1alpha1.ClusterPropagationPolicyPermanentIDLabel: "f2507cgb-f3f3-4a4b-b289-5691a4fef979", + }, + }, + } + return fake.NewClientBuilder().WithScheme(scheme).WithObjects(rb) + }, + expectedBindings: &workv1alpha2.ResourceBindingList{ + Items: []workv1alpha2.ResourceBinding{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "binding-1", + ResourceVersion: "999", + Labels: map[string]string{ + policyv1alpha1.ClusterPropagationPolicyPermanentIDLabel: "f2507cgb-f3f3-4a4b-b289-5691a4fef979", + }, + }, + }, + }, + }, + }, + { + name: "cannot list resource binding with policy", + policyID: "g5609cgb-f3f3-4a4b-b289-4512a4fef979", + policyName: "test-policy-2", + wantErr: true, + setupClient: func() *fake.ClientBuilder { + return fake.NewClientBuilder() + }, + expectedBindings: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fakeClient := tt.setupClient().Build() + + resourceDetector := &ResourceDetector{ + Client: fakeClient, + } + + bindings, err := resourceDetector.listCPPDerivedRBs(tt.policyID, tt.policyName) + + if (err != nil) != tt.wantErr { + t.Errorf("listCPPDerivedRBs() error = %v, wantErr %v", err, tt.wantErr) + } + + if !reflect.DeepEqual(tt.expectedBindings, bindings) { + t.Errorf("listCPPDerivedRBs() = %v, want %v", bindings, tt.expectedBindings) + } + }) + } +} + +func Test_listCPPDerivedCRBs(t *testing.T) { + scheme := runtime.NewScheme() + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + utilruntime.Must(workv1alpha2.Install(scheme)) + + tests := []struct { + name string + policyID string + policyName string + wantErr bool + setupClient func() *fake.ClientBuilder + expectedBindings *workv1alpha2.ClusterResourceBindingList + }{ + { + name: "list cluster binding with policy", + policyID: "f2507cgb-f3f3-4a4b-b289-5691a4fef979", + policyName: "test-policy-1", + wantErr: false, + setupClient: func() *fake.ClientBuilder { + rb := &workv1alpha2.ClusterResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "binding-1", + ResourceVersion: "999", + Labels: map[string]string{ + policyv1alpha1.ClusterPropagationPolicyPermanentIDLabel: "f2507cgb-f3f3-4a4b-b289-5691a4fef979", + }, + }, + } + return fake.NewClientBuilder().WithScheme(scheme).WithObjects(rb) + }, + expectedBindings: &workv1alpha2.ClusterResourceBindingList{ + Items: []workv1alpha2.ClusterResourceBinding{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "binding-1", + ResourceVersion: "999", + Labels: map[string]string{ + policyv1alpha1.ClusterPropagationPolicyPermanentIDLabel: "f2507cgb-f3f3-4a4b-b289-5691a4fef979", + }, + }, + }, + }, + }, + }, + { + name: "cannot list cluster binding with policy", + policyID: "g5609cgb-f3f3-4a4b-b289-4512a4fef979", + policyName: "test-policy-2", + wantErr: true, + setupClient: func() *fake.ClientBuilder { + return fake.NewClientBuilder() + }, + expectedBindings: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fakeClient := tt.setupClient().Build() + + resourceDetector := &ResourceDetector{ + Client: fakeClient, + } + + bindings, err := resourceDetector.listCPPDerivedCRBs(tt.policyID, tt.policyName) + + if (err != nil) != tt.wantErr { + t.Errorf("listCPPDerivedCRBs() error = %v, wantErr %v", err, tt.wantErr) + } + + if !reflect.DeepEqual(tt.expectedBindings, bindings) { + t.Errorf("listCPPDerivedCRBs() = %v, want %v", bindings, tt.expectedBindings) + } + }) + } +} + +func Test_excludeClusterPolicy(t *testing.T) { + tests := []struct { + name string + objLabels map[string]string + want bool + }{ + { + name: "propagation policy was claimed", + objLabels: map[string]string{}, + want: false, + }, { + name: "propagation policy was not claimed", + objLabels: map[string]string{ + policyv1alpha1.ClusterPropagationPolicyPermanentIDLabel: "f2507cgb-f3f3-4a4b-b289-5691a4fef979", + }, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := excludeClusterPolicy(tt.objLabels) + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/pkg/detector/preemption.go b/pkg/detector/preemption.go index bbbf14ecb1bf..3b71818a3ed7 100755 --- a/pkg/detector/preemption.go +++ b/pkg/detector/preemption.go @@ -17,6 +17,8 @@ limitations under the License. package detector import ( + "context" + pq "github.com/emirpasic/gods/queues/priorityqueue" godsutils "github.com/emirpasic/gods/utils" corev1 "k8s.io/api/core/v1" @@ -234,7 +236,7 @@ func (d *ResourceDetector) preemptClusterPropagationPolicy(resourceTemplate *uns // fetchResourceTemplate fetches resource template by resource selector, ignore it if not found or deleting. func (d *ResourceDetector) fetchResourceTemplate(rs policyv1alpha1.ResourceSelector) (*unstructured.Unstructured, error) { - resourceTemplate, err := helper.FetchResourceTemplate(d.DynamicClient, d.InformerManager, d.RESTMapper, helper.ConstructObjectReference(rs)) + resourceTemplate, err := helper.FetchResourceTemplate(context.TODO(), d.DynamicClient, d.InformerManager, d.RESTMapper, helper.ConstructObjectReference(rs)) if err != nil { // do nothing if resource template not exist, it might has been removed. if apierrors.IsNotFound(err) { diff --git a/pkg/detector/preemption_test.go b/pkg/detector/preemption_test.go new file mode 100644 index 000000000000..bcda63c957c8 --- /dev/null +++ b/pkg/detector/preemption_test.go @@ -0,0 +1,651 @@ +/* +Copyright 2024 The Karmada 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 detector + +import ( + "fmt" + "testing" + "time" + + appsv1 "k8s.io/api/apps/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + dynamicfake "k8s.io/client-go/dynamic/fake" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1" + "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" + "github.com/karmada-io/karmada/pkg/util/fedinformer/genericmanager" +) + +type MockAsyncWorker struct { + queue []interface{} +} + +// Note: This is a dummy implementation of Add for testing purposes. +func (m *MockAsyncWorker) Add(item interface{}) { + // No actual work is done in the mock; we just simulate running + m.queue = append(m.queue, item) +} + +// Note: This is a dummy implementation of AddAfter for testing purposes. +func (m *MockAsyncWorker) AddAfter(item interface{}, duration time.Duration) { + // No actual work is done in the mock; we just simulate running + fmt.Printf("%v", duration) + m.queue = append(m.queue, item) +} + +// Note: This is a dummy implementation of Enqueue for testing purposes. +func (m *MockAsyncWorker) Enqueue(obj interface{}) { + // Assuming KeyFunc is used to generate a key; for simplicity, we use obj directly + m.queue = append(m.queue, obj) +} + +// Note: This is a dummy implementation of Run for testing purposes. +func (m *MockAsyncWorker) Run(workerNumber int, stopChan <-chan struct{}) { + // No actual work is done in the mock; we just simulate running + fmt.Printf("%v", workerNumber) + fmt.Printf("%v", <-stopChan) +} + +// GetQueue returns the current state of the queue +func (m *MockAsyncWorker) GetQueue() []interface{} { + return m.queue +} + +func TestHandleDeprioritizedPropagationPolicy(t *testing.T) { + scheme := runtime.NewScheme() + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + utilruntime.Must(appsv1.AddToScheme(scheme)) + utilruntime.Must(v1alpha2.Install(scheme)) + utilruntime.Must(policyv1alpha1.Install(scheme)) + + propagationPolicyGVR := schema.GroupVersionResource{ + Group: policyv1alpha1.GroupVersion.Group, + Version: policyv1alpha1.GroupVersion.Version, + Resource: policyv1alpha1.ResourcePluralPropagationPolicy, + } + + tests := []struct { + name string + newPolicy *policyv1alpha1.PropagationPolicy + oldPolicy *policyv1alpha1.PropagationPolicy + objects []runtime.Object + setupClient func() *fake.ClientBuilder + wantQueueSize int + }{ + { + name: "preempt deprioritized propagation policy of len 1", + newPolicy: &policyv1alpha1.PropagationPolicy{ + ObjectMeta: metav1.ObjectMeta{Name: "app", Namespace: "test"}, + Spec: policyv1alpha1.PropagationSpec{ + Priority: ptr.To[int32](2), + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + LabelSelector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "nginx"}}, + }, + }, + }, + }, + oldPolicy: &policyv1alpha1.PropagationPolicy{ + ObjectMeta: metav1.ObjectMeta{Name: "app", Namespace: "test"}, + Spec: policyv1alpha1.PropagationSpec{ + Priority: ptr.To[int32](4), + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + LabelSelector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "nginx"}}, + }, + }, + }, + }, + objects: []runtime.Object{ + &policyv1alpha1.PropagationPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "test", + Labels: map[string]string{ + policyv1alpha1.PropagationPolicyPermanentIDLabel: "policy-1", + }, + }, + Spec: policyv1alpha1.PropagationSpec{ + Priority: ptr.To[int32](3), + Preemption: policyv1alpha1.PreemptAlways, + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + Name: "default", + }, + }, + }, + }, + }, + setupClient: func() *fake.ClientBuilder { + obj := &policyv1alpha1.PropagationPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "test", + Labels: map[string]string{ + policyv1alpha1.PropagationPolicyPermanentIDLabel: "policy-1", + }, + }, + Spec: policyv1alpha1.PropagationSpec{ + Priority: ptr.To[int32](3), + Preemption: policyv1alpha1.PreemptAlways, + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + Name: "default", + }, + }, + }, + } + return fake.NewClientBuilder().WithScheme(scheme).WithObjects(obj) + }, + wantQueueSize: 1, + }, + { + name: "preempt deprioritized propagation policy of len 2", + newPolicy: &policyv1alpha1.PropagationPolicy{ + ObjectMeta: metav1.ObjectMeta{Name: "app", Namespace: "test"}, + Spec: policyv1alpha1.PropagationSpec{ + Priority: ptr.To[int32](2), + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + LabelSelector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "nginx"}}, + }, + }, + }, + }, + oldPolicy: &policyv1alpha1.PropagationPolicy{ + ObjectMeta: metav1.ObjectMeta{Name: "app", Namespace: "test"}, + Spec: policyv1alpha1.PropagationSpec{ + Priority: ptr.To[int32](5), + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + LabelSelector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "nginx"}}, + }, + }, + }, + }, + objects: []runtime.Object{ + &policyv1alpha1.PropagationPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "test", + Labels: map[string]string{ + policyv1alpha1.PropagationPolicyPermanentIDLabel: "policy-1", + }, + }, + Spec: policyv1alpha1.PropagationSpec{ + Priority: ptr.To[int32](3), + Preemption: policyv1alpha1.PreemptAlways, + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + Name: "default", + }, + }, + }, + }, + &policyv1alpha1.PropagationPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo-2", + Namespace: "test", + Labels: map[string]string{ + policyv1alpha1.PropagationPolicyPermanentIDLabel: "policy-2", + }, + }, + Spec: policyv1alpha1.PropagationSpec{ + Priority: ptr.To[int32](4), + Preemption: policyv1alpha1.PreemptAlways, + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test-2", + Name: "default-2", + }, + }, + }, + }, + }, + setupClient: func() *fake.ClientBuilder { + obj := []client.Object{ + &policyv1alpha1.PropagationPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "test", + Labels: map[string]string{ + policyv1alpha1.PropagationPolicyPermanentIDLabel: "policy-1", + }, + }, + Spec: policyv1alpha1.PropagationSpec{ + Priority: ptr.To[int32](3), + Preemption: policyv1alpha1.PreemptAlways, + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + Name: "default", + }, + }, + }, + }, + &policyv1alpha1.PropagationPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo-2", + Namespace: "test", + Labels: map[string]string{ + policyv1alpha1.PropagationPolicyPermanentIDLabel: "policy-2", + }, + }, + Spec: policyv1alpha1.PropagationSpec{ + Priority: ptr.To[int32](4), + Preemption: policyv1alpha1.PreemptAlways, + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test-2", + Name: "default-2", + }, + }, + }, + }, + } + return fake.NewClientBuilder().WithScheme(scheme).WithObjects(obj...) + }, + wantQueueSize: 2, + }, + { + name: "no policy to preempt", + newPolicy: &policyv1alpha1.PropagationPolicy{ + ObjectMeta: metav1.ObjectMeta{Name: "app", Namespace: "test"}, + Spec: policyv1alpha1.PropagationSpec{ + Priority: ptr.To[int32](2), + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + LabelSelector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "nginx"}}, + }, + }, + }, + }, + oldPolicy: &policyv1alpha1.PropagationPolicy{ + ObjectMeta: metav1.ObjectMeta{Name: "app", Namespace: "test"}, + Spec: policyv1alpha1.PropagationSpec{ + Priority: ptr.To[int32](4), + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + LabelSelector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "nginx"}}, + }, + }, + }, + }, + objects: nil, + setupClient: func() *fake.ClientBuilder { + return fake.NewClientBuilder().WithScheme(scheme) + }, + wantQueueSize: 0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fakeClient := tt.setupClient().Build() + stopCh := make(chan struct{}) + defer close(stopCh) + fakeDynamicClient := dynamicfake.NewSimpleDynamicClient(scheme, tt.objects...) + genMgr := genericmanager.NewSingleClusterInformerManager(fakeDynamicClient, 0, stopCh) + resourceDetector := &ResourceDetector{ + Client: fakeClient, + DynamicClient: fakeDynamicClient, + InformerManager: genMgr, + propagationPolicyLister: genMgr.Lister(propagationPolicyGVR), + } + mockWorker := &MockAsyncWorker{} + resourceDetector.policyReconcileWorker = mockWorker + resourceDetector.InformerManager.Start() + resourceDetector.InformerManager.WaitForCacheSync() + + resourceDetector.HandleDeprioritizedPropagationPolicy(*tt.oldPolicy, *tt.newPolicy) + + gotQueueSize := len(mockWorker.GetQueue()) + if gotQueueSize != tt.wantQueueSize { + t.Errorf("HandleDeprioritizedPropagationPolicy() want queue size %v, got %v", tt.wantQueueSize, gotQueueSize) + } + }) + } +} + +func TestHandleDeprioritizedClusterPropagationPolicy(t *testing.T) { + scheme := runtime.NewScheme() + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + utilruntime.Must(appsv1.AddToScheme(scheme)) + utilruntime.Must(v1alpha2.Install(scheme)) + utilruntime.Must(policyv1alpha1.Install(scheme)) + + clusterPropagationPolicyGVR := schema.GroupVersionResource{ + Group: policyv1alpha1.GroupVersion.Group, + Version: policyv1alpha1.GroupVersion.Version, + Resource: policyv1alpha1.ResourcePluralClusterPropagationPolicy, + } + + tests := []struct { + name string + newPolicy *policyv1alpha1.ClusterPropagationPolicy + oldPolicy *policyv1alpha1.ClusterPropagationPolicy + objects []runtime.Object + setupClient func() *fake.ClientBuilder + wantQueueSize int + }{ + { + name: "preempt deprioritized cluster propagation policy of len 1", + newPolicy: &policyv1alpha1.ClusterPropagationPolicy{ + ObjectMeta: metav1.ObjectMeta{Name: "app", Namespace: "test"}, + Spec: policyv1alpha1.PropagationSpec{ + Priority: ptr.To[int32](2), + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + LabelSelector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "nginx"}}, + }, + }, + }, + }, + oldPolicy: &policyv1alpha1.ClusterPropagationPolicy{ + ObjectMeta: metav1.ObjectMeta{Name: "app", Namespace: "test"}, + Spec: policyv1alpha1.PropagationSpec{ + Priority: ptr.To[int32](4), + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + LabelSelector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "nginx"}}, + }, + }, + }, + }, + objects: []runtime.Object{ + &policyv1alpha1.ClusterPropagationPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + Labels: map[string]string{ + policyv1alpha1.ClusterPropagationPolicyPermanentIDLabel: "policy-1", + }, + }, + Spec: policyv1alpha1.PropagationSpec{ + Priority: ptr.To[int32](3), + Preemption: policyv1alpha1.PreemptAlways, + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + Name: "default", + }, + }, + }, + }, + }, + setupClient: func() *fake.ClientBuilder { + obj := &policyv1alpha1.ClusterPropagationPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + Labels: map[string]string{ + policyv1alpha1.ClusterPropagationPolicyPermanentIDLabel: "policy-1", + }, + }, + Spec: policyv1alpha1.PropagationSpec{ + Priority: ptr.To[int32](3), + Preemption: policyv1alpha1.PreemptAlways, + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + Name: "default", + }, + }, + }, + } + return fake.NewClientBuilder().WithScheme(scheme).WithObjects(obj) + }, + wantQueueSize: 1, + }, + { + name: "preempt deprioritized cluster propagation policy of len 2", + newPolicy: &policyv1alpha1.ClusterPropagationPolicy{ + ObjectMeta: metav1.ObjectMeta{Name: "app", Namespace: "test"}, + Spec: policyv1alpha1.PropagationSpec{ + Priority: ptr.To[int32](2), + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + LabelSelector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "nginx"}}, + }, + }, + }, + }, + oldPolicy: &policyv1alpha1.ClusterPropagationPolicy{ + ObjectMeta: metav1.ObjectMeta{Name: "app", Namespace: "test"}, + Spec: policyv1alpha1.PropagationSpec{ + Priority: ptr.To[int32](5), + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + LabelSelector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "nginx"}}, + }, + }, + }, + }, + objects: []runtime.Object{ + &policyv1alpha1.ClusterPropagationPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + Labels: map[string]string{ + policyv1alpha1.ClusterPropagationPolicyPermanentIDLabel: "policy-1", + }, + }, + Spec: policyv1alpha1.PropagationSpec{ + Priority: ptr.To[int32](3), + Preemption: policyv1alpha1.PreemptAlways, + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + Name: "default", + }, + }, + }, + }, + &policyv1alpha1.ClusterPropagationPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo-2", + Namespace: "bar-2", + Labels: map[string]string{ + policyv1alpha1.ClusterPropagationPolicyPermanentIDLabel: "policy-2", + }, + }, + Spec: policyv1alpha1.PropagationSpec{ + Priority: ptr.To[int32](4), + Preemption: policyv1alpha1.PreemptAlways, + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test-2", + Name: "default-2", + }, + }, + }, + }, + }, + setupClient: func() *fake.ClientBuilder { + obj := []client.Object{ + &policyv1alpha1.ClusterPropagationPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + Labels: map[string]string{ + policyv1alpha1.ClusterPropagationPolicyPermanentIDLabel: "policy-1", + }, + }, + Spec: policyv1alpha1.PropagationSpec{ + Priority: ptr.To[int32](3), + Preemption: policyv1alpha1.PreemptAlways, + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + Name: "default", + }, + }, + }, + }, + &policyv1alpha1.ClusterPropagationPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo-2", + Namespace: "bar-2", + Labels: map[string]string{ + policyv1alpha1.ClusterPropagationPolicyPermanentIDLabel: "policy-2", + }, + }, + Spec: policyv1alpha1.PropagationSpec{ + Priority: ptr.To[int32](4), + Preemption: policyv1alpha1.PreemptAlways, + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test-2", + Name: "default-2", + }, + }, + }, + }, + } + return fake.NewClientBuilder().WithScheme(scheme).WithObjects(obj...) + }, + wantQueueSize: 2, + }, + { + name: "no cluster policy to preempt", + newPolicy: &policyv1alpha1.ClusterPropagationPolicy{ + ObjectMeta: metav1.ObjectMeta{Name: "app", Namespace: "test"}, + Spec: policyv1alpha1.PropagationSpec{ + Priority: ptr.To[int32](2), + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + LabelSelector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "nginx"}}, + }, + }, + }, + }, + oldPolicy: &policyv1alpha1.ClusterPropagationPolicy{ + ObjectMeta: metav1.ObjectMeta{Name: "app", Namespace: "test"}, + Spec: policyv1alpha1.PropagationSpec{ + Priority: ptr.To[int32](4), + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "test", + LabelSelector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "nginx"}}, + }, + }, + }, + }, + objects: nil, + setupClient: func() *fake.ClientBuilder { + return fake.NewClientBuilder().WithScheme(scheme) + }, + wantQueueSize: 0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fakeClient := tt.setupClient().Build() + stopCh := make(chan struct{}) + defer close(stopCh) + fakeDynamicClient := dynamicfake.NewSimpleDynamicClient(scheme, tt.objects...) + genMgr := genericmanager.NewSingleClusterInformerManager(fakeDynamicClient, 0, stopCh) + resourceDetector := &ResourceDetector{ + Client: fakeClient, + DynamicClient: fakeDynamicClient, + InformerManager: genMgr, + clusterPropagationPolicyLister: genMgr.Lister(clusterPropagationPolicyGVR), + } + mockWorker := &MockAsyncWorker{} + resourceDetector.clusterPolicyReconcileWorker = mockWorker + resourceDetector.InformerManager.Start() + resourceDetector.InformerManager.WaitForCacheSync() + + resourceDetector.HandleDeprioritizedClusterPropagationPolicy(*tt.oldPolicy, *tt.newPolicy) + + gotQueueSize := len(mockWorker.GetQueue()) + if gotQueueSize != tt.wantQueueSize { + t.Errorf("HandleDeprioritizedClusterPropagationPolicy() want queue size %v, got %v", tt.wantQueueSize, gotQueueSize) + } + }) + } +} diff --git a/pkg/estimator/client/service_test.go b/pkg/estimator/client/service_test.go new file mode 100644 index 000000000000..9d074e7864db --- /dev/null +++ b/pkg/estimator/client/service_test.go @@ -0,0 +1,172 @@ +/* +Copyright 2024 The Karmada 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 client + +import ( + "context" + "testing" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/client-go/kubernetes/fake" +) + +func TestResolveCluster(t *testing.T) { + tests := []struct { + name string + namespace string + id string + port int32 + service *corev1.Service + expectError bool + expected string + }{ + { + name: "Service not found", + namespace: "default", + id: "nonexistent", + port: 80, + service: nil, + expected: "nonexistent.default.svc.cluster.local:80", + }, + { + name: "Unsupported service type", + namespace: "default", + id: "myservice", + port: 80, + service: &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "myservice", + Namespace: "default", + }, + Spec: corev1.ServiceSpec{ + Type: corev1.ServiceTypeClusterIP, + }, + }, + expectError: true, + }, + { + name: "ExternalName service with int target port", + namespace: "default", + id: "myservice", + port: 80, + service: &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "myservice", + Namespace: "default", + }, + Spec: corev1.ServiceSpec{ + Type: corev1.ServiceTypeExternalName, + ExternalName: "example.com", + Ports: []corev1.ServicePort{ + { + Port: 80, + TargetPort: intstr.FromInt(8080), + }, + }, + }, + }, + expected: "example.com:8080", + }, + { + name: "ExternalName service with non-int target port", + namespace: "default", + id: "myservice", + port: 80, + service: &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "myservice", + Namespace: "default", + }, + Spec: corev1.ServiceSpec{ + Type: corev1.ServiceTypeExternalName, + ExternalName: "example.com", + Ports: []corev1.ServicePort{ + { + Port: 80, + TargetPort: intstr.FromString("http"), + }, + }, + }, + }, + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + clientset := fake.NewSimpleClientset() + if tt.service != nil { + _, err := clientset.CoreV1().Services(tt.namespace).Create(context.TODO(), tt.service, metav1.CreateOptions{}) + if err != nil { + t.Fatalf("failed to create service: %v", err) + } + } + + result, err := resolveCluster(clientset, tt.namespace, tt.id, tt.port) + if (err != nil) != tt.expectError { + t.Errorf("expected error: %v, got: %v", tt.expectError, err) + } + if result != tt.expected { + t.Errorf("expected: %s, got: %s", tt.expected, result) + } + }) + } +} + +func TestFindServicePort(t *testing.T) { + tests := []struct { + name string + service *corev1.Service + port int32 + expectError bool + }{ + { + name: "Port found", + service: &corev1.Service{ + Spec: corev1.ServiceSpec{ + Ports: []corev1.ServicePort{ + {Port: 80}, + }, + }, + }, + port: 80, + }, + { + name: "Port not found", + service: &corev1.Service{ + Spec: corev1.ServiceSpec{ + Ports: []corev1.ServicePort{ + {Port: 8080}, + }, + }, + }, + port: 80, + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := findServicePort(tt.service, tt.port) + if (err != nil) != tt.expectError { + t.Errorf("expected error: %v, got: %v", tt.expectError, err) + } + }) + } +} diff --git a/pkg/events/events.go b/pkg/events/events.go index ea94a2cf99dd..8e3e945b2247 100644 --- a/pkg/events/events.go +++ b/pkg/events/events.go @@ -54,6 +54,8 @@ const ( EventReasonSyncWorkloadFailed = "SyncFailed" // EventReasonSyncWorkloadSucceed indicates that Sync workload succeed. EventReasonSyncWorkloadSucceed = "SyncSucceed" + // EventReasonWorkDispatching indicates that work is dispatching or not. + EventReasonWorkDispatching = "WorkDispatching" ) // Define events for ResourceBinding and ClusterResourceBinding objects. diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index 3b328475e3da..28551c07266e 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -8320,7 +8320,7 @@ func schema_k8sio_api_admissionregistration_v1_ValidatingAdmissionPolicyBindingS }, }, SchemaProps: spec.SchemaProps{ - Description: "validationActions declares how Validations of the referenced ValidatingAdmissionPolicy are enforced. If a validation evaluates to false it is always enforced according to these actions.\n\nFailures defined by the ValidatingAdmissionPolicy's FailurePolicy are enforced according to these actions only if the FailurePolicy is set to Fail, otherwise the failures are ignored. This includes compilation errors, runtime errors and misconfigurations of the policy.\n\nvalidationActions is declared as a set of action values. Order does not matter. validationActions may not contain duplicates of the same action.\n\nThe supported actions values are:\n\n\"Deny\" specifies that a validation failure results in a denied request.\n\n\"Warn\" specifies that a validation failure is reported to the request client in HTTP Warning headers, with a warning code of 299. Warnings can be sent both for allowed or denied admission responses.\n\n\"Audit\" specifies that a validation failure is included in the published audit event for the request. The audit event will contain a `validation.policy.admission.k8s.io/validation_failure` audit annotation with a value containing the details of the validation failures, formatted as a JSON list of objects, each with the following fields: - message: The validation failure message string - policy: The resource name of the ValidatingAdmissionPolicy - binding: The resource name of the ValidatingAdmissionPolicyBinding - expressionIndex: The index of the failed validations in the ValidatingAdmissionPolicy - validationActions: The enforcement actions enacted for the validation failure Example audit annotation: `\"validation.policy.admission.k8s.io/validation_failure\": \"[{\"message\": \"Invalid value\", {\"policy\": \"policy.example.com\", {\"binding\": \"policybinding.example.com\", {\"expressionIndex\": \"1\", {\"validationActions\": [\"Audit\"]}]\"`\n\nClients should expect to handle additional values by ignoring any values not recognized.\n\n\"Deny\" and \"Warn\" may not be used together since this combination needlessly duplicates the validation failure both in the API response body and the HTTP warning headers.\n\nRequired.", + Description: "validationActions declares how Validations of the referenced ValidatingAdmissionPolicy are enforced. If a validation evaluates to false it is always enforced according to these actions.\n\nFailures defined by the ValidatingAdmissionPolicy's FailurePolicy are enforced according to these actions only if the FailurePolicy is set to Fail, otherwise the failures are ignored. This includes compilation errors, runtime errors and misconfigurations of the policy.\n\nvalidationActions is declared as a set of action values. Order does not matter. validationActions may not contain duplicates of the same action.\n\nThe supported actions values are:\n\n\"Deny\" specifies that a validation failure results in a denied request.\n\n\"Warn\" specifies that a validation failure is reported to the request client in HTTP Warning headers, with a warning code of 299. Warnings can be sent both for allowed or denied admission responses.\n\n\"Audit\" specifies that a validation failure is included in the published audit event for the request. The audit event will contain a `validation.policy.admission.k8s.io/validation_failure` audit annotation with a value containing the details of the validation failures, formatted as a JSON list of objects, each with the following fields: - message: The validation failure message string - policy: The resource name of the ValidatingAdmissionPolicy - binding: The resource name of the ValidatingAdmissionPolicyBinding - expressionIndex: The index of the failed validations in the ValidatingAdmissionPolicy - validationActions: The enforcement actions enacted for the validation failure Example audit annotation: `\"validation.policy.admission.k8s.io/validation_failure\": \"[{\\\"message\\\": \\\"Invalid value\\\", {\\\"policy\\\": \\\"policy.example.com\\\", {\\\"binding\\\": \\\"policybinding.example.com\\\", {\\\"expressionIndex\\\": \\\"1\\\", {\\\"validationActions\\\": [\\\"Audit\\\"]}]\"`\n\nClients should expect to handle additional values by ignoring any values not recognized.\n\n\"Deny\" and \"Warn\" may not be used together since this combination needlessly duplicates the validation failure both in the API response body and the HTTP warning headers.\n\nRequired.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -18611,7 +18611,7 @@ func schema_k8sio_api_core_v1_PodSpec(ref common.ReferenceCallback) common.OpenA }, "setHostnameAsFQDN": { SchemaProps: spec.SchemaProps{ - Description: "If true the pod's hostname will be configured as the pod's FQDN, rather than the leaf name (the default). In Linux containers, this means setting the FQDN in the hostname field of the kernel (the nodename field of struct utsname). In Windows containers, this means setting the registry value of hostname for the registry key HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters to FQDN. If a pod does not have FQDN, this has no effect. Default to false.", + Description: "If true the pod's hostname will be configured as the pod's FQDN, rather than the leaf name (the default). In Linux containers, this means setting the FQDN in the hostname field of the kernel (the nodename field of struct utsname). In Windows containers, this means setting the registry value of hostname for the registry key HKEY_LOCAL_MACHINE\\\\SYSTEM\\\\CurrentControlSet\\\\Services\\\\Tcpip\\\\Parameters to FQDN. If a pod does not have FQDN, this has no effect. Default to false.", Type: []string{"boolean"}, Format: "", }, @@ -25059,7 +25059,7 @@ func schema_pkg_apis_apiextensions_v1_JSONSchemaProps(ref common.ReferenceCallba }, "format": { SchemaProps: spec.SchemaProps{ - Description: "format is an OpenAPI v3 format string. Unknown formats are ignored. The following formats are validated:\n\n- bsonobjectid: a bson object ID, i.e. a 24 characters hex string - uri: an URI as parsed by Golang net/url.ParseRequestURI - email: an email address as parsed by Golang net/mail.ParseAddress - hostname: a valid representation for an Internet host name, as defined by RFC 1034, section 3.1 [RFC1034]. - ipv4: an IPv4 IP as parsed by Golang net.ParseIP - ipv6: an IPv6 IP as parsed by Golang net.ParseIP - cidr: a CIDR as parsed by Golang net.ParseCIDR - mac: a MAC address as parsed by Golang net.ParseMAC - uuid: an UUID that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$ - uuid3: an UUID3 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?3[0-9a-f]{3}-?[0-9a-f]{4}-?[0-9a-f]{12}$ - uuid4: an UUID4 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?4[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12}$ - uuid5: an UUID5 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?5[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12}$ - isbn: an ISBN10 or ISBN13 number string like \"0321751043\" or \"978-0321751041\" - isbn10: an ISBN10 number string like \"0321751043\" - isbn13: an ISBN13 number string like \"978-0321751041\" - creditcard: a credit card number defined by the regex ^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11})$ with any non digit characters mixed in - ssn: a U.S. social security number following the regex ^\\d{3}[- ]?\\d{2}[- ]?\\d{4}$ - hexcolor: an hexadecimal color code like \"#FFFFFF: following the regex ^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$ - rgbcolor: an RGB color code like rgb like \"rgb(255,255,2559\" - byte: base64 encoded binary data - password: any kind of string - date: a date string like \"2006-01-02\" as defined by full-date in RFC3339 - duration: a duration string like \"22 ns\" as parsed by Golang time.ParseDuration or compatible with Scala duration format - datetime: a date time string like \"2014-12-15T19:30:20.000Z\" as defined by date-time in RFC3339.", + Description: "format is an OpenAPI v3 format string. Unknown formats are ignored. The following formats are validated:\n\n- bsonobjectid: a bson object ID, i.e. a 24 characters hex string - uri: an URI as parsed by Golang net/url.ParseRequestURI - email: an email address as parsed by Golang net/mail.ParseAddress - hostname: a valid representation for an Internet host name, as defined by RFC 1034, section 3.1 [RFC1034]. - ipv4: an IPv4 IP as parsed by Golang net.ParseIP - ipv6: an IPv6 IP as parsed by Golang net.ParseIP - cidr: a CIDR as parsed by Golang net.ParseCIDR - mac: a MAC address as parsed by Golang net.ParseMAC - uuid: an UUID that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$ - uuid3: an UUID3 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?3[0-9a-f]{3}-?[0-9a-f]{4}-?[0-9a-f]{12}$ - uuid4: an UUID4 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?4[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12}$ - uuid5: an UUID5 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?5[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12}$ - isbn: an ISBN10 or ISBN13 number string like \"0321751043\" or \"978-0321751041\" - isbn10: an ISBN10 number string like \"0321751043\" - isbn13: an ISBN13 number string like \"978-0321751041\" - creditcard: a credit card number defined by the regex ^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\\\d{3})\\\\d{11})$ with any non digit characters mixed in - ssn: a U.S. social security number following the regex ^\\\\d{3}[- ]?\\\\d{2}[- ]?\\\\d{4}$ - hexcolor: an hexadecimal color code like \"#FFFFFF: following the regex ^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$ - rgbcolor: an RGB color code like rgb like \"rgb(255,255,2559\" - byte: base64 encoded binary data - password: any kind of string - date: a date string like \"2006-01-02\" as defined by full-date in RFC3339 - duration: a duration string like \"22 ns\" as parsed by Golang time.ParseDuration or compatible with Scala duration format - datetime: a date time string like \"2014-12-15T19:30:20.000Z\" as defined by date-time in RFC3339.", Type: []string{"string"}, Format: "", }, diff --git a/pkg/karmadactl/addons/descheduler/manifests.go b/pkg/karmadactl/addons/descheduler/manifests.go index 5b54f25ce098..ad28d37d4aa6 100644 --- a/pkg/karmadactl/addons/descheduler/manifests.go +++ b/pkg/karmadactl/addons/descheduler/manifests.go @@ -45,8 +45,8 @@ spec: command: - /bin/karmada-descheduler - --kubeconfig=/etc/kubeconfig - - --bind-address=0.0.0.0 - - --secure-port=10358 + - --metrics-bind-address=0.0.0.0:10358 + - --health-probe-bind-address=0.0.0.0:10358 - --leader-elect-resource-namespace={{ .Namespace }} - --scheduler-estimator-ca-file=/etc/karmada/pki/ca.crt - --scheduler-estimator-cert-file=/etc/karmada/pki/karmada.crt diff --git a/pkg/karmadactl/addons/estimator/manifests.go b/pkg/karmadactl/addons/estimator/manifests.go index a640fbc0446f..cc98b6b052a0 100644 --- a/pkg/karmadactl/addons/estimator/manifests.go +++ b/pkg/karmadactl/addons/estimator/manifests.go @@ -48,12 +48,12 @@ spec: - /bin/karmada-scheduler-estimator - --kubeconfig=/etc/{{ .MemberClusterName}}-kubeconfig - --cluster-name={{ .MemberClusterName}} - - --bind-address=0.0.0.0 - - --secure-port=10351 - --grpc-auth-cert-file=/etc/karmada/pki/karmada.crt - --grpc-auth-key-file=/etc/karmada/pki/karmada.key - --client-cert-auth=true - --grpc-client-ca-file=/etc/karmada/pki/ca.crt + - --metrics-bind-address=0.0.0.0:10351 + - --health-probe-bind-address=0.0.0.0:10351 livenessProbe: httpGet: path: /healthz diff --git a/pkg/karmadactl/annotate/annotate.go b/pkg/karmadactl/annotate/annotate.go new file mode 100644 index 000000000000..934d17769561 --- /dev/null +++ b/pkg/karmadactl/annotate/annotate.go @@ -0,0 +1,55 @@ +/* +Copyright 2024 The Karmada 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 annotate + +import ( + "fmt" + + "github.com/spf13/cobra" + "k8s.io/cli-runtime/pkg/genericiooptions" + kubectlannotate "k8s.io/kubectl/pkg/cmd/annotate" + "k8s.io/kubectl/pkg/util/templates" + + "github.com/karmada-io/karmada/pkg/karmadactl/util" +) + +var ( + annotateExample = templates.Examples(` + # Update deployment 'foo' with the annotation 'work.karmada.io/conflict-resolution' and the value 'overwrite' + # If the same annotation is set multiple times, only the last value will be applied + [1]%s annotate deployment foo work.karmada.io/conflict-resolution='overwrite' + + # Update a deployment identified by type and name in "deployment.json" + [1]%s annotate -f deployment.json work.karmada.io/conflict-resolution='overwrite' + + # Update deployment 'foo' with the annotation 'work.karmada.io/conflict-resolution' and the value 'abort', overwriting any existing value + [1]%s annotate --overwrite deployment foo work.karmada.io/conflict-resolution='abort' + + # Update all deployments in the namespace + [1]%s annotate deployment --all work.karmada.io/conflict-resolution='abort' + + # Update deployment 'foo' only if the resource is unchanged from version 1 + [1]%s annotate deployment foo work.karmada.io/conflict-resolution='abort' --resource-version=1 + + # Update deployment 'foo' by removing an annotation named 'work.karmada.io/conflict-resolution' if it exists + # Does not require the --overwrite flag + [1]%s annotate deployment foo work.karmada.io/conflict-resolution-`) +) + +// NewCmdAnnotate returns new initialized instance of annotate sub command +func NewCmdAnnotate(f util.Factory, parentCommand string, ioStreams genericiooptions.IOStreams) *cobra.Command { + cmd := kubectlannotate.NewCmdAnnotate(parentCommand, f, ioStreams) + cmd.Example = fmt.Sprintf(annotateExample, parentCommand) + return cmd +} diff --git a/pkg/karmadactl/apiresources/apiresources.go b/pkg/karmadactl/apiresources/apiresources.go new file mode 100644 index 000000000000..a5be361f7edf --- /dev/null +++ b/pkg/karmadactl/apiresources/apiresources.go @@ -0,0 +1,121 @@ +/* +Copyright 2024 The Karmada 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 apiresources + +import ( + "fmt" + + "github.com/spf13/cobra" + "k8s.io/cli-runtime/pkg/genericiooptions" + kubectlapiresources "k8s.io/kubectl/pkg/cmd/apiresources" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/util/templates" + + "github.com/karmada-io/karmada/pkg/karmadactl/options" + "github.com/karmada-io/karmada/pkg/karmadactl/util" +) + +var ( + apiresourcesExample = templates.Examples(` + # Print the supported API resources in Karmada control plane + %[1]s api-resources + + # Print the supported API resources with more information in cluster(member1) + %[1]s api-resources -o wide --operation-scope=members --cluster=member1 + + # Print the supported API resources sorted by a column in Karmada control plane + %[1]s api-resources --sort-by=name + + # Print the supported namespaced resources in Karmada control plane + %[1]s api-resources --namespaced=true + + # Print the supported non-namespaced resources in Karmada control plane + %[1]s api-resources --namespaced=false + + # Print the supported API resources with a specific APIGroup in Karmada control plane + %[1]s api-resources --api-group=rbac.authorization.k8s.io`) +) + +// NewCmdAPIResources creates the api-resources command +func NewCmdAPIResources(f util.Factory, parentCommand string, ioStreams genericiooptions.IOStreams) *cobra.Command { + var o CommandAPIResourcesOptions + o.APIResourceOptions = kubectlapiresources.NewAPIResourceOptions(ioStreams) + + cmd := &cobra.Command{ + Use: "api-resources", + Short: "Print the supported API resources on the server", + Long: "Print the supported API resources on the server.", + Example: fmt.Sprintf(apiresourcesExample, parentCommand), + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.RunAPIResources()) + }, + } + + o.OperationScope = options.KarmadaControlPlane + cmd.Flags().Var(&o.OperationScope, "operation-scope", "Used to control the operation scope of the command. The optional values are karmada and members. Defaults to karmada.") + cmd.Flags().StringVar(&o.Cluster, "cluster", "", "Used to specify a target member cluster and only takes effect when the command's operation scope is members, for example: --operation-scope=members --cluster=member1") + cmd.Flags().BoolVar(&o.NoHeaders, "no-headers", o.NoHeaders, "When using the default or custom-column output format, don't print headers (default print headers).") + cmd.Flags().StringVarP(&o.Output, "output", "o", o.Output, `Output format. One of: (wide, name).`) + + cmd.Flags().StringVar(&o.APIGroup, "api-group", o.APIGroup, "Limit to resources in the specified API group.") + cmd.Flags().BoolVar(&o.Namespaced, "namespaced", o.Namespaced, "If false, non-namespaced resources will be returned, otherwise returning namespaced resources by default.") + cmd.Flags().StringSliceVar(&o.Verbs, "verbs", o.Verbs, "Limit to resources that support the specified verbs.") + cmd.Flags().StringVar(&o.SortBy, "sort-by", o.SortBy, "If non-empty, sort list of resources using specified field. The field can be either 'name' or 'kind'.") + cmd.Flags().BoolVar(&o.Cached, "cached", o.Cached, "Use the cached list of resources if available.") + cmd.Flags().StringSliceVar(&o.Categories, "categories", o.Categories, "Limit to resources that belong to the specified categories.") + return cmd +} + +// CommandAPIResourcesOptions contains the input to the api-resources command. +type CommandAPIResourcesOptions struct { + // flags specific to describe + *kubectlapiresources.APIResourceOptions + Cluster string + OperationScope options.OperationScope +} + +// Complete adapts from the command line args and validates them +func (o *CommandAPIResourcesOptions) Complete(f util.Factory, cmd *cobra.Command, args []string) error { + var apiFactory cmdutil.Factory = f + if o.OperationScope == options.Members && len(o.Cluster) != 0 { + memberFactory, err := f.FactoryForMemberCluster(o.Cluster) + if err != nil { + return err + } + apiFactory = memberFactory + } + return o.APIResourceOptions.Complete(apiFactory, cmd, args) +} + +// Validate checks to the APIResourceOptions to see if there is sufficient information run the command +func (o *CommandAPIResourcesOptions) Validate() error { + err := options.VerifyOperationScopeFlags(o.OperationScope, options.KarmadaControlPlane, options.Members) + if err != nil { + return err + } + if o.OperationScope == options.Members && len(o.Cluster) == 0 { + return fmt.Errorf("must specify a member cluster") + } + return o.APIResourceOptions.Validate() +} + +// Run does the work +func (o *CommandAPIResourcesOptions) Run() error { + return o.APIResourceOptions.RunAPIResources() +} diff --git a/pkg/karmadactl/apiresources/apiversions.go b/pkg/karmadactl/apiresources/apiversions.go new file mode 100644 index 000000000000..1726a4277f1e --- /dev/null +++ b/pkg/karmadactl/apiresources/apiversions.go @@ -0,0 +1,100 @@ +/* +Copyright 2024 The Karmada 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 apiresources + +import ( + "fmt" + + "github.com/spf13/cobra" + "k8s.io/cli-runtime/pkg/genericiooptions" + kubectlapiresources "k8s.io/kubectl/pkg/cmd/apiresources" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/util/templates" + + "github.com/karmada-io/karmada/pkg/karmadactl/options" + "github.com/karmada-io/karmada/pkg/karmadactl/util" +) + +var ( + apiversionsExample = templates.Examples(` + # Print the supported API versions + %[1]s api-versions + + # Print the supported API versions in cluster(member1) + %[1]s api-versions --operation-scope=members --cluster=member1`) +) + +// NewCmdAPIVersions creates the api-versions command +func NewCmdAPIVersions(f util.Factory, parentCommand string, ioStreams genericiooptions.IOStreams) *cobra.Command { + var o CommandAPIVersionsOptions + o.APIVersionsOptions = kubectlapiresources.NewAPIVersionsOptions(ioStreams) + cmd := &cobra.Command{ + Use: "api-versions", + Short: "Print the supported API versions on the server, in the form of \"group/version\"", + Long: "Print the supported API versions on the server, in the form of \"group/version\".", + Example: fmt.Sprintf(apiversionsExample, parentCommand), + DisableFlagsInUseLine: true, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.RunAPIVersions()) + }, + } + + o.OperationScope = options.KarmadaControlPlane + cmd.Flags().Var(&o.OperationScope, "operation-scope", "Used to control the operation scope of the command. The optional values are karmada and members. Defaults to karmada.") + cmd.Flags().StringVar(&o.Cluster, "cluster", "", "Used to specify a target member cluster and only takes effect when the command's operation scope is members, for example: --operation-scope=members --cluster=member1") + return cmd +} + +// CommandAPIVersionsOptions contains the input to the api-versions command. +type CommandAPIVersionsOptions struct { + // flags specific to api-versions + *kubectlapiresources.APIVersionsOptions + Cluster string + OperationScope options.OperationScope +} + +// Complete adapts from the command line args and factory to the data required +func (o *CommandAPIVersionsOptions) Complete(f util.Factory, cmd *cobra.Command, args []string) error { + var apiFactory cmdutil.Factory = f + if o.OperationScope == options.Members && len(o.Cluster) != 0 { + memberFactory, err := f.FactoryForMemberCluster(o.Cluster) + if err != nil { + return err + } + apiFactory = memberFactory + } + return o.APIVersionsOptions.Complete(apiFactory, cmd, args) +} + +// Validate checks to the APIVersionsOptions to see if there is sufficient information run the command +func (o *CommandAPIVersionsOptions) Validate() error { + err := options.VerifyOperationScopeFlags(o.OperationScope, options.KarmadaControlPlane, options.Members) + if err != nil { + return err + } + if o.OperationScope == options.Members && len(o.Cluster) == 0 { + return fmt.Errorf("must specify a member cluster") + } + return nil +} + +// Run does the work +func (o *CommandAPIVersionsOptions) Run() error { + return o.APIVersionsOptions.RunAPIVersions() +} diff --git a/pkg/karmadactl/attach/attach.go b/pkg/karmadactl/attach/attach.go new file mode 100644 index 000000000000..9676bfab1784 --- /dev/null +++ b/pkg/karmadactl/attach/attach.go @@ -0,0 +1,124 @@ +/* +Copyright 2024 The Karmada 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 attach + +import ( + "fmt" + "time" + + "github.com/spf13/cobra" + "k8s.io/cli-runtime/pkg/genericiooptions" + kubectlattach "k8s.io/kubectl/pkg/cmd/attach" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/util/completion" + "k8s.io/kubectl/pkg/util/templates" + + "github.com/karmada-io/karmada/pkg/karmadactl/options" + "github.com/karmada-io/karmada/pkg/karmadactl/util" +) + +var ( + attachExample = templates.Examples(` + # Get output from running pod mypod in cluster(member1); use the 'kubectl.kubernetes.io/default-container' annotation + # for selecting the container to be attached or the first container in the pod will be chosen + %[1]s attach mypod --cluster=member1 + + # Get output from ruby-container from pod mypod in cluster(member1) + %[1]s attach mypod -c ruby-container --cluster=member1 + + # Switch to raw terminal mode; sends stdin to 'bash' in ruby-container from pod mypod in Karmada control plane + # and sends stdout/stderr from 'bash' back to the client + %[1]s attach mypod -c ruby-container -i -t + + # Get output from the first pod of a replica set named nginx in cluster(member1) + %[1]s attach rs/nginx --cluster=member1 + `) +) + +const ( + defaultPodAttachTimeout = 60 * time.Second +) + +// NewCmdAttach new attach command. +func NewCmdAttach(f util.Factory, parentCommand string, streams genericiooptions.IOStreams) *cobra.Command { + var o CommandAttachOptions + o.AttachOptions = kubectlattach.NewAttachOptions(streams) + + cmd := &cobra.Command{ + Use: "attach (POD | TYPE/NAME) -c CONTAINER", + DisableFlagsInUseLine: true, + Short: "Attach to a running container", + Long: "Attach to a process that is already running inside an existing container.", + Example: fmt.Sprintf(attachExample, parentCommand), + ValidArgsFunction: completion.PodResourceNameCompletionFunc(f), + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.Run()) + }, + } + + cmdutil.AddPodRunningTimeoutFlag(cmd, defaultPodAttachTimeout) + cmdutil.AddContainerVarFlags(cmd, &o.ContainerName, o.ContainerName) + options.AddKubeConfigFlags(cmd.Flags()) + o.OperationScope = options.KarmadaControlPlane + cmd.Flags().BoolVarP(&o.Stdin, "stdin", "i", o.Stdin, "Pass stdin to the container") + cmd.Flags().BoolVarP(&o.TTY, "tty", "t", o.TTY, "Stdin is a TTY") + cmd.Flags().BoolVarP(&o.Quiet, "quiet", "q", o.Quiet, "Only print output from the remote session") + cmd.Flags().StringVarP(options.DefaultConfigFlags.Namespace, "namespace", "n", *options.DefaultConfigFlags.Namespace, "If present, the namespace scope for this CLI request") + cmd.Flags().Var(&o.OperationScope, "operation-scope", "Used to control the operation scope of the command. The optional values are karmada and members. Defaults to karmada.") + cmd.Flags().StringVar(&o.Cluster, "cluster", "", "Used to specify a target member cluster and only takes effect when the command's operation scope is members, for example: --operation-scope=members --cluster=member1") + return cmd +} + +// CommandAttachOptions declare the arguments accepted by the attach command +type CommandAttachOptions struct { + // flags specific to attach + *kubectlattach.AttachOptions + Cluster string + OperationScope options.OperationScope +} + +// Complete verifies command line arguments and loads data from the command environment +func (o *CommandAttachOptions) Complete(f util.Factory, cmd *cobra.Command, args []string) error { + var attachFactory cmdutil.Factory = f + if o.OperationScope == options.Members && len(o.Cluster) != 0 { + memberFactory, err := f.FactoryForMemberCluster(o.Cluster) + if err != nil { + return err + } + attachFactory = memberFactory + } + return o.AttachOptions.Complete(attachFactory, cmd, args) +} + +// Validate checks that the provided attach options are specified. +func (o *CommandAttachOptions) Validate() error { + err := options.VerifyOperationScopeFlags(o.OperationScope, options.KarmadaControlPlane, options.Members) + if err != nil { + return err + } + if o.OperationScope == options.Members && len(o.Cluster) == 0 { + return fmt.Errorf("must specify a member cluster") + } + return o.AttachOptions.Validate() +} + +// Run executes a validated remote execution against a pod. +func (o *CommandAttachOptions) Run() error { + return o.AttachOptions.Run() +} diff --git a/pkg/karmadactl/cmdinit/kubernetes/deployments.go b/pkg/karmadactl/cmdinit/kubernetes/deployments.go index 3c112b5c28b9..793e7258b952 100644 --- a/pkg/karmadactl/cmdinit/kubernetes/deployments.go +++ b/pkg/karmadactl/cmdinit/kubernetes/deployments.go @@ -452,8 +452,8 @@ func (i *CommandInitOption) makeKarmadaSchedulerDeployment() *appsv1.Deployment Command: []string{ "/bin/karmada-scheduler", "--kubeconfig=/etc/kubeconfig", - "--bind-address=0.0.0.0", - "--secure-port=10351", + "--metrics-bind-address=0.0.0.0:10351", + "--health-probe-bind-address=0.0.0.0:10351", "--enable-scheduler-estimator=true", "--leader-elect=true", "--scheduler-estimator-ca-file=/etc/karmada/pki/ca.crt", @@ -591,10 +591,9 @@ func (i *CommandInitOption) makeKarmadaControllerManagerDeployment() *appsv1.Dep Command: []string{ "/bin/karmada-controller-manager", "--kubeconfig=/etc/kubeconfig", - "--bind-address=0.0.0.0", "--metrics-bind-address=:8080", + "--health-probe-bind-address=0.0.0.0:10357", "--cluster-status-update-frequency=10s", - "--secure-port=10357", fmt.Sprintf("--leader-elect-resource-namespace=%s", i.Namespace), "--v=4", }, diff --git a/pkg/karmadactl/cmdinit/utils/examples.go b/pkg/karmadactl/cmdinit/utils/examples.go index 3dec2cb6d1b7..b9ccfda5c906 100644 --- a/pkg/karmadactl/cmdinit/utils/examples.go +++ b/pkg/karmadactl/cmdinit/utils/examples.go @@ -140,6 +140,8 @@ spec: - /bin/karmada-scheduler-estimator - --kubeconfig=/etc/{{member_cluster_name}}-kubeconfig - --cluster-name={{member_cluster_name}} + - --metrics-bind-address=0.0.0.0:10351 + - --health-probe-bind-address=0.0.0.0:10351 volumeMounts: - name: member-kubeconfig subPath: {{member_cluster_name}}-kubeconfig diff --git a/pkg/karmadactl/create/create.go b/pkg/karmadactl/create/create.go new file mode 100644 index 000000000000..7f5a1213ff0d --- /dev/null +++ b/pkg/karmadactl/create/create.go @@ -0,0 +1,53 @@ +/* +Copyright 2024 The Karmada 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 create + +import ( + "fmt" + + "github.com/spf13/cobra" + "k8s.io/cli-runtime/pkg/genericiooptions" + kubectlcreate "k8s.io/kubectl/pkg/cmd/create" + "k8s.io/kubectl/pkg/util/templates" + + "github.com/karmada-io/karmada/pkg/karmadactl/util" +) + +var ( + createLong = templates.LongDesc(` + Create a resource from a file or from stdin. + + JSON and YAML formats are accepted.`) + + createExample = templates.Examples(` + # Create a pod using the data in pod.json + %[1]s create -f ./pod.json + + # Create a pod based on the JSON passed into stdin + cat pod.json | %[1]s create -f - + + # Edit the data in registry.yaml in JSON then create the resource using the edited data + %[1]s create -f registry.yaml --edit -o json`) +) + +// NewCmdCreate returns new initialized instance of create sub command +func NewCmdCreate(f util.Factory, parentCommnd string, ioStreams genericiooptions.IOStreams) *cobra.Command { + cmd := kubectlcreate.NewCmdCreate(f, ioStreams) + cmd.Long = fmt.Sprintf(createLong, parentCommnd) + cmd.Example = fmt.Sprintf(createExample, parentCommnd) + return cmd +} diff --git a/pkg/karmadactl/delete/delete.go b/pkg/karmadactl/delete/delete.go new file mode 100644 index 000000000000..1a48c1b49fd6 --- /dev/null +++ b/pkg/karmadactl/delete/delete.go @@ -0,0 +1,96 @@ +/* + Copyright 2024 The Karmada 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 delete + +import ( + "fmt" + + "github.com/spf13/cobra" + "k8s.io/cli-runtime/pkg/genericiooptions" + kubectldelete "k8s.io/kubectl/pkg/cmd/delete" + "k8s.io/kubectl/pkg/util/templates" + + "github.com/karmada-io/karmada/pkg/karmadactl/util" +) + +var ( + deleteLong = templates.LongDesc(` + Delete resources by file names, stdin, resources and names, or by resources and label selector. + + JSON and YAML formats are accepted. Only one type of argument may be specified: file names, + resources and names, or resources and label selector. + + Some resources, such as pods, support graceful deletion. These resources define a default period + before they are forcibly terminated (the grace period) but you may override that value with + the --grace-period flag, or pass --now to set a grace-period of 1. Because these resources often + represent entities in the cluster, deletion may not be acknowledged immediately. If the node + hosting a pod is down or cannot reach the API server, termination may take significantly longer + than the grace period. To force delete a resource, you must specify the --force flag. + Note: only a subset of resources support graceful deletion. In absence of the support, + the --grace-period flag is ignored. + + IMPORTANT: Force deleting pods does not wait for confirmation that the pod's processes have been + terminated, which can leave those processes running until the node detects the deletion and + completes graceful deletion. If your processes use shared storage or talk to a remote API and + depend on the name of the pod to identify themselves, force deleting those pods may result in + multiple processes running on different machines using the same identification which may lead + to data corruption or inconsistency. Only force delete pods when you are sure the pod is + terminated, or if your application can tolerate multiple copies of the same pod running at once. + Also, if you force delete pods, the scheduler may place new pods on those nodes before the node + has released those resources and causing those pods to be evicted immediately. + + Note that the delete command does NOT do resource version checks, so if someone submits an + update to a resource right when you submit a delete, their update will be lost along with the + rest of the resource. + + After a CustomResourceDefinition is deleted, invalidation of discovery cache may take up + to 6 hours. If you don't want to wait, you might want to run "[1]%s api-resources" to refresh + the discovery cache.`) + + deleteExample = templates.Examples(` + # Delete a propagationpolicy using the type and name specified in propagationpolicy.json + [1]%s delete -f ./propagationpolicy.json + + # Delete resources from a directory containing kustomization.yaml - e.g. dir/kustomization.yaml + [1]%s delete -k dir + + # Delete resources from all files that end with '.json' + [1]%s delete -f '*.json' + + # Delete a propagationpolicy based on the type and name in the JSON passed into stdin + cat propagationpolicy.json | [1]%s delete -f - + + # Delete propagationpolicies and services with same names "baz" and "foo" + [1]%s delete propagationpolicy,service baz foo + + # Delete propagationpolicies and services with label name=myLabel + [1]%s delete propagationpolicies,services -l name=myLabel + + # Delete a propagationpolicy with minimal delay + [1]%s delete propagationpolicy foo --now + + # Force delete a propagationpolicy on a dead node + [1]%s delete propagationpolicy foo --force + + # Delete all propagationpolicies + [1]%s delete propagationpolicies --all`) +) + +// NewCmdDelete returns new initialized instance of delete sub command +func NewCmdDelete(f util.Factory, parentCommnd string, ioStreams genericiooptions.IOStreams) *cobra.Command { + cmd := kubectldelete.NewCmdDelete(f, ioStreams) + cmd.Long = fmt.Sprintf(deleteLong, parentCommnd) + cmd.Example = fmt.Sprintf(deleteExample, parentCommnd) + return cmd +} diff --git a/pkg/karmadactl/describe/describe.go b/pkg/karmadactl/describe/describe.go index 7b644af17faf..eefe9ab92c47 100644 --- a/pkg/karmadactl/describe/describe.go +++ b/pkg/karmadactl/describe/describe.go @@ -30,7 +30,7 @@ import ( var ( describeLong = templates.LongDesc(` - Show details of a specific resource or group of resources in a member cluster. + Show details of a specific resource or group of resources in Karmada control plane or a member cluster. Print a detailed description of the selected resources, including related resources such as events or controllers. You may select a single object by name, @@ -43,21 +43,24 @@ var ( prefixed with NAME_PREFIX.`) describeExample = templates.Examples(` + # Describe a deployment in Karmada control plane + %[1]s describe deployment/nginx + # Describe a pod in cluster(member1) - %[1]s describe pods/nginx -C=member1 + %[1]s describe pods/nginx --operation-scope=members --cluster=member1 # Describe all pods in cluster(member1) - %[1]s describe pods -C=member1 + %[1]s describe pods --operation-scope=members --cluster=member1 # Describe a pod identified by type and name in "pod.json" in cluster(member1) - %[1]s describe -f pod.json -C=member1 + %[1]s describe -f pod.json --operation-scope=members --cluster=member1 # Describe pods by label name=myLabel in cluster(member1) - %[1]s describe po -l name=myLabel -C=member1 + %[1]s describe po -l name=myLabel --operation-scope=members --cluster=member1 # Describe all pods managed by the 'frontend' replication controller in cluster(member1) # (rc-created pods get the name of the rc as a prefix in the pod name) - %[1]s describe pods frontend -C=member1`) + %[1]s describe pods frontend --operation-scope=members --cluster=member1`) ) // NewCmdDescribe new describe command. @@ -66,8 +69,8 @@ func NewCmdDescribe(f util.Factory, parentCommand string, streams genericiooptio kubedescribeFlags := kubectldescribe.NewDescribeFlags(f, streams) cmd := &cobra.Command{ - Use: "describe (-f FILENAME | TYPE [NAME_PREFIX | -l label] | TYPE/NAME) (-C CLUSTER)", - Short: "Show details of a specific resource or group of resources in a cluster", + Use: "describe (-f FILENAME | TYPE [NAME_PREFIX | -l label] | TYPE/NAME) (--operation-scope=SCOPE --cluster=CLUSTER)", + Short: "Show details of a specific resource or group of resources in Karmada control plane or a member cluster", Long: fmt.Sprintf(describeLong, parentCommand), SilenceUsage: true, DisableFlagsInUseLine: true, @@ -76,6 +79,9 @@ func NewCmdDescribe(f util.Factory, parentCommand string, streams genericiooptio if err := o.Complete(f, args, kubedescribeFlags, parentCommand); err != nil { return err } + if err := o.Validate(); err != nil { + return err + } if err := o.Run(); err != nil { return err } @@ -90,8 +96,10 @@ func NewCmdDescribe(f util.Factory, parentCommand string, streams genericiooptio kubedescribeFlags.AddFlags(cmd) options.AddKubeConfigFlags(flags) + o.OperationScope = options.KarmadaControlPlane + flags.Var(&o.OperationScope, "operation-scope", "Used to control the operation scope of the command. The optional values are karmada and members. Defaults to karmada.") flags.StringVarP(options.DefaultConfigFlags.Namespace, "namespace", "n", *options.DefaultConfigFlags.Namespace, "If present, the namespace scope for this CLI request") - flags.StringVarP(&o.Cluster, "cluster", "C", "", "Specify a member cluster") + flags.StringVarP(&o.Cluster, "cluster", "C", "", "Used to specify a target member cluster and only takes effect when the command's operation scope is members, for example: --operation-scope=members --cluster=member1") return cmd } @@ -101,23 +109,39 @@ type CommandDescribeOptions struct { // flags specific to describe KubectlDescribeOptions *kubectldescribe.DescribeOptions Cluster string + OperationScope options.OperationScope } // Complete ensures that options are valid and marshals them if necessary func (o *CommandDescribeOptions) Complete(f util.Factory, args []string, describeFlag *kubectldescribe.DescribeFlags, parentCommand string) error { - if len(o.Cluster) == 0 { - return fmt.Errorf("must specify a cluster") + if o.OperationScope == options.KarmadaControlPlane { + describeFlag.Factory = f + } + if o.OperationScope == options.Members && len(o.Cluster) != 0 { + memberFactory, err := f.FactoryForMemberCluster(o.Cluster) + if err != nil { + return err + } + describeFlag.Factory = memberFactory } - memberFactory, err := f.FactoryForMemberCluster(o.Cluster) + var err error + o.KubectlDescribeOptions, err = describeFlag.ToOptions(parentCommand, args) if err != nil { return err } - describeFlag.Factory = memberFactory - o.KubectlDescribeOptions, err = describeFlag.ToOptions(parentCommand, args) + return nil +} + +// Validate checks if the parameters are valid +func (o *CommandDescribeOptions) Validate() error { + err := options.VerifyOperationScopeFlags(o.OperationScope, options.KarmadaControlPlane, options.Members) if err != nil { return err } + if o.OperationScope == options.Members && len(o.Cluster) == 0 { + return fmt.Errorf("must specify a member cluster") + } return nil } diff --git a/pkg/karmadactl/edit/edit.go b/pkg/karmadactl/edit/edit.go new file mode 100644 index 000000000000..e90828f1f1a4 --- /dev/null +++ b/pkg/karmadactl/edit/edit.go @@ -0,0 +1,54 @@ +/* +Copyright 2024 The Karmada 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 edit + +import ( + "fmt" + + "github.com/spf13/cobra" + "k8s.io/cli-runtime/pkg/genericiooptions" + kubectledit "k8s.io/kubectl/pkg/cmd/edit" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/templates" + + "github.com/karmada-io/karmada/pkg/karmadactl/util" +) + +var ( + editExample = templates.Examples(i18n.T(` + # Edit the service named 'registry' + %[1]s edit svc/registry + + # Use an alternative editor + KUBE_EDITOR="nano" %[1]s edit svc/registry + + # Edit the job 'myjob' in JSON using the v1 API format + %[1]s edit job.v1.batch/myjob -o json + + # Edit the deployment 'mydeployment' in YAML and save the modified config in its annotation + %[1]s edit deployment/mydeployment -o yaml --save-config + + # Edit the 'status' subresource for the 'mydeployment' deployment + %[1]s edit deployment mydeployment --subresource='status'`)) +) + +// NewCmdEdit returns new initialized instance of edit sub command +func NewCmdEdit(f util.Factory, parentCommand string, ioStreams genericiooptions.IOStreams) *cobra.Command { + cmd := kubectledit.NewCmdEdit(f, ioStreams) + cmd.Example = fmt.Sprintf(editExample, parentCommand) + return cmd +} diff --git a/pkg/karmadactl/exec/exec.go b/pkg/karmadactl/exec/exec.go index 663478d5d8f6..0df1be5d62d6 100644 --- a/pkg/karmadactl/exec/exec.go +++ b/pkg/karmadactl/exec/exec.go @@ -36,27 +36,30 @@ const ( var ( execLong = templates.LongDesc(` - Execute a command in a container in a cluster.`) + Execute a command in a container.`) execExample = templates.Examples(` + # Get output from running the 'date' command from pod mypod, using the first container by default + %[1]s exec mypod -- date + # Get output from running the 'date' command from pod mypod, using the first container by default in cluster(member1) - %[1]s exec mypod -C=member1 -- date + %[1]s exec mypod --operation-scope=members --cluster=member1 -- date # Get output from running the 'date' command in ruby-container from pod mypod in cluster(member1) - %[1]s exec mypod -c ruby-container -C=member1 -- date + %[1]s exec mypod -c ruby-container --operation-scope=members --cluster=member1 -- date # Get output from running the 'date' command in ruby-container from pod mypod in cluster(member1) - %[1]s exec mypod -c ruby-container -C=member1 -- date + %[1]s exec mypod -c ruby-container --operation-scope=members --cluster=member1 -- date - # Switch to raw terminal mode; sends stdin to 'bash' in ruby-container from pod mypod in cluster(member1) + # Switch to raw terminal mode; sends stdin to 'bash' in ruby-container from pod mypod # and sends stdout/stderr from 'bash' back to the client - %[1]s exec mypod -c ruby-container -C=member1 -i -t -- bash -il + %[1]s exec mypod -c ruby-container -i -t -- bash -il # Get output from running 'date' command from the first pod of the deployment mydeployment, using the first container by default in cluster(member1) - %[1]s exec deploy/mydeployment -C=member1 -- date + %[1]s exec deploy/mydeployment --operation-scope=members --cluster=member1 -- date # Get output from running 'date' command from the first pod of the service myservice, using the first container by default in cluster(member1) - %[1]s exec svc/myservice -C=member1 -- date`) + %[1]s exec svc/myservice --operation-scope=members --cluster=member1 -- date`) ) // NewCmdExec new exec command. @@ -95,6 +98,7 @@ func NewCmdExec(f util.Factory, parentCommand string, streams genericiooptions.I }, } + o.OperationScope = options.KarmadaControlPlane flags := cmd.Flags() options.AddKubeConfigFlags(flags) flags.StringVarP(options.DefaultConfigFlags.Namespace, "namespace", "n", *options.DefaultConfigFlags.Namespace, "If present, the namespace scope for this CLI request") @@ -105,7 +109,8 @@ func NewCmdExec(f util.Factory, parentCommand string, streams genericiooptions.I flags.BoolVarP(&o.KubectlExecOptions.Stdin, "stdin", "i", o.KubectlExecOptions.Stdin, "Pass stdin to the container") flags.BoolVarP(&o.KubectlExecOptions.TTY, "tty", "t", o.KubectlExecOptions.TTY, "Stdin is a TTY") flags.BoolVarP(&o.KubectlExecOptions.Quiet, "quiet", "q", o.KubectlExecOptions.Quiet, "Only print output from the remote session") - flags.StringVarP(&o.Cluster, "cluster", "C", "", "Specify a member cluster") + flags.Var(&o.OperationScope, "operation-scope", "Used to control the operation scope of the command. The optional values are karmada and members. Defaults to karmada.") + flags.StringVar(&o.Cluster, "cluster", "", "Used to specify a target member cluster and only takes effect when the command's operation scope is members, for example: --operation-scope=members --cluster=member1") return cmd } @@ -114,22 +119,31 @@ type CommandExecOptions struct { // flags specific to exec KubectlExecOptions *kubectlexec.ExecOptions Cluster string + OperationScope options.OperationScope } // Complete verifies command line arguments and loads data from the command environment func (o *CommandExecOptions) Complete(f util.Factory, cmd *cobra.Command, argsIn []string, argsLenAtDash int) error { - if len(o.Cluster) == 0 { - return fmt.Errorf("must specify a cluster") - } - memberFactory, err := f.FactoryForMemberCluster(o.Cluster) - if err != nil { - return err + var execFactory cmdutil.Factory = f + if o.OperationScope == options.Members && len(o.Cluster) != 0 { + memberFactory, err := f.FactoryForMemberCluster(o.Cluster) + if err != nil { + return err + } + execFactory = memberFactory } - return o.KubectlExecOptions.Complete(memberFactory, cmd, argsIn, argsLenAtDash) + return o.KubectlExecOptions.Complete(execFactory, cmd, argsIn, argsLenAtDash) } // Validate checks that the provided exec options are specified. func (o *CommandExecOptions) Validate() error { + err := options.VerifyOperationScopeFlags(o.OperationScope, options.KarmadaControlPlane, options.Members) + if err != nil { + return err + } + if o.OperationScope == options.Members && len(o.Cluster) == 0 { + return fmt.Errorf("must specify a member cluster") + } return o.KubectlExecOptions.Validate() } diff --git a/pkg/karmadactl/explain/explain.go b/pkg/karmadactl/explain/explain.go new file mode 100644 index 000000000000..7b5bbfbac58a --- /dev/null +++ b/pkg/karmadactl/explain/explain.go @@ -0,0 +1,130 @@ +/* +Copyright 2024 The Karmada 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 explain + +import ( + "fmt" + + "github.com/spf13/cobra" + "k8s.io/cli-runtime/pkg/genericiooptions" + kubectlexplain "k8s.io/kubectl/pkg/cmd/explain" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/util/templates" + + "github.com/karmada-io/karmada/pkg/karmadactl/options" + "github.com/karmada-io/karmada/pkg/karmadactl/util" +) + +var ( + explainLong = templates.LongDesc(` + Describe fields and structure of various resources in Karmada control plane or a member cluster. + + This command describes the fields associated with each supported API resource. + Fields are identified via a simple JSONPath identifier: + + .[.] + + Information about each field is retrieved from the server in OpenAPI format.`) + + explainExamples = templates.Examples(` + # Get the documentation of the resource and its fields in Karmada control plane + %[1]s explain propagationpolicies + + # Get all the fields in the resource in member cluster member1 + %[1]s explain pods --recursive --operation-scope=members --cluster=member1 + + # Get the explanation for resourcebindings in supported api versions in Karmada control plane + %[1]s explain resourcebindings --api-version=work.karmada.io/v1alpha1 + + # Get the documentation of a specific field of a resource in member cluster member1 + %[1]s explain pods.spec.containers --operation-scope=members --cluster=member1 + + # Get the documentation of resources in different format in Karmada control plane + %[1]s explain clusterpropagationpolicies --output=plaintext-openapiv2`) + plaintextTemplateName = "plaintext" +) + +// NewCmdExplain new explain command. +func NewCmdExplain(f util.Factory, parentCommand string, streams genericiooptions.IOStreams) *cobra.Command { + var o CommandExplainOptions + o.ExplainOptions = kubectlexplain.NewExplainOptions(parentCommand, streams) + + cmd := &cobra.Command{ + Use: "explain TYPE [--recursive=FALSE|TRUE] [--api-version=api-version-group] [--output=plaintext|plaintext-openapiv2] ", + DisableFlagsInUseLine: true, + Short: "Get documentation for a resource", + Long: fmt.Sprintf(explainLong, parentCommand), + Example: fmt.Sprintf(explainExamples, parentCommand), + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.Run()) + }, + } + + flags := cmd.Flags() + o.OperationScope = options.KarmadaControlPlane + flags.Var(&o.OperationScope, "operation-scope", "Used to control the operation scope of the command. The optional values are karmada and members. Defaults to karmada.") + flags.BoolVar(&o.Recursive, "recursive", o.Recursive, "When true, print the name of all the fields recursively. Otherwise, print the available fields with their description.") + flags.StringVar(&o.APIVersion, "api-version", o.APIVersion, "Use given api-version (group/version) of the resource.") + + // Only enable --output as a valid flag if the feature is enabled + flags.StringVar(&o.OutputFormat, "output", plaintextTemplateName, "Format in which to render the schema. Valid values are: (plaintext, plaintext-openapiv2).") + + flags.StringVarP(options.DefaultConfigFlags.Namespace, "namespace", "n", *options.DefaultConfigFlags.Namespace, "If present, the namespace scope for this CLI request") + flags.StringVar(&o.Cluster, "cluster", "", "Used to specify a target member cluster and only takes effect when the command's operation scope is member clusters, for example: --operation-scope=all --cluster=member1") + return cmd +} + +// CommandExplainOptions contains the input to the explain command. +type CommandExplainOptions struct { + // flags specific to explain + *kubectlexplain.ExplainOptions + Cluster string + OperationScope options.OperationScope +} + +// Complete ensures that options are valid and marshals them if necessary +func (o *CommandExplainOptions) Complete(f util.Factory, cmd *cobra.Command, args []string) error { + var explainFactory cmdutil.Factory = f + if o.OperationScope == options.Members && len(o.Cluster) != 0 { + memberFactory, err := f.FactoryForMemberCluster(o.Cluster) + if err != nil { + return err + } + explainFactory = memberFactory + } + + return o.ExplainOptions.Complete(explainFactory, cmd, args) +} + +// Validate checks that the provided explain options are specified +func (o *CommandExplainOptions) Validate() error { + err := options.VerifyOperationScopeFlags(o.OperationScope, options.KarmadaControlPlane, options.Members) + if err != nil { + return err + } + if o.OperationScope == options.Members && len(o.Cluster) == 0 { + return fmt.Errorf("must specify a member cluster") + } + return o.ExplainOptions.Validate() +} + +// Run executes the appropriate steps to print a model's documentation +func (o *CommandExplainOptions) Run() error { + return o.ExplainOptions.Run() +} diff --git a/pkg/karmadactl/get/get.go b/pkg/karmadactl/get/get.go index 4bf33c5511a0..edf66affd92d 100644 --- a/pkg/karmadactl/get/get.go +++ b/pkg/karmadactl/get/get.go @@ -61,6 +61,17 @@ const ( proxyURL = "/apis/cluster.karmada.io/v1alpha1/clusters/%s/proxy/" ) +type adoption string + +const ( + // managedByKarmada indicates that these are resources of member clusters and are managed by the Karmada control plane. + managedByKarmada adoption = "Y" + // notManagedByKaramda indicates that these are resources of member clusters and are not managed by the Karmada control plane. + notManagedByKaramda adoption = "N" + // notApplicable indicates that these are Karmada control plane resources. + notApplicable adoption = "-" +) + var ( podColumns = []metav1.TableColumnDefinition{ {Name: "CLUSTER", Type: "string", Format: "", Priority: 0}, @@ -69,7 +80,7 @@ var ( eventColumn = metav1.TableColumnDefinition{Name: "EVENT", Type: "string", Format: "", Priority: 0} getLong = templates.LongDesc(` - Display one or many resources in member clusters. + Display one or many resources in Karmada control plane and member clusters. Prints a table of the most important information about the specified resources. You can filter the list using a label selector and the --selector flag. If the @@ -80,28 +91,31 @@ var ( of the --template flag, you can filter the attributes of the fetched resources.`) getExample = templates.Examples(` - # List all pods in ps output format + # List all pods in Karmada control plane in ps output format %[1]s get pods - # List all pods in ps output format with more information (such as node name) + # List all pods in Karmada control plane in ps output format with more information (such as node name) %[1]s get pods -o wide # List all pods of member1 cluster in ps output format - %[1]s get pods -C member1 + %[1]s get pods --operation-scope=members --clusters=member1 - # List a single replicasets controller with specified NAME in ps output format + # List all pods of Karmada control plane and member1 cluster in ps output format + %[1]s get pods --operation-scope=all --clusters=member1 + + # List a single replicasets controller with specified NAME in Karmada control plane in ps output format %[1]s get replicasets nginx - # List deployments in JSON output format, in the "v1" version of the "apps" API group + # List deployments in Karmada control plane in JSON output format, in the "v1" version of the "apps" API group %[1]s get deployments.v1.apps -o json # Return only the phase value of the specified resource - %[1]s get -o template deployment/nginx -C member1 --template={{.spec.replicas}} + %[1]s get -o template deployment/nginx --template={{.spec.replicas}} - # List all replication controllers and services together in ps output format + # List all replication controllers and services together in Karmada control plane in ps output format %[1]s get rs,services - # List one or more resources by their type and names + # List one or more resources in Karmada control plane by their type and names %[1]s get rs/nginx-cb87b6d88 service/kubernetes`) ) @@ -110,7 +124,7 @@ func NewCmdGet(f util.Factory, parentCommand string, streams genericiooptions.IO o := NewCommandGetOptions(streams) cmd := &cobra.Command{ Use: "get [NAME | -l label | -n namespace]", - Short: "Display one or many resources", + Short: "Display one or many resources in Karmada control plane and member clusters.", Long: getLong, SilenceUsage: true, DisableFlagsInUseLine: true, @@ -135,9 +149,11 @@ func NewCmdGet(f util.Factory, parentCommand string, streams genericiooptions.IO o.PrintFlags.AddFlags(cmd) flags := cmd.Flags() options.AddKubeConfigFlags(flags) + o.OperationScope = options.KarmadaControlPlane + flags.Var(&o.OperationScope, "operation-scope", "Used to control the operation scope of the command. The optional values are karmada, members, and all. Defaults to karmada.") flags.StringVarP(options.DefaultConfigFlags.Namespace, "namespace", "n", *options.DefaultConfigFlags.Namespace, "If present, the namespace scope for this CLI request") flags.StringVarP(&o.LabelSelector, "labels", "l", "", "-l=label or -l label") - flags.StringSliceVarP(&o.Clusters, "clusters", "C", []string{}, "-C=member1,member2") + flags.StringSliceVarP(&o.Clusters, "clusters", "C", []string{}, "Used to specify target member clusters and only takes effect when the command's operation scope is members or all, for example: --operation-scope=all --clusters=member1,member2") flags.BoolVarP(&o.AllNamespaces, "all-namespaces", "A", o.AllNamespaces, "If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.") flags.BoolVar(&o.IgnoreNotFound, "ignore-not-found", o.IgnoreNotFound, "If the requested object does not exist the command will return exit code 0.") flags.BoolVarP(&o.Watch, "watch", "w", o.Watch, "After listing/getting the requested object, watch for changes. Uninitialized objects are excluded if no object name is provided.") @@ -149,7 +165,9 @@ func NewCmdGet(f util.Factory, parentCommand string, streams genericiooptions.IO // CommandGetOptions contains the input to the get command. type CommandGetOptions struct { - Clusters []string + Clusters []string + OperationScope options.OperationScope + targetMemberClusters []string PrintFlags *get.PrintFlags ToPrinter func(*meta.RESTMapping, *bool, bool, bool) (printers.ResourcePrinterFunc, error) @@ -196,11 +214,11 @@ func NewCommandGetOptions(streams genericiooptions.IOStreams) *CommandGetOptions // Complete takes the command arguments and infers any remaining options. func (g *CommandGetOptions) Complete(f util.Factory) error { newScheme := gclient.NewSchema() - namespace, _, err := f.ToRawKubeConfigLoader().Namespace() + + err := g.handleNamespaceScopeFlags(f) if err != nil { return err } - g.Namespace = namespace templateArg := "" if g.PrintFlags.TemplateFlags != nil && g.PrintFlags.TemplateFlags.TemplateArgument != nil { @@ -250,7 +268,7 @@ func (g *CommandGetOptions) Complete(f util.Factory) error { return err } g.karmadaClient = karmadaClient - return nil + return g.handleClusterScopeFlags() } // Validate checks the set of flags provided by the user. @@ -265,7 +283,11 @@ func (g *CommandGetOptions) Validate(cmd *cobra.Command) error { return fmt.Errorf("--output-watch-events option can only be used with --watch or --watch-only") } - if len(g.Clusters) > 0 { + if err := options.VerifyOperationScopeFlags(g.OperationScope); err != nil { + return err + } + + if options.ContainMembersScope(g.OperationScope) && len(g.Clusters) > 0 { clusters, err := g.karmadaClient.ClusterV1alpha1().Clusters().List(context.TODO(), metav1.ListOptions{}) if err != nil { return err @@ -275,10 +297,39 @@ func (g *CommandGetOptions) Validate(cmd *cobra.Command) error { return nil } +func (g *CommandGetOptions) handleClusterScopeFlags() error { + var err error + switch g.OperationScope { + case options.KarmadaControlPlane: + g.targetMemberClusters = []string{} + case options.Members, options.All: + if len(g.Clusters) == 0 { + g.targetMemberClusters, err = LoadRegisteredClusters(g.karmadaClient) + return err + } + g.targetMemberClusters = g.Clusters + return nil + } + return nil +} + +func (g *CommandGetOptions) handleNamespaceScopeFlags(f util.Factory) error { + var err error + g.Namespace, g.ExplicitNamespace, err = f.ToRawKubeConfigLoader().Namespace() + if err != nil { + return err + } + if g.AllNamespaces { + g.ExplicitNamespace = false + } + return nil +} + // Obj cluster info type Obj struct { - Cluster string - Info *resource.Info + Cluster string + IsControlPlane bool + Info *resource.Info } // WatchObj is a obj that is watched @@ -296,35 +347,29 @@ func (g *CommandGetOptions) Run(f util.Factory, cmd *cobra.Command, args []strin var watchObjs []WatchObj var allErrs []error - if g.AllNamespaces { - g.ExplicitNamespace = false - } - outputOption := cmd.Flags().Lookup("output").Value.String() if strings.Contains(outputOption, "custom-columns") || outputOption == "yaml" || strings.Contains(outputOption, "json") { g.ServerPrint = false } - if len(g.Clusters) == 0 { - clusterList, err := g.karmadaClient.ClusterV1alpha1().Clusters().List(context.TODO(), metav1.ListOptions{}) - if err != nil { - return fmt.Errorf("failed to list all member clusters in control plane, err: %w", err) - } - - for i := range clusterList.Items { - g.Clusters = append(g.Clusters, clusterList.Items[i].Name) - } + if options.ContainKarmadaScope(g.OperationScope) { + g.getObjInfo(&mux, f, "Karmada", true, &objs, &watchObjs, &allErrs, args) } - wg.Add(len(g.Clusters)) - for idx := range g.Clusters { - memberFactory, err := f.FactoryForMemberCluster(g.Clusters[idx]) - if err != nil { - return err + if len(g.targetMemberClusters) != 0 { + wg.Add(len(g.targetMemberClusters)) + for idx := range g.targetMemberClusters { + memberFactory, err := f.FactoryForMemberCluster(g.targetMemberClusters[idx]) + if err != nil { + return err + } + go func() { + g.getObjInfo(&mux, memberFactory, g.targetMemberClusters[idx], false, &objs, &watchObjs, &allErrs, args) + wg.Done() + }() } - go g.getObjInfo(&wg, &mux, memberFactory, g.Clusters[idx], &objs, &watchObjs, &allErrs, args) + wg.Wait() } - wg.Wait() if g.Watch || g.WatchOnly { return g.watch(watchObjs) @@ -428,12 +473,17 @@ func (g *CommandGetOptions) printObjs(objs []Obj, allErrs *[]error, _ []string) // printIfNotFindResource is sure we output something if we wrote no output, and had no errors, and are not ignoring NotFound func (g *CommandGetOptions) printIfNotFindResource(written int, allErrs *[]error, allResourcesNamespaced bool) { - if written == 0 && !g.IgnoreNotFound && len(*allErrs) == 0 { - if allResourcesNamespaced { - fmt.Fprintf(g.ErrOut, "No resources found in %s namespace.\n", *options.DefaultConfigFlags.Namespace) - } else { - fmt.Fprintln(g.ErrOut, "No resources found") - } + if written != 0 || g.IgnoreNotFound || len(*allErrs) != 0 { + return + } + if !options.ContainKarmadaScope(g.OperationScope) && len(g.targetMemberClusters) == 0 { + fmt.Fprintln(g.ErrOut, "No member Clusters found in Karmada control plane") + return + } + if allResourcesNamespaced { + fmt.Fprintf(g.ErrOut, "No resources found in %s namespace.\n", g.Namespace) + } else { + fmt.Fprintln(g.ErrOut, "No resources found") } } @@ -446,23 +496,24 @@ func (g *CommandGetOptions) checkPrintWithNamespace(mapping *meta.RESTMapping) b } // getObjInfo get obj info in member cluster -func (g *CommandGetOptions) getObjInfo(wg *sync.WaitGroup, mux *sync.Mutex, f cmdutil.Factory, - cluster string, objs *[]Obj, watchObjs *[]WatchObj, allErrs *[]error, args []string, +func (g *CommandGetOptions) getObjInfo(mux *sync.Mutex, f cmdutil.Factory, + cluster string, isControlPlane bool, objs *[]Obj, watchObjs *[]WatchObj, allErrs *[]error, args []string, ) { - defer wg.Done() - restClient, err := f.RESTClient() if err != nil { *allErrs = append(*allErrs, err) return } - // check if it is authorized to proxy this member cluster - request := restClient.Get().RequestURI(fmt.Sprintf(proxyURL, cluster) + "api") - if _, err := request.DoRaw(context.TODO()); err != nil { - *allErrs = append(*allErrs, fmt.Errorf("cluster(%s) is inaccessible, please check authorization or network", cluster)) - return + if !isControlPlane { + // check if it is authorized to proxy this member cluster + request := restClient.Get().RequestURI(fmt.Sprintf(proxyURL, cluster) + "api") + if _, err := request.DoRaw(context.TODO()); err != nil { + *allErrs = append(*allErrs, fmt.Errorf("cluster(%s) is inaccessible, please check authorization or network", cluster)) + return + } } + r := f.NewBuilder(). Unstructured(). NamespaceParam(g.Namespace).DefaultNamespace().AllNamespaces(g.AllNamespaces). @@ -514,8 +565,9 @@ func (g *CommandGetOptions) getObjInfo(wg *sync.WaitGroup, mux *sync.Mutex, f cm var objInfo Obj for ix := range infos { objInfo = Obj{ - Cluster: cluster, - Info: infos[ix], + Cluster: cluster, + IsControlPlane: isControlPlane, + Info: infos[ix], } *objs = append(*objs, objInfo) } @@ -549,11 +601,15 @@ func (g *CommandGetOptions) reconstructionRow(objs []Obj, table *metav1.Table) ( continue } + if objs[ix].IsControlPlane { + table.Rows[rowIdx].Cells = append(table.Rows[rowIdx].Cells, notApplicable) + continue + } v, exist := unObj.GetLabels()[karmadautil.ManagedByKarmadaLabel] if exist && v == karmadautil.ManagedByKarmadaLabelValue { - table.Rows[rowIdx].Cells = append(table.Rows[rowIdx].Cells, "Y") + table.Rows[rowIdx].Cells = append(table.Rows[rowIdx].Cells, managedByKarmada) } else { - table.Rows[rowIdx].Cells = append(table.Rows[rowIdx].Cells, "N") + table.Rows[rowIdx].Cells = append(table.Rows[rowIdx].Cells, notManagedByKaramda) } } allTableRows = append(allTableRows, table.Rows...) @@ -954,3 +1010,17 @@ func (p *skipPrinter) PrintObj(obj runtime.Object, writer io.Writer) error { table.Rows = nil return p.delegate.PrintObj(table, writer) } + +// LoadRegisteredClusters gets a list of register clusters. +func LoadRegisteredClusters(clientSet karmadaclientset.Interface) ([]string, error) { + var clusters []string + clusterList, err := clientSet.ClusterV1alpha1().Clusters().List(context.TODO(), metav1.ListOptions{}) + if err != nil { + return nil, fmt.Errorf("failed to list all member clusters in control plane, err: %w", err) + } + + for i := range clusterList.Items { + clusters = append(clusters, clusterList.Items[i].Name) + } + return clusters, nil +} diff --git a/pkg/karmadactl/karmadactl.go b/pkg/karmadactl/karmadactl.go index 21c0bd534108..86a033406fbd 100644 --- a/pkg/karmadactl/karmadactl.go +++ b/pkg/karmadactl/karmadactl.go @@ -29,16 +29,24 @@ import ( "k8s.io/kubectl/pkg/util/templates" "github.com/karmada-io/karmada/pkg/karmadactl/addons" + "github.com/karmada-io/karmada/pkg/karmadactl/annotate" + "github.com/karmada-io/karmada/pkg/karmadactl/apiresources" "github.com/karmada-io/karmada/pkg/karmadactl/apply" + "github.com/karmada-io/karmada/pkg/karmadactl/attach" "github.com/karmada-io/karmada/pkg/karmadactl/cmdinit" "github.com/karmada-io/karmada/pkg/karmadactl/config" "github.com/karmada-io/karmada/pkg/karmadactl/cordon" + "github.com/karmada-io/karmada/pkg/karmadactl/create" "github.com/karmada-io/karmada/pkg/karmadactl/deinit" + karmadactldelete "github.com/karmada-io/karmada/pkg/karmadactl/delete" "github.com/karmada-io/karmada/pkg/karmadactl/describe" + "github.com/karmada-io/karmada/pkg/karmadactl/edit" "github.com/karmada-io/karmada/pkg/karmadactl/exec" + "github.com/karmada-io/karmada/pkg/karmadactl/explain" "github.com/karmada-io/karmada/pkg/karmadactl/get" "github.com/karmada-io/karmada/pkg/karmadactl/interpret" "github.com/karmada-io/karmada/pkg/karmadactl/join" + "github.com/karmada-io/karmada/pkg/karmadactl/label" "github.com/karmada-io/karmada/pkg/karmadactl/logs" "github.com/karmada-io/karmada/pkg/karmadactl/options" "github.com/karmada-io/karmada/pkg/karmadactl/promote" @@ -87,8 +95,12 @@ func NewKarmadaCtlCommand(cmdUse, parentCommand string) *cobra.Command { { Message: "Basic Commands:", Commands: []*cobra.Command{ + explain.NewCmdExplain(f, parentCommand, ioStreams), get.NewCmdGet(f, parentCommand, ioStreams), config.NewCmdConfig(parentCommand), + create.NewCmdCreate(f, parentCommand, ioStreams), + karmadactldelete.NewCmdDelete(f, parentCommand, ioStreams), + edit.NewCmdEdit(f, parentCommand, ioStreams), }, }, { @@ -114,6 +126,7 @@ func NewKarmadaCtlCommand(cmdUse, parentCommand string) *cobra.Command { { Message: "Troubleshooting and Debugging Commands:", Commands: []*cobra.Command{ + attach.NewCmdAttach(f, parentCommand, ioStreams), logs.NewCmdLogs(f, parentCommand, ioStreams), exec.NewCmdExec(f, parentCommand, ioStreams), describe.NewCmdDescribe(f, parentCommand, ioStreams), @@ -128,6 +141,20 @@ func NewKarmadaCtlCommand(cmdUse, parentCommand string) *cobra.Command { top.NewCmdTop(f, parentCommand, ioStreams), }, }, + { + Message: "Settings Commands:", + Commands: []*cobra.Command{ + label.NewCmdLabel(f, parentCommand, ioStreams), + annotate.NewCmdAnnotate(f, parentCommand, ioStreams), + }, + }, + { + Message: "Other Commands:", + Commands: []*cobra.Command{ + apiresources.NewCmdAPIResources(f, parentCommand, ioStreams), + apiresources.NewCmdAPIVersions(f, parentCommand, ioStreams), + }, + }, } groups.Add(rootCmd) diff --git a/pkg/karmadactl/label/label.go b/pkg/karmadactl/label/label.go new file mode 100644 index 000000000000..aa308bd25c56 --- /dev/null +++ b/pkg/karmadactl/label/label.go @@ -0,0 +1,54 @@ +/* +Copyright 2024 The Karmada 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 label + +import ( + "fmt" + + "github.com/spf13/cobra" + "k8s.io/cli-runtime/pkg/genericiooptions" + kubectllabel "k8s.io/kubectl/pkg/cmd/label" + "k8s.io/kubectl/pkg/util/templates" + + "github.com/karmada-io/karmada/pkg/karmadactl/util" +) + +var ( + labelExample = templates.Examples(` + # Update deployment 'foo' with the label 'resourcetemplate.karmada.io/deletion-protected' and the value 'Always' + [1]%s label deployment foo resourcetemplate.karmada.io/deletion-protected=Always + + # Update deployment 'foo' with the label 'resourcetemplate.karmada.io/deletion-protected' and the value '', overwriting any existing value + [1]%s label --overwrite deployment foo resourcetemplate.karmada.io/deletion-protected= + + # Update all deployment in the namespace + [1]%s label pp --all resourcetemplate.karmada.io/deletion-protected= + + # Update a deployment identified by the type and name in "deployment.json" + [1]%s label -f deployment.json resourcetemplate.karmada.io/deletion-protected= + + # Update deployment 'foo' only if the resource is unchanged from version 1 + [1]%s label deployment resourcetemplate.karmada.io/deletion-protected=Always --resource-version=1 + + # Update deployment 'foo' by removing a label named 'bar' if it exists + # Does not require the --overwrite flag + [1]%s label deployment foo resourcetemplate.karmada.io/deletion-protected-`) +) + +// NewCmdLabel returns new initialized instance of label sub command +func NewCmdLabel(f util.Factory, parentCommand string, ioStreams genericiooptions.IOStreams) *cobra.Command { + cmd := kubectllabel.NewCmdLabel(f, ioStreams) + cmd.Example = fmt.Sprintf(labelExample, parentCommand) + return cmd +} diff --git a/pkg/karmadactl/options/global.go b/pkg/karmadactl/options/global.go index e76c42cb8447..e24c26722e89 100644 --- a/pkg/karmadactl/options/global.go +++ b/pkg/karmadactl/options/global.go @@ -17,6 +17,7 @@ limitations under the License. package options import ( + "fmt" "time" "github.com/spf13/pflag" @@ -47,3 +48,66 @@ func AddKubeConfigFlags(flags *pflag.FlagSet) { flags.StringVar(DefaultConfigFlags.KubeConfig, "kubeconfig", *DefaultConfigFlags.KubeConfig, "Path to the kubeconfig file to use for CLI requests.") flags.StringVar(DefaultConfigFlags.Context, "karmada-context", *DefaultConfigFlags.Context, "The name of the kubeconfig context to use") } + +// OperationScope defines the operation scope of a command. +type OperationScope string + +// String returns the string value of OperationScope +func (o *OperationScope) String() string { + return string(*o) +} + +// Set value to OperationScope +func (o *OperationScope) Set(s string) error { + switch s { + case "": + return nil + case string(KarmadaControlPlane): + *o = KarmadaControlPlane + return nil + case string(Members): + *o = Members + return nil + case string(All): + *o = All + return nil + } + return fmt.Errorf("not support OperationScope: %s", s) +} + +// Type returns type of OperationScope +func (o *OperationScope) Type() string { + return "operationScope" +} + +const ( + // KarmadaControlPlane indicates the operation scope of a command is Karmada control plane. + KarmadaControlPlane OperationScope = "karmada" + // Members indicates the operation scope of a command is member clusters. + Members OperationScope = "members" + // All indicates the operation scope of a command contains Karmada control plane and member clusters. + All OperationScope = "all" +) + +// VerifyOperationScopeFlags verifies whether the given operationScope is valid. +func VerifyOperationScopeFlags(operationScope OperationScope, supportScope ...OperationScope) error { + if len(supportScope) == 0 { + supportScope = []OperationScope{KarmadaControlPlane, Members, All} + } + for _, scope := range supportScope { + if operationScope == scope { + return nil + } + } + return fmt.Errorf("not support operation scope: %s", operationScope) +} + +// ContainKarmadaScope returns true if the given operationScope contains Karmada control plane. +func ContainKarmadaScope(operationScope OperationScope) bool { + return operationScope == KarmadaControlPlane || operationScope == All +} + +// ContainMembersScope returns true if the given operationScope contains member clusters. +func ContainMembersScope(operationScope OperationScope) bool { + return operationScope == Members || operationScope == All +} diff --git a/pkg/karmadactl/top/metrics_printer.go b/pkg/karmadactl/top/metrics_printer.go index 6a9c9a50712a..d30f31bae8a5 100644 --- a/pkg/karmadactl/top/metrics_printer.go +++ b/pkg/karmadactl/top/metrics_printer.go @@ -42,6 +42,8 @@ var ( NamespaceColumn = "NAMESPACE" // PodColumn is the column name for pod. PodColumn = "POD" + // NodeColumns is the list of columns used in the top node command. + NodeColumns = []string{"NAME", "CLUSTER", "CPU(cores)", "CPU%", "MEMORY(bytes)", "MEMORY%"} ) // ResourceMetricsInfo contains the information of a resource metric. @@ -105,6 +107,52 @@ func (printer *CmdPrinter) PrintPodMetrics(metrics []metricsapi.PodMetrics, prin return nil } +// PrintNodeMetrics prints the given metrics to the given writer. +func (printer *CmdPrinter) PrintNodeMetrics(metrics []metricsapi.NodeMetrics, availableResources map[string]map[string]corev1.ResourceList, noHeaders bool, sortBy string) error { + if len(metrics) == 0 { + return nil + } + w := printers.GetNewTabWriter(printer.out) + defer w.Flush() + + sort.Sort(NewNodeMetricsSorter(metrics, sortBy)) + + if !noHeaders { + printColumnNames(w, NodeColumns) + } + var usage corev1.ResourceList + for _, m := range metrics { + m.Usage.DeepCopyInto(&usage) + cluster := m.Annotations[autoscalingv1alpha1.QuerySourceAnnotationKey] + printMetricsLine(w, &ResourceMetricsInfo{ + Name: m.Name, + Cluster: cluster, + Metrics: usage, + Available: availableResources[cluster][m.Name], + }) + delete(availableResources[cluster], m.Name) + } + + // print lines for nodes of which the metrics is unreachable. + for cluster, resourceMap := range availableResources { + for nodeName := range resourceMap { + printMissingMetricsNodeLine(w, cluster, nodeName) + } + } + return nil +} + +func printMissingMetricsNodeLine(out io.Writer, cluster, nodeName string) { + printValue(out, nodeName) + printValue(out, cluster) + unknownMetricsStatus := "" + for i := 0; i < len(MeasuredResources); i++ { + printValue(out, unknownMetricsStatus) + printValue(out, unknownMetricsStatus) + } + fmt.Fprint(out, "\n") +} + func printColumnNames(out io.Writer, names []string) { for _, name := range names { printValue(out, name) diff --git a/pkg/karmadactl/top/metrics_sorter.go b/pkg/karmadactl/top/metrics_sorter.go index aaf78b33cc5c..564f4081b8bc 100644 --- a/pkg/karmadactl/top/metrics_sorter.go +++ b/pkg/karmadactl/top/metrics_sorter.go @@ -76,3 +76,39 @@ func NewPodMetricsSorter(metrics []metricsapi.PodMetrics, withNamespace bool, so podMetrics: podMetrics, } } + +// NodeMetricsSorter sorts a list of NodeMetrics. +type NodeMetricsSorter struct { + metrics []metricsapi.NodeMetrics + sortBy string +} + +// Len returns the length of the NodeMetricsSorter. +func (n *NodeMetricsSorter) Len() int { + return len(n.metrics) +} + +// Swap swaps the place of two NodeMetrics. +func (n *NodeMetricsSorter) Swap(i, j int) { + n.metrics[i], n.metrics[j] = n.metrics[j], n.metrics[i] +} + +// Less compares two NodeMetrics and returns true if the first NodeMetrics should sort before the second. +func (n *NodeMetricsSorter) Less(i, j int) bool { + switch n.sortBy { + case "cpu": + return n.metrics[i].Usage.Cpu().MilliValue() > n.metrics[j].Usage.Cpu().MilliValue() + case "memory": + return n.metrics[i].Usage.Memory().Value() > n.metrics[j].Usage.Memory().Value() + default: + return n.metrics[i].Name < n.metrics[j].Name + } +} + +// NewNodeMetricsSorter returns a new NodeMetricsSorter, which can be used to sort a list of NodeMetrics. +func NewNodeMetricsSorter(metrics []metricsapi.NodeMetrics, sortBy string) *NodeMetricsSorter { + return &NodeMetricsSorter{ + metrics: metrics, + sortBy: sortBy, + } +} diff --git a/pkg/karmadactl/top/top.go b/pkg/karmadactl/top/top.go index 65d12b11fec8..235b81727f7c 100644 --- a/pkg/karmadactl/top/top.go +++ b/pkg/karmadactl/top/top.go @@ -62,6 +62,7 @@ func NewCmdTop(f util.Factory, parentCommand string, streams genericiooptions.IO // create subcommands cmd.AddCommand(NewCmdTopPod(f, parentCommand, nil, streams)) + cmd.AddCommand(NewCmdTopNode(f, parentCommand, nil, streams)) return cmd } diff --git a/pkg/karmadactl/top/top_node.go b/pkg/karmadactl/top/top_node.go new file mode 100644 index 000000000000..f1d71385b0b5 --- /dev/null +++ b/pkg/karmadactl/top/top_node.go @@ -0,0 +1,304 @@ +/* +Copyright 2024 The Karmada 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 top + +import ( + "context" + "errors" + "fmt" + "sync" + + "github.com/spf13/cobra" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + utilerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/genericiooptions" + "k8s.io/client-go/kubernetes" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/util/completion" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/templates" + metricsapi "k8s.io/metrics/pkg/apis/metrics" + metricsV1beta1api "k8s.io/metrics/pkg/apis/metrics/v1beta1" + metricsclientset "k8s.io/metrics/pkg/client/clientset/versioned" + + autoscalingv1alpha1 "github.com/karmada-io/karmada/pkg/apis/autoscaling/v1alpha1" + karmadaclientset "github.com/karmada-io/karmada/pkg/generated/clientset/versioned" + "github.com/karmada-io/karmada/pkg/karmadactl/util" +) + +// NodeOptions contains all the options for running the top-node cli command. +type NodeOptions struct { + Clusters []string + ResourceName string + Selector string + SortBy string + NoHeaders bool + UseProtocolBuffers bool + ShowCapacity bool + + Printer *CmdPrinter + karmadaClient karmadaclientset.Interface + + metrics *metricsapi.NodeMetricsList + availableResources map[string]map[string]corev1.ResourceList + + lock sync.Mutex + errs []error + + genericiooptions.IOStreams +} + +var ( + topNodeLong = templates.LongDesc(i18n.T(` + Display resource (CPU/memory) usage of nodes in member clusters. + + The top-node command allows you to see the resource consumption of nodes.`)) + + topNodeExample = templates.Examples(i18n.T(` + # Show metrics for all nodes in the default namespace + %[1]s top node + + # Show metrics for all nodes in the default namespace in member1 cluster + %[1]s top node --clusters=member1 + + # Show metrics for all nodes in the default namespace in member1 and member2 cluster + %[1]s top node --clusters=member1,member2 + + # Show metrics for all nodes in the given namespace + %[1]s top node --namespace=NAMESPACE + + # Show metrics for the nodes defined by label name=myLabel + %[1]s top node -l name=myLabel`)) +) + +// NewCmdTopNode implements the top node command. +func NewCmdTopNode(f util.Factory, parentCommand string, o *NodeOptions, streams genericclioptions.IOStreams) *cobra.Command { + if o == nil { + o = &NodeOptions{ + IOStreams: streams, + UseProtocolBuffers: true, + } + } + + cmd := &cobra.Command{ + Use: "node [NAME | -l label]", + DisableFlagsInUseLine: true, + Short: i18n.T("Display resource (CPU/memory) usage of nodes"), + Long: topNodeLong, + Example: fmt.Sprintf(topNodeExample, parentCommand), + ValidArgsFunction: completion.ResourceNameCompletionFunc(f, "node"), + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.RunTopNode(f)) + }, + Aliases: []string{"nodes", "no"}, + } + cmdutil.AddLabelSelectorFlagVar(cmd, &o.Selector) + cmd.Flags().StringVar(&o.SortBy, "sort-by", o.SortBy, "If non-empty, sort nodes list using specified field. The field can be either 'cpu' or 'memory'.") + cmd.Flags().StringSliceVar(&o.Clusters, "clusters", []string{}, "Used to specify target member clusters, for example: --clusters=member1,member2") + cmd.Flags().BoolVar(&o.NoHeaders, "no-headers", o.NoHeaders, "If present, print output without headers") + cmd.Flags().BoolVar(&o.UseProtocolBuffers, "use-protocol-buffers", o.UseProtocolBuffers, "Enables using protocol-buffers to access Metrics API.") + cmd.Flags().BoolVar(&o.ShowCapacity, "show-capacity", o.ShowCapacity, "Print node resources based on Capacity instead of Allocatable(default) of the nodes.") + + return cmd +} + +// Complete completes all the required options. +func (o *NodeOptions) Complete(f util.Factory, cmd *cobra.Command, args []string) error { + if len(args) == 1 { + o.ResourceName = args[0] + } else if len(args) > 1 { + return cmdutil.UsageErrorf(cmd, "%s", cmd.Use) + } + + o.Printer = NewTopCmdPrinter(o.Out) + o.lock = sync.Mutex{} + o.errs = make([]error, 0) + + karmadaClient, err := f.KarmadaClientSet() + if err != nil { + return err + } + o.karmadaClient = karmadaClient + + o.metrics = &metricsapi.NodeMetricsList{} + o.availableResources = make(map[string]map[string]corev1.ResourceList) + return nil +} + +// Validate checks the validity of the options. +func (o *NodeOptions) Validate() error { + if len(o.SortBy) > 0 { + if o.SortBy != sortByCPU && o.SortBy != sortByMemory { + return errors.New("--sort-by accepts only cpu or memory") + } + } + if len(o.ResourceName) > 0 && len(o.Selector) > 0 { + return errors.New("only one of NAME or --selector can be provided") + } + + if len(o.Clusters) > 0 { + clusters, err := o.karmadaClient.ClusterV1alpha1().Clusters().List(context.TODO(), metav1.ListOptions{}) + if err != nil { + return err + } + return util.VerifyClustersExist(o.Clusters, clusters) + } + + return nil +} + +// RunTopNode runs the top node command. +func (o *NodeOptions) RunTopNode(f util.Factory) error { + var err error + var wg sync.WaitGroup + + selector := labels.Everything() + if len(o.Selector) > 0 { + selector, err = labels.Parse(o.Selector) + if err != nil { + return err + } + } + + o.Clusters, err = GenClusterList(o.karmadaClient, o.Clusters) + if err != nil { + return err + } + + wg.Add(len(o.Clusters)) + for _, cluster := range o.Clusters { + go func(f util.Factory, cluster string, selector labels.Selector) { + defer wg.Done() + o.runTopNodePerCluster(f, cluster, selector) + }(f, cluster, selector) + } + wg.Wait() + + if len(o.metrics.Items) == 0 && len(o.errs) == 0 { + // if we had no errors, be sure we output something. + fmt.Fprintln(o.ErrOut, "No resources found") + } + + err = o.Printer.PrintNodeMetrics(o.metrics.Items, o.availableResources, o.NoHeaders, o.SortBy) + if err != nil { + o.errs = append(o.errs, err) + } + + return utilerrors.NewAggregate(o.errs) +} + +func (o *NodeOptions) runTopNodePerCluster(f util.Factory, cluster string, selector labels.Selector) { + var err error + defer func() { + if err != nil { + o.lock.Lock() + o.errs = append(o.errs, fmt.Errorf("cluster(%s): %s", cluster, err)) + o.lock.Unlock() + } + }() + + clusterClient, metricsClient, err := GetMemberAndMetricsClientSet(f, cluster, o.UseProtocolBuffers) + if err != nil { + return + } + + metrics, err := getNodeMetricsFromMetricsAPI(metricsClient, o.ResourceName, selector) + if err != nil { + return + } + + if len(metrics.Items) == 0 { + err = fmt.Errorf("metrics not available yet") + return + } + + nodes, err := getNodes(clusterClient, selector, o.ResourceName) + if err != nil { + return + } + + o.lock.Lock() + for _, item := range metrics.Items { + if item.Annotations == nil { + item.Annotations = map[string]string{autoscalingv1alpha1.QuerySourceAnnotationKey: cluster} + } else { + item.Annotations[autoscalingv1alpha1.QuerySourceAnnotationKey] = cluster + } + o.metrics.Items = append(o.metrics.Items, item) + } + + resourceMap := make(map[string]corev1.ResourceList, len(nodes)) + for _, n := range nodes { + if !o.ShowCapacity { + resourceMap[n.Name] = n.Status.Allocatable + } else { + resourceMap[n.Name] = n.Status.Capacity + } + } + o.availableResources[cluster] = resourceMap + o.lock.Unlock() +} + +func getNodeMetricsFromMetricsAPI(metricsClient *metricsclientset.Clientset, resourceName string, selector labels.Selector) (*metricsapi.NodeMetricsList, error) { + var err error + versionedMetrics := &metricsV1beta1api.NodeMetricsList{} + mc := metricsClient.MetricsV1beta1() + nm := mc.NodeMetricses() + if resourceName != "" { + m, err := nm.Get(context.TODO(), resourceName, metav1.GetOptions{}) + if err != nil { + return nil, err + } + versionedMetrics.Items = []metricsV1beta1api.NodeMetrics{*m} + } else { + versionedMetrics, err = nm.List(context.TODO(), metav1.ListOptions{LabelSelector: selector.String()}) + if err != nil { + return nil, err + } + } + metrics := &metricsapi.NodeMetricsList{} + err = metricsV1beta1api.Convert_v1beta1_NodeMetricsList_To_metrics_NodeMetricsList(versionedMetrics, metrics, nil) + if err != nil { + return nil, err + } + return metrics, nil +} + +func getNodes(clusterClient *kubernetes.Clientset, selector labels.Selector, resourceName string) ([]corev1.Node, error) { + var nodes []corev1.Node + if len(resourceName) > 0 { + node, err := clusterClient.CoreV1().Nodes().Get(context.TODO(), resourceName, metav1.GetOptions{}) + if err != nil { + return nil, err + } + nodes = append(nodes, *node) + } else { + nodeList, err := clusterClient.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{ + LabelSelector: selector.String(), + }) + if err != nil { + return nil, err + } + nodes = append(nodes, nodeList.Items...) + } + return nodes, nil +} diff --git a/pkg/karmadactl/top/top_pods.go b/pkg/karmadactl/top/top_pods.go index f9501542abce..e53e5df954c7 100644 --- a/pkg/karmadactl/top/top_pods.go +++ b/pkg/karmadactl/top/top_pods.go @@ -84,6 +84,12 @@ var ( # Show metrics for all pods in the default namespace %[1]s top pod + # Show metrics for all pods in the default namespace in member1 cluster + %[1]s top pod --clusters=member1 + + # Show metrics for all pods in the default namespace in member1 and member2 cluster + %[1]s top pod --clusters=member1,member2 + # Show metrics for all pods in the given namespace %[1]s top pod --namespace=NAMESPACE diff --git a/pkg/registry/cluster/storage/aggregate.go b/pkg/registry/cluster/storage/aggregate.go index c6c5136e3426..1a41ca5b43f0 100644 --- a/pkg/registry/cluster/storage/aggregate.go +++ b/pkg/registry/cluster/storage/aggregate.go @@ -34,7 +34,6 @@ import ( "k8s.io/apiserver/pkg/authentication/user" "k8s.io/apiserver/pkg/endpoints/handlers/responsewriters" "k8s.io/apiserver/pkg/endpoints/request" - apirequest "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/registry/rest" restclient "k8s.io/client-go/rest" "k8s.io/klog/v2" @@ -150,7 +149,7 @@ func requestWithResourceNameHandlerFunc( klog.Errorf("failed to get impersonateToken for cluster %s: %v", cluster.Name, err) return } - statusCode, err := doClusterRequest(req.Method, requestURLStr(location.String(), proxyRequestInfo), transport, requester, impersonateToken) + statusCode, err := doClusterRequest(req.Method, requestURLStr(location, proxyRequestInfo), transport, requester, impersonateToken) if err != nil { klog.Errorf("failed to do request for cluster %s: %v", cluster.Name, err) return @@ -359,7 +358,7 @@ func doClusterRequest( } // requestURLStr returns the request resource url string. -func requestURLStr(urlStr string, requestInfo *apirequest.RequestInfo) string { +func requestURLStr(location *url.URL, requestInfo *request.RequestInfo) string { parts := []string{requestInfo.APIPrefix} if requestInfo.APIGroup != "" { parts = append(parts, requestInfo.APIGroup) @@ -378,7 +377,7 @@ func requestURLStr(urlStr string, requestInfo *apirequest.RequestInfo) string { requestInfo.Subresource != "exec" && requestInfo.Subresource != "log" { parts = append(parts, requestInfo.Subresource) } - return fmt.Sprintf("%s/%s", urlStr, strings.Join(parts, "/")) + return location.ResolveReference(&url.URL{Path: strings.Join(parts, "/")}).String() } func setRequestHeader(req *http.Request, userInfo user.Info, impersonateToken string) { diff --git a/pkg/registry/cluster/storage/aggregate_test.go b/pkg/registry/cluster/storage/aggregate_test.go new file mode 100644 index 000000000000..378df7b0ee46 --- /dev/null +++ b/pkg/registry/cluster/storage/aggregate_test.go @@ -0,0 +1,67 @@ +/* +Copyright 2022 The Karmada 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 storage + +import ( + "net/http" + "net/url" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/karmada-io/karmada/pkg/util/lifted" +) + +func TestRequestURL(t *testing.T) { + tests := []struct { + name string + urlString string + request http.Request + want string + }{ + { + name: "without slash in the end", + urlString: "https://0.0.0.0:6443", + request: http.Request{ + Method: "GET", + URL: &url.URL{ + Path: "/api/v1/namespaces/test/pods/", + }, + }, + want: "https://0.0.0.0:6443/api/v1/namespaces/test/pods", + }, + { + name: "with slash in the end", + urlString: "https://0.0.0.0:6443/", + request: http.Request{ + Method: "GET", + URL: &url.URL{ + Path: "/api/v1/namespaces/test/pods/", + }, + }, + want: "https://0.0.0.0:6443/api/v1/namespaces/test/pods", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + proxyRequestInfo := lifted.NewRequestInfo(&tt.request) + location, _ := url.Parse(tt.urlString) + requestURL := requestURLStr(location, proxyRequestInfo) + require.Equal(t, tt.want, requestURL) + }) + } +} diff --git a/pkg/registry/search/storage/proxy_test.go b/pkg/registry/search/storage/proxy_test.go new file mode 100644 index 000000000000..ec710063f710 --- /dev/null +++ b/pkg/registry/search/storage/proxy_test.go @@ -0,0 +1,103 @@ +/* +Copyright 2024 The Karmada 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 storage + +import ( + "context" + _ "net/http" + _ "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" + genericrequest "k8s.io/apiserver/pkg/endpoints/request" + _ "k8s.io/apiserver/pkg/registry/rest" + + searchapis "github.com/karmada-io/karmada/pkg/apis/search" + "github.com/karmada-io/karmada/pkg/search/proxy" +) + +func TestNewProxyingREST(t *testing.T) { + ctl := &proxy.Controller{} + r := NewProxyingREST(ctl) + assert.NotNil(t, r) + assert.Equal(t, ctl, r.ctl) +} + +func TestProxyingREST_New(t *testing.T) { + ctl := &proxy.Controller{} + r := NewProxyingREST(ctl) + obj := r.New() + assert.NotNil(t, obj) + _, ok := obj.(*searchapis.Proxying) + assert.True(t, ok) +} + +func TestProxyingREST_NamespaceScoped(t *testing.T) { + ctl := &proxy.Controller{} + r := NewProxyingREST(ctl) + assert.False(t, r.NamespaceScoped()) +} + +func TestProxyingREST_ConnectMethods(t *testing.T) { + ctl := &proxy.Controller{} + r := NewProxyingREST(ctl) + methods := r.ConnectMethods() + assert.Equal(t, proxyMethods, methods) +} + +func TestProxyingREST_NewConnectOptions(t *testing.T) { + ctl := &proxy.Controller{} + r := NewProxyingREST(ctl) + obj, ok, s := r.NewConnectOptions() + assert.Nil(t, obj) + assert.True(t, ok) + assert.Equal(t, "", s) +} + +func TestProxyingREST_Connect(t *testing.T) { + ctl := &proxy.Controller{} + r := NewProxyingREST(ctl) + + t.Run("Test missing RequestInfo in context", func(t *testing.T) { + ctx := context.Background() + _, err := r.Connect(ctx, "", nil, nil) + assert.NotNil(t, err) + assert.EqualError(t, err, "no RequestInfo found in the context") + }) + + t.Run("Test invalid RequestInfo parts", func(t *testing.T) { + ctx := genericrequest.WithRequestInfo(context.Background(), &genericrequest.RequestInfo{ + Parts: []string{"proxying"}, + }) + _, err := r.Connect(ctx, "", nil, nil) + assert.NotNil(t, err) + assert.EqualError(t, err, "invalid requestInfo parts: [proxying]") + }) +} + +func TestProxyingREST_Destroy(_ *testing.T) { + ctl := &proxy.Controller{} + r := NewProxyingREST(ctl) + r.Destroy() +} + +func TestProxyingREST_GetSingularName(t *testing.T) { + ctl := &proxy.Controller{} + r := NewProxyingREST(ctl) + name := r.GetSingularName() + assert.Equal(t, "proxying", name) +} diff --git a/pkg/resourceinterpreter/customized/declarative/luavm/lua_convert.go b/pkg/resourceinterpreter/customized/declarative/luavm/lua_convert.go index a24023e60fc8..36b085dca1a1 100644 --- a/pkg/resourceinterpreter/customized/declarative/luavm/lua_convert.go +++ b/pkg/resourceinterpreter/customized/declarative/luavm/lua_convert.go @@ -52,7 +52,7 @@ func ConvertLuaResultInto(luaResult *lua.LTable, obj interface{}, references ... // but if a field is empty struct, it will be encoded into empty slice format as '[]' (root cause is empty lua.LTable // can not be distinguished from empty slice or empty struct). // - // Supposing an object contains empty fileds, like following one has an empty slice field and an empty struct field. + // Supposing an object contains empty fields, like following one has an empty slice field and an empty struct field. // e.g: struct{one-filed: {}, another-field: []} // // When it is converted to lua.LTable, empty slice and empty struct are all converted to lua.LTable{}, which can't be distinguished. @@ -195,7 +195,7 @@ func traverseToFindEmptyField(root gjson.Result, fieldPath []string) (sets.Set[s // 3. when traverse to the field `spec.dd.ee`, we got an empty slice, but it also exists in `fieldOfEmptyStruct`, // so, it originally is struct too, we add it into `fieldOfEmptySliceToStruct` variable. // 4. when traverse to the field `spec.dd.ff`, we got an empty slice, but it not exists in either map variable, -// so, it orinally not exist, we can't judge whether it is struct, so we add it into `fieldOfEmptySliceToDelete` variable to remove it. +// so, it originally not exist, we can't judge whether it is struct, so we add it into `fieldOfEmptySliceToDelete` variable to remove it. // // So, finally, fieldOfEmptySliceToStruct={"spec.aa", "spec.dd.ee"}, fieldOfEmptySliceToDelete={"spec.dd.ff"} func traverseToFindEmptyFieldNeededModify(root gjson.Result, fieldPath, fieldPathWithArrayIndex []string, fieldOfEmptySlice, fieldOfEmptyStruct sets.Set[string]) (sets.Set[string], sets.Set[string]) { diff --git a/pkg/resourceinterpreter/default/native/aggregatestatus_test.go b/pkg/resourceinterpreter/default/native/aggregatestatus_test.go index af9b89605522..e4bb77d65e7c 100644 --- a/pkg/resourceinterpreter/default/native/aggregatestatus_test.go +++ b/pkg/resourceinterpreter/default/native/aggregatestatus_test.go @@ -29,6 +29,7 @@ import ( policyv1 "k8s.io/api/policy/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" "github.com/karmada-io/karmada/pkg/util/helper" @@ -1148,3 +1149,33 @@ func Test_aggregateHorizontalPodAutoscalerStatus(t *testing.T) { }) } } + +func Test_getAllDefaultAggregateStatusInterpreter(t *testing.T) { + expectedKinds := []schema.GroupVersionKind{ + {Group: "apps", Version: "v1", Kind: "Deployment"}, + {Group: "apps", Version: "v1", Kind: "StatefulSet"}, + {Group: "batch", Version: "v1", Kind: "Job"}, + {Group: "", Version: "v1", Kind: "Pod"}, + {Group: "", Version: "v1", Kind: "Service"}, + {Group: "networking.k8s.io", Version: "v1", Kind: "Ingress"}, + {Group: "batch", Version: "v1", Kind: "CronJob"}, + {Group: "apps", Version: "v1", Kind: "DaemonSet"}, + {Group: "", Version: "v1", Kind: "PersistentVolume"}, + {Group: "", Version: "v1", Kind: "PersistentVolumeClaim"}, + {Group: "policy", Version: "v1", Kind: "PodDisruptionBudget"}, + {Group: "autoscaling", Version: "v2", Kind: "HorizontalPodAutoscaler"}, + } + + got := getAllDefaultAggregateStatusInterpreter() + + if len(got) != len(expectedKinds) { + t.Errorf("getAllDefaultAggregateStatusInterpreter() length = %d, want %d", len(got), len(expectedKinds)) + } + + for _, key := range expectedKinds { + _, exists := got[key] + if !exists { + t.Errorf("getAllDefaultAggregateStatusInterpreter() missing key %v", key) + } + } +} diff --git a/pkg/resourceinterpreter/default/native/default_test.go b/pkg/resourceinterpreter/default/native/default_test.go new file mode 100644 index 000000000000..46a14c0a1539 --- /dev/null +++ b/pkg/resourceinterpreter/default/native/default_test.go @@ -0,0 +1,710 @@ +/* +Copyright 2024 The Karmada 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 native + +import ( + "testing" + + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + policyv1 "k8s.io/api/policy/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/klog/v2" + + configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1" + workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" + "github.com/karmada-io/karmada/pkg/util/helper" +) + +var e = NewDefaultInterpreter() + +func TestHookEnabled(t *testing.T) { + tests := []struct { + name string + kind schema.GroupVersionKind + operationType configv1alpha1.InterpreterOperation + want bool + }{ + { + name: "deployment with interpretreplica operation enabled", + kind: schema.GroupVersionKind{ + Group: "apps", + Version: "v1", + Kind: "Deployment", + }, + operationType: configv1alpha1.InterpreterOperationInterpretReplica, + want: true, + }, { + name: "statefulset with revisereplica operation enabled", + kind: schema.GroupVersionKind{ + Group: "apps", + Version: "v1", + Kind: "StatefulSet", + }, + operationType: configv1alpha1.InterpreterOperationReviseReplica, + want: true, + }, { + name: "persistentvolumeclaim with retain operation enabled", + kind: schema.GroupVersionKind{ + Group: "", + Version: "v1", + Kind: "PersistentVolumeClaim", + }, + operationType: configv1alpha1.InterpreterOperationRetain, + want: true, + }, { + name: "ingress with aggregatestatus operation enabled", + kind: schema.GroupVersionKind{ + Group: "networking.k8s.io", + Version: "v1", + Kind: "Ingress", + }, + operationType: configv1alpha1.InterpreterOperationAggregateStatus, + want: true, + }, { + name: "serviceimport with interpretdependency operation enabled", + kind: schema.GroupVersionKind{ + Group: "multicluster.x-k8s.io", + Version: "v1alpha1", + Kind: "ServiceImport", + }, + operationType: configv1alpha1.InterpreterOperationInterpretDependency, + want: true, + }, { + name: "deployment with interpretstatus operation enabled", + kind: schema.GroupVersionKind{ + Group: "apps", + Version: "v1", + Kind: "Deployment", + }, + operationType: configv1alpha1.InterpreterOperationInterpretStatus, + want: true, + }, { + name: "poddisruptionbudget with interprethealth operation enabled", + kind: schema.GroupVersionKind{ + Group: "policy", + Version: "v1", + Kind: "PodDisruptionBudget", + }, + operationType: configv1alpha1.InterpreterOperationInterpretHealth, + want: true, + }, { + name: "foot5zmh with prune operation enabled", + kind: schema.GroupVersionKind{ + Group: "example-stgzr.karmada.io", + Version: "v1alpha1", + Kind: "Foot5zmh", + }, + operationType: configv1alpha1.InterpreterOperationPrune, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := e.HookEnabled(tt.kind, tt.operationType) + if got != tt.want { + t.Errorf("HookEnabled() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestGetReplicas(t *testing.T) { + tests := []struct { + name string + object *unstructured.Unstructured + wantReplica int32 + wantRequirement *workv1alpha2.ReplicaRequirements + wantErr bool + }{ + { + name: "desired replica exists", + object: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "fake-deployment", + "namespace": "default", + "labels": map[string]interface{}{"app": "my-app"}, + }, + "spec": map[string]interface{}{ + "replicas": int64(2), + "selector": map[string]interface{}{ + "matchLabels": map[string]interface{}{"app": "my-app"}, + }, + "template": map[string]interface{}{ + "metadata": map[string]interface{}{ + "labels": map[string]interface{}{"app": "my-app"}, + }, + "spec": map[string]interface{}{ + "nodeSelector": map[string]interface{}{ + "foo": "foo1", + }, + "tolerations": []interface{}{ + map[string]interface{}{ + "key": "foo", + "operator": "Exists", + "effect": "NoSchedule", + }, + }, + "affinity": map[string]interface{}{ + "nodeAffinity": map[string]interface{}{ + "requiredDuringSchedulingIgnoredDuringExecution": map[string]interface{}{ + "nodeSelectorTerms": []interface{}{ + map[string]interface{}{ + "matchFields": []interface{}{ + map[string]interface{}{ + "key": "foo", + "operator": "Exists", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + wantReplica: 2, + wantRequirement: &workv1alpha2.ReplicaRequirements{ + NodeClaim: &workv1alpha2.NodeClaim{ + NodeSelector: map[string]string{ + "foo": "foo1", + }, + Tolerations: []corev1.Toleration{ + { + Key: "foo", + Operator: corev1.TolerationOpExists, + Effect: corev1.TaintEffectNoSchedule, + }, + }, + HardNodeAffinity: &corev1.NodeSelector{ + NodeSelectorTerms: []corev1.NodeSelectorTerm{ + { + MatchFields: []corev1.NodeSelectorRequirement{ + { + Key: "foo", + Operator: corev1.NodeSelectorOpExists, + }, + }, + }, + }, + }, + }, + }, + wantErr: false, + }, { + name: "cannot get desired replica of given kind and apiversion", + object: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Pod", + "metadata": map[string]interface{}{ + "name": "fake-pod", + "namespace": "default", + "labels": map[string]interface{}{"app": "my-app"}, + }, + }, + }, + wantReplica: 0, + wantRequirement: &workv1alpha2.ReplicaRequirements{}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotReplica, gotRequirement, err := e.GetReplicas(tt.object) + if (err != nil) != tt.wantErr { + t.Errorf("e.GetReplicas() error = %v, want %v", err, tt.wantErr) + } + assert.Equalf(t, tt.wantReplica, gotReplica, "e.GetReplicas(%v)", tt.object) + assert.Equalf(t, tt.wantRequirement, gotRequirement, "e.GetReplicas(%v)", tt.object) + }) + } +} + +func TestReviseReplica(t *testing.T) { + tests := []struct { + name string + object *unstructured.Unstructured + replica int64 + want *unstructured.Unstructured + wantErr bool + }{ + { + name: "revise deployment replica", + object: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "fake-deployment", + }, + "spec": map[string]interface{}{ + "replicas": int64(1), + }, + }, + }, + replica: 3, + want: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "fake-deployment", + }, + "spec": map[string]interface{}{ + "replicas": int64(3), + }, + }, + }, + wantErr: false, + }, + { + name: "cannot revise deployment replica of given kind and apiversion", + object: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Job", + "metadata": map[string]interface{}{ + "name": "fake-deployment", + }, + "spec": map[string]interface{}{ + "replicas": int64(1), + }, + }, + }, + replica: 3, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := e.ReviseReplica(tt.object, tt.replica) + if (err != nil) != tt.wantErr { + t.Errorf("e.ReviseReplica() error = %v, want %v", err, tt.wantErr) + } + assert.Equalf(t, tt.want, got, "e.ReviseReplica(%v,%v)", tt.object, tt.replica) + }) + } +} + +func TestRetain(t *testing.T) { + tests := []struct { + name string + desired *unstructured.Unstructured + observed *unstructured.Unstructured + want *unstructured.Unstructured + wantErr bool + }{ + { + name: "retain observed replica", + desired: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "nginx", + }, + "spec": map[string]interface{}{ + "replicas": int32(2), + }, + }, + }, + observed: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "nginx", + }, + "spec": map[string]interface{}{ + "replicas": int32(4), + }, + }, + }, + want: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "nginx", + }, + "spec": map[string]interface{}{ + "replicas": int32(2), + }, + }, + }, + wantErr: false, + }, + { + name: "cannot retain observed replica of given kind and apiversion", + desired: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Pod", + "metadata": map[string]interface{}{ + "name": "nginx", + }, + "spec": map[string]interface{}{ + "replicas": int32(2), + }, + }, + }, + observed: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Pod", + "metadata": map[string]interface{}{ + "name": "nginx", + }, + "spec": map[string]interface{}{ + "replicas": int32(4), + }, + }, + }, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := e.Retain(tt.desired, tt.observed) + if (err != nil) != tt.wantErr { + t.Errorf("e.Retain() error = %v, want %v", err, tt.wantErr) + } + assert.Equalf(t, tt.want, got, "e.Retain(%v,%v)", tt.desired, tt.observed) + }) + } +} + +func TestAggregateStatus(t *testing.T) { + statusMap := map[string]interface{}{ + "replicas": 1, + "readyReplicas": 1, + "updatedReplicas": 1, + "availableReplicas": 1, + "unavailableReplicas": 0, + } + raw, err := helper.BuildStatusRawExtension(statusMap) + if err != nil { + klog.Errorf("Failed to build raw, error: %v", err) + return + } + tests := []struct { + name string + object *unstructured.Unstructured + aggregatedStatusItems []workv1alpha2.AggregatedStatusItem + want *unstructured.Unstructured + wantErr bool + }{ + { + name: "update deployment status", + object: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + }, + }, + aggregatedStatusItems: []workv1alpha2.AggregatedStatusItem{ + { + ClusterName: "member1", + Status: raw, + Applied: true, + }, + { + ClusterName: "member2", + Status: raw, + Applied: true, + }, + }, + want: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "creationTimestamp": nil, + }, + "spec": map[string]interface{}{ + "selector": nil, + "strategy": map[string]interface{}{}, + "template": map[string]interface{}{ + "metadata": map[string]interface{}{ + "creationTimestamp": nil, + }, + "spec": map[string]interface{}{ + "containers": nil, + }, + }, + }, + "status": map[string]interface{}{ + "availableReplicas": int64(2), + "readyReplicas": int64(2), + "replicas": int64(2), + "updatedReplicas": int64(2), + }, + }, + }, + wantErr: false, + }, { + name: "cannot update deployment status for given kind and apiversion", + object: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Job", + }, + }, + aggregatedStatusItems: []workv1alpha2.AggregatedStatusItem{ + { + ClusterName: "member1", + Status: raw, + Applied: true, + }, + { + ClusterName: "member2", + Status: raw, + Applied: true, + }, + }, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := e.AggregateStatus(tt.object, tt.aggregatedStatusItems) + if (err != nil) != tt.wantErr { + t.Errorf("e.AggregateStatus() error = %v, want %v", err, tt.wantErr) + } + assert.Equalf(t, tt.want, got, "e.AggregateStatus(%v,%v)", tt.object, tt.aggregatedStatusItems) + }) + } +} + +func TestGetDependencies(t *testing.T) { + tests := []struct { + name string + object *unstructured.Unstructured + want []configv1alpha1.DependentObjectReference + wantErr bool + }{ + { + name: "deployment with dependencies 2", + object: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "fake-deployment", + "namespace": namespace, + }, + "spec": map[string]interface{}{ + "replicas": 3, + "template": map[string]interface{}{ + "spec": testPairs[1].podSpecsWithDependencies.Object, + }, + }, + }, + }, + want: []configv1alpha1.DependentObjectReference{ + { + APIVersion: "v1", + Kind: "ConfigMap", + Namespace: namespace, + Name: "initcontainer-envfrom-configmap", + }, + { + APIVersion: "v1", + Kind: "Secret", + Namespace: namespace, + Name: "test-secret", + }, + { + APIVersion: "v1", + Kind: "ServiceAccount", + Namespace: namespace, + Name: "test-serviceaccount", + }, + }, + wantErr: false, + }, + { + name: "can not get dependencies of given kind and apiversion", + object: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "CronJob", + "metadata": map[string]interface{}{ + "name": "fake-cronjob", + "namespace": namespace, + }, + "spec": map[string]interface{}{ + "replicas": 3, + "template": map[string]interface{}{ + "spec": testPairs[1].podSpecsWithDependencies.Object, + }, + }, + }, + }, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := e.GetDependencies(tt.object) + if (err != nil) != tt.wantErr { + t.Errorf("e.GetDependencies() error = %v, want %v", err, tt.wantErr) + } + assert.Equalf(t, tt.want, got, "e.GetDependencies(%v)", tt.object) + }) + } +} + +func TestReflectStatus(t *testing.T) { + currStatus := policyv1.PodDisruptionBudgetStatus{ + CurrentHealthy: 1, + DesiredHealthy: 1, + DisruptionsAllowed: 1, + ExpectedPods: 1, + } + wantRawExtension, err := helper.BuildStatusRawExtension(&currStatus) + if err != nil { + klog.Errorf("Failed to build wantRawExtension, error: %v", err) + return + } + testRawExtension, err := helper.BuildStatusRawExtension(map[string]interface{}{"key": "value"}) + if err != nil { + klog.Errorf("Failed to build testRawExtension, error: %v", err) + return + } + tests := []struct { + name string + object *unstructured.Unstructured + want *runtime.RawExtension + wantErr bool + }{ + { + name: "object have correct format status", + object: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "policy/v1", + "kind": "PodDisruptionBudget", + "status": map[string]interface{}{ + "currentHealthy": int64(1), + "desiredHealthy": int64(1), + "disruptionsAllowed": int64(1), + "expectedPods": int64(1), + }, + }, + }, + want: wantRawExtension, + wantErr: false, + }, + { + name: "missing build-in handler", + object: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "status": map[string]interface{}{"key": "value"}, + }, + }, + want: testRawExtension, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := e.ReflectStatus(tt.object) + if (err != nil) != tt.wantErr { + t.Errorf("e.ReflectStatus() error = %v, want %v", err, tt.wantErr) + } + assert.Equalf(t, tt.want, got, "e.ReflectStatus(%v)", tt.object) + }) + } +} + +func TestInterpretHealth(t *testing.T) { + tests := []struct { + name string + object *unstructured.Unstructured + want bool + wantErr bool + }{ + { + name: "deployment healthy", + object: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "fake-deployment", + "generation": 1, + }, + "spec": map[string]interface{}{ + "replicas": 3, + }, + "status": map[string]interface{}{ + "availableReplicas": 3, + "updatedReplicas": 3, + "observedGeneration": 1, + }, + }, + }, + want: true, + wantErr: false, + }, + { + name: "cannot get health state for given kind and apiversion", + object: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "policy/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "fake-deployment", + "generation": 1, + }, + "spec": map[string]interface{}{ + "replicas": 3, + }, + "status": map[string]interface{}{ + "availableReplicas": 3, + "updatedReplicas": 3, + "observedGeneration": 1, + }, + }, + }, + want: false, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := e.InterpretHealth(tt.object) + if (err != nil) != tt.wantErr { + t.Errorf("e.InterpretHealth() error = %v, want %v", err, tt.wantErr) + } + assert.Equalf(t, tt.want, got, "e.InterpretHealth(%v)", tt.object) + }) + } +} diff --git a/pkg/resourceinterpreter/default/native/dependencies_test.go b/pkg/resourceinterpreter/default/native/dependencies_test.go index f1635bf15615..d9d5d310f1d4 100644 --- a/pkg/resourceinterpreter/default/native/dependencies_test.go +++ b/pkg/resourceinterpreter/default/native/dependencies_test.go @@ -23,6 +23,7 @@ import ( discoveryv1 "k8s.io/api/discovery/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" mcsv1alpha1 "sigs.k8s.io/mcs-api/pkg/apis/v1alpha1" configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1" @@ -943,3 +944,90 @@ func Test_getServiceImportDependencies(t *testing.T) { }) } } + +func Test_getAllDefaultDependenciesInterpreter(t *testing.T) { + expectedKinds := []schema.GroupVersionKind{ + {Group: "apps", Version: "v1", Kind: "Deployment"}, + {Group: "batch", Version: "v1", Kind: "Job"}, + {Group: "batch", Version: "v1", Kind: "CronJob"}, + {Group: "", Version: "v1", Kind: "Pod"}, + {Group: "apps", Version: "v1", Kind: "DaemonSet"}, + {Group: "apps", Version: "v1", Kind: "StatefulSet"}, + {Group: "networking.k8s.io", Version: "v1", Kind: "Ingress"}, + {Group: "multicluster.x-k8s.io", Version: "v1alpha1", Kind: "ServiceImport"}, + } + + got := getAllDefaultDependenciesInterpreter() + + if len(got) != len(expectedKinds) { + t.Errorf("getAllDefaultDependenciesInterpreter() length = %d, want %d", len(got), len(expectedKinds)) + } + + for _, key := range expectedKinds { + _, exists := got[key] + if !exists { + t.Errorf("getAllDefaultDependenciesInterpreter() missing key %v", key) + } + } +} + +func Test_getIngressDependencies(t *testing.T) { + tests := []struct { + name string + object *unstructured.Unstructured + want []configv1alpha1.DependentObjectReference + wantErr bool + }{ + { + name: "ingress with dependencies 2", + object: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "networking.k8s.io/v1", + "kind": "Ingress", + "metadata": map[string]interface{}{ + "name": "test-ingress", + "namespace": namespace, + }, + "spec": map[string]interface{}{ + "tls": []interface{}{ + map[string]interface{}{ + "hosts": []interface{}{"foo1.*.bar.com"}, + "secretName": "cloud-secret", + }, + map[string]interface{}{ + "hosts": []interface{}{"foo2.*.bar.com"}, + "secretName": "test-secret", + }, + }, + }, + }, + }, + want: []configv1alpha1.DependentObjectReference{ + { + APIVersion: "v1", + Kind: "Secret", + Namespace: namespace, + Name: "cloud-secret", + }, + { + APIVersion: "v1", + Kind: "Secret", + Namespace: namespace, + Name: "test-secret", + }, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := getIngressDependencies(tt.object) + if (err != nil) != tt.wantErr { + t.Errorf("getIngressDependencies() err = %v, wantErr %v", err, tt.wantErr) + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("getIngressDependencies() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/resourceinterpreter/default/native/healthy_test.go b/pkg/resourceinterpreter/default/native/healthy_test.go index 35ad3b82eb3c..5fc26c1007c9 100644 --- a/pkg/resourceinterpreter/default/native/healthy_test.go +++ b/pkg/resourceinterpreter/default/native/healthy_test.go @@ -21,6 +21,7 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" ) func Test_interpretDeploymentHealth(t *testing.T) { @@ -702,6 +703,7 @@ func Test_interpretPodHealth(t *testing.T) { }) } } + func Test_interpretPodDisruptionBudgetHealth(t *testing.T) { tests := []struct { name string @@ -754,3 +756,30 @@ func Test_interpretPodDisruptionBudgetHealth(t *testing.T) { }) } } + +func Test_getAllDefaultHealthInterpreter(t *testing.T) { + expectedKinds := []schema.GroupVersionKind{ + {Group: "apps", Version: "v1", Kind: "Deployment"}, + {Group: "apps", Version: "v1", Kind: "StatefulSet"}, + {Group: "apps", Version: "v1", Kind: "ReplicaSet"}, + {Group: "apps", Version: "v1", Kind: "DaemonSet"}, + {Group: "", Version: "v1", Kind: "Service"}, + {Group: "networking.k8s.io", Version: "v1", Kind: "Ingress"}, + {Group: "", Version: "v1", Kind: "PersistentVolumeClaim"}, + {Group: "", Version: "v1", Kind: "Pod"}, + {Group: "policy", Version: "v1", Kind: "PodDisruptionBudget"}, + } + + got := getAllDefaultHealthInterpreter() + + if len(got) != len(expectedKinds) { + t.Errorf("getAllDefaultHealthInterpreter() length = %d, want %d", len(got), len(expectedKinds)) + } + + for _, key := range expectedKinds { + _, exists := got[key] + if !exists { + t.Errorf("getAllDefaultHealthInterpreter() missing key %v", key) + } + } +} diff --git a/pkg/resourceinterpreter/default/native/replica_test.go b/pkg/resourceinterpreter/default/native/replica_test.go new file mode 100644 index 000000000000..8ea6849e6f53 --- /dev/null +++ b/pkg/resourceinterpreter/default/native/replica_test.go @@ -0,0 +1,247 @@ +/* +Copyright 2024 The Karmada 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 native + +import ( + "testing" + + "github.com/stretchr/testify/assert" + appsv1 "k8s.io/api/apps/v1" + batchv1 "k8s.io/api/batch/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/klog/v2" + "k8s.io/utils/ptr" + + workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" + "github.com/karmada-io/karmada/pkg/util/helper" +) + +func Test_getAllDefaultReplicaInterpreter(t *testing.T) { + expectedKinds := []schema.GroupVersionKind{ + {Group: "apps", Version: "v1", Kind: "Deployment"}, + {Group: "apps", Version: "v1", Kind: "StatefulSet"}, + {Group: "batch", Version: "v1", Kind: "Job"}, + {Group: "", Version: "v1", Kind: "Pod"}, + } + + got := getAllDefaultReplicaInterpreter() + + if len(got) != len(expectedKinds) { + t.Errorf("getAllDefaultReplicaInterpreter() length = %d, want %d", len(got), len(expectedKinds)) + } + + for _, key := range expectedKinds { + _, exists := got[key] + if !exists { + t.Errorf("getAllDefaultReplicaInterpreter() missing key %v", key) + } + } +} + +func Test_deployReplica(t *testing.T) { + object := &appsv1.Deployment{ + Spec: appsv1.DeploymentSpec{ + Replicas: ptr.To[int32](2), + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + NodeSelector: map[string]string{"foo": "foo1"}, + Tolerations: []corev1.Toleration{{Key: "foo", Operator: corev1.TolerationOpExists, Effect: corev1.TaintEffectNoSchedule}}, + Affinity: &corev1.Affinity{ + NodeAffinity: &corev1.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ + NodeSelectorTerms: []corev1.NodeSelectorTerm{{ + MatchFields: []corev1.NodeSelectorRequirement{{Key: "foo", Operator: corev1.NodeSelectorOpExists}}, + }}, + }, + }, + }, + }, + }, + }, + } + + unstructuredObject, err := helper.ToUnstructured(object) + if err != nil { + klog.Errorf("Failed to transform object, error: %v", err) + return + } + gotReplica, gotRequirement, err := deployReplica(unstructuredObject) + + wantReplica := int32(2) + wantRequirement := &workv1alpha2.ReplicaRequirements{ + NodeClaim: &workv1alpha2.NodeClaim{ + NodeSelector: map[string]string{"foo": "foo1"}, + Tolerations: []corev1.Toleration{{Key: "foo", Operator: corev1.TolerationOpExists, Effect: corev1.TaintEffectNoSchedule}}, + HardNodeAffinity: &corev1.NodeSelector{ + NodeSelectorTerms: []corev1.NodeSelectorTerm{{ + MatchFields: []corev1.NodeSelectorRequirement{{Key: "foo", Operator: corev1.NodeSelectorOpExists}}, + }}, + }, + }, + } + + if err != nil { + t.Errorf("deployReplica() error = %v, want nil", err) + } + + assert.Equalf(t, wantReplica, gotReplica, "deployReplica(%v)", unstructuredObject) + assert.Equalf(t, wantRequirement, gotRequirement, "deployReplica(%v)", unstructuredObject) +} + +func Test_statefulSetReplica(t *testing.T) { + object := &appsv1.StatefulSet{ + Spec: appsv1.StatefulSetSpec{ + Replicas: ptr.To[int32](2), + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + NodeSelector: map[string]string{"foo": "foo1"}, + Tolerations: []corev1.Toleration{{Key: "foo", Operator: corev1.TolerationOpExists, Effect: corev1.TaintEffectNoSchedule}}, + Affinity: &corev1.Affinity{ + NodeAffinity: &corev1.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ + NodeSelectorTerms: []corev1.NodeSelectorTerm{{ + MatchFields: []corev1.NodeSelectorRequirement{{Key: "foo", Operator: corev1.NodeSelectorOpExists}}, + }}, + }, + }, + }, + }, + }, + }, + } + unstructuredObject, err := helper.ToUnstructured(object) + if err != nil { + klog.Errorf("Failed to transform object, error: %v", err) + return + } + gotReplica, gotRequirement, err := statefulSetReplica(unstructuredObject) + + wantReplica := int32(2) + wantRequirement := &workv1alpha2.ReplicaRequirements{ + NodeClaim: &workv1alpha2.NodeClaim{ + NodeSelector: map[string]string{"foo": "foo1"}, + Tolerations: []corev1.Toleration{{Key: "foo", Operator: corev1.TolerationOpExists, Effect: corev1.TaintEffectNoSchedule}}, + HardNodeAffinity: &corev1.NodeSelector{ + NodeSelectorTerms: []corev1.NodeSelectorTerm{{ + MatchFields: []corev1.NodeSelectorRequirement{{Key: "foo", Operator: corev1.NodeSelectorOpExists}}, + }}, + }, + }, + } + + if err != nil { + t.Errorf("statefulSetReplica() error = %v, want nil", err) + } + + assert.Equalf(t, wantReplica, gotReplica, "statefulSetReplica(%v)", unstructuredObject) + assert.Equalf(t, wantRequirement, gotRequirement, "statefulSetReplica(%v)", unstructuredObject) +} + +func Test_jobReplica(t *testing.T) { + object := &batchv1.Job{ + Spec: batchv1.JobSpec{ + Parallelism: ptr.To[int32](3), + Completions: ptr.To[int32](2), + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + NodeSelector: map[string]string{"foo": "foo1"}, + Tolerations: []corev1.Toleration{{Key: "foo", Operator: corev1.TolerationOpExists, Effect: corev1.TaintEffectNoSchedule}}, + Affinity: &corev1.Affinity{ + NodeAffinity: &corev1.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ + NodeSelectorTerms: []corev1.NodeSelectorTerm{{ + MatchFields: []corev1.NodeSelectorRequirement{{Key: "foo", Operator: corev1.NodeSelectorOpExists}}, + }}, + }, + }, + }, + }, + }, + }, + } + unstructuredObject, err := helper.ToUnstructured(object) + if err != nil { + klog.Errorf("Failed to transform object, error: %v", err) + return + } + gotReplica, gotRequirement, err := jobReplica(unstructuredObject) + + wantReplica := int32(2) + wantRequirement := &workv1alpha2.ReplicaRequirements{ + NodeClaim: &workv1alpha2.NodeClaim{ + NodeSelector: map[string]string{"foo": "foo1"}, + Tolerations: []corev1.Toleration{{Key: "foo", Operator: corev1.TolerationOpExists, Effect: corev1.TaintEffectNoSchedule}}, + HardNodeAffinity: &corev1.NodeSelector{ + NodeSelectorTerms: []corev1.NodeSelectorTerm{{ + MatchFields: []corev1.NodeSelectorRequirement{{Key: "foo", Operator: corev1.NodeSelectorOpExists}}, + }}, + }, + }, + } + + if err != nil { + t.Errorf("jobReplica() error = %v, want nil", err) + } + + assert.Equalf(t, wantReplica, gotReplica, "jobReplica(%v)", unstructuredObject) + assert.Equalf(t, wantRequirement, gotRequirement, "jobReplica(%v)", unstructuredObject) +} + +func Test_podReplica(t *testing.T) { + object := &corev1.Pod{ + Spec: corev1.PodSpec{ + NodeSelector: map[string]string{"foo": "foo1"}, + Tolerations: []corev1.Toleration{{Key: "foo", Operator: corev1.TolerationOpExists, Effect: corev1.TaintEffectNoSchedule}}, + Affinity: &corev1.Affinity{ + NodeAffinity: &corev1.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ + NodeSelectorTerms: []corev1.NodeSelectorTerm{{ + MatchFields: []corev1.NodeSelectorRequirement{{Key: "foo", Operator: corev1.NodeSelectorOpExists}}, + }}, + }, + }, + }, + }, + } + unstructuredObject, err := helper.ToUnstructured(object) + if err != nil { + klog.Errorf("Failed to transform object, error: %v", err) + return + } + gotReplica, gotRequirement, err := podReplica(unstructuredObject) + + wantReplica := int32(1) + wantRequirement := &workv1alpha2.ReplicaRequirements{ + NodeClaim: &workv1alpha2.NodeClaim{ + NodeSelector: map[string]string{"foo": "foo1"}, + Tolerations: []corev1.Toleration{{Key: "foo", Operator: corev1.TolerationOpExists, Effect: corev1.TaintEffectNoSchedule}}, + HardNodeAffinity: &corev1.NodeSelector{ + NodeSelectorTerms: []corev1.NodeSelectorTerm{{ + MatchFields: []corev1.NodeSelectorRequirement{{Key: "foo", Operator: corev1.NodeSelectorOpExists}}, + }}, + }, + }, + } + + if err != nil { + t.Errorf("podReplica() error = %v, want nil", err) + } + + assert.Equalf(t, wantReplica, gotReplica, "podReplica(%v)", unstructuredObject) + assert.Equalf(t, wantRequirement, gotRequirement, "podReplica(%v)", unstructuredObject) +} diff --git a/pkg/resourceinterpreter/default/native/retain_test.go b/pkg/resourceinterpreter/default/native/retain_test.go index fa6db7063a0f..e15b4cf74c28 100644 --- a/pkg/resourceinterpreter/default/native/retain_test.go +++ b/pkg/resourceinterpreter/default/native/retain_test.go @@ -24,6 +24,8 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/klog/v2" "github.com/karmada-io/karmada/pkg/util" "github.com/karmada-io/karmada/pkg/util/helper" @@ -31,81 +33,135 @@ import ( func Test_retainK8sWorkloadReplicas(t *testing.T) { desiredNum, observedNum := int32(2), int32(4) - observed, _ := helper.ToUnstructured(&appsv1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: "nginx", - }, - Spec: appsv1.DeploymentSpec{ - Replicas: &observedNum, - }, - }) - desired, _ := helper.ToUnstructured(&appsv1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: "nginx", - Labels: map[string]string{ - util.RetainReplicasLabel: util.RetainReplicasValue, - }, - }, - Spec: appsv1.DeploymentSpec{ - Replicas: &desiredNum, - }, - }) - want, _ := helper.ToUnstructured(&appsv1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: "nginx", - Labels: map[string]string{ - util.RetainReplicasLabel: util.RetainReplicasValue, - }, - }, - Spec: appsv1.DeploymentSpec{ - Replicas: &observedNum, - }, - }) - desired2, _ := helper.ToUnstructured(&appsv1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: "nginx", - }, - Spec: appsv1.DeploymentSpec{ - Replicas: &desiredNum, - }, - }) type args struct { - desired *unstructured.Unstructured - observed *unstructured.Unstructured + desired interface{} + observed interface{} } tests := []struct { name string args args - want *unstructured.Unstructured + want interface{} wantErr bool }{ { name: "deployment is control by hpa", args: args{ - desired: desired, - observed: observed, + desired: &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx", + Labels: map[string]string{ + util.RetainReplicasLabel: util.RetainReplicasValue, + }, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: &desiredNum, + }, + }, + observed: &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx", + }, + Spec: appsv1.DeploymentSpec{ + Replicas: &observedNum, + }, + }, + }, + want: &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx", + Labels: map[string]string{ + util.RetainReplicasLabel: util.RetainReplicasValue, + }, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: &observedNum, + }, }, - want: want, wantErr: false, }, { name: "deployment is not control by hpa", args: args{ - desired: desired2, - observed: observed, + desired: &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx", + }, + Spec: appsv1.DeploymentSpec{ + Replicas: &desiredNum, + }, + }, + observed: &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx", + }, + Spec: appsv1.DeploymentSpec{ + Replicas: &observedNum, + }, + }, + }, + want: &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx", + }, + Spec: appsv1.DeploymentSpec{ + Replicas: &desiredNum, + }, }, - want: desired2, wantErr: false, }, + { + name: "empty observed replicas", + args: args{ + desired: &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx", + Labels: map[string]string{ + util.RetainReplicasLabel: util.RetainReplicasValue, + }, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: &desiredNum, + }, + }, + observed: &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx", + }, + Spec: appsv1.DeploymentSpec{}, + }, + }, + want: nil, + wantErr: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := retainWorkloadReplicas(tt.args.desired, tt.args.observed) + unstructuredDesiredObj, err := helper.ToUnstructured(tt.args.desired) + if err != nil { + klog.Errorf("Failed to transform desired, error: %v", err) + return + } + + unstructuredObservedObj, err := helper.ToUnstructured(tt.args.observed) + if err != nil { + klog.Errorf("Failed to transform observed, error: %v", err) + return + } + got, err := retainWorkloadReplicas(unstructuredDesiredObj, unstructuredObservedObj) if (err != nil) != tt.wantErr { t.Errorf("retainWorkloadReplicas() error = %v, wantErr %v", err, tt.wantErr) return } - assert.Equalf(t, tt.want, got, "retainDeploymentFields(%v, %v)", tt.args.desired, tt.args.observed) + + unstructuredWantObj := (*unstructured.Unstructured)(nil) + if tt.want != nil { + unstructuredWantObj, err = helper.ToUnstructured(tt.want) + if err != nil { + klog.Errorf("Failed to transform want, error: %v", err) + return + } + } + assert.Equalf(t, unstructuredWantObj, got, "retainWorkloadReplicas(%v, %v)", unstructuredDesiredObj, unstructuredObservedObj) }) } } @@ -256,3 +312,407 @@ func Test_retainPersistentVolumeClaimFields(t *testing.T) { }) } } + +func Test_retainJobSelectorFields(t *testing.T) { + replicaNum := int32(2) + type args struct { + desired interface{} + observed interface{} + } + tests := []struct { + name string + args args + want interface{} + wantErr bool + }{ + { + name: "matchLabels and templateLabels exists", + args: args{ + desired: &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx", + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"app": "nginx_v1"}, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{"app": "nginx_v1"}, + }, + }, + Replicas: &replicaNum, + }, + }, + observed: &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx", + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"name": "nginx"}, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{"name": "nginx"}, + }, + }, + Replicas: &replicaNum, + }, + }, + }, + want: &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx", + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"name": "nginx"}, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{"name": "nginx"}, + }, + }, + Replicas: &replicaNum, + }, + }, + wantErr: false, + }, + { + name: "matchLabels does not exists", + args: args{ + desired: &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx", + }, + Spec: appsv1.DeploymentSpec{ + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{"app": "nginx_v1"}, + }, + }, + Replicas: &replicaNum, + }, + }, + observed: &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx", + }, + Spec: appsv1.DeploymentSpec{ + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{"name": "nginx"}, + }, + }, + Replicas: &replicaNum, + }, + }, + }, + want: &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx", + }, + Spec: appsv1.DeploymentSpec{ + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{"name": "nginx"}, + }, + }, + Replicas: &replicaNum, + }, + }, + wantErr: false, + }, + { + name: "templateLabels does not exists", + args: args{ + desired: &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx", + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"app": "nginx_v1"}, + }, + Replicas: &replicaNum, + }, + }, + observed: &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx", + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"name": "nginx"}, + }, + Replicas: &replicaNum, + }, + }, + }, + want: &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx", + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"name": "nginx"}, + }, + Replicas: &replicaNum, + }, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + unstructuredDesiredObj, err := helper.ToUnstructured(tt.args.desired) + if err != nil { + klog.Errorf("Failed to transform desired, error: %v", err) + return + } + unstructuredObservedObj, err := helper.ToUnstructured(tt.args.observed) + if err != nil { + klog.Errorf("Failed to transform observed, error: %v", err) + return + } + got, err := retainJobSelectorFields(unstructuredDesiredObj, unstructuredObservedObj) + if (err != nil) != tt.wantErr { + t.Errorf("retainJobSelectorFields() error = %v, wantErr %v", err, tt.wantErr) + return + } + unstructuredWantObj, err := helper.ToUnstructured(tt.want) + if err != nil { + klog.Errorf("Failed to transform want, error: %v", err) + return + } + assert.Equalf(t, unstructuredWantObj, got, "retainJobSelectorFields(%v, %v)", unstructuredDesiredObj, unstructuredObservedObj) + }) + } +} + +func Test_retainPodFields(t *testing.T) { + type args struct { + desired interface{} + observed interface{} + } + tests := []struct { + name string + args args + want interface{} + wantErr bool + }{ + { + name: "retain observed pod fields", + args: args{ + desired: &corev1.Pod{Spec: corev1.PodSpec{ + NodeName: "node2", + ServiceAccountName: "fake-desired-sa", + Volumes: []corev1.Volume{ + { + Name: "fake-desired-volume", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: "fake-desired-secret", + }, + }, + }, + }, + InitContainers: []corev1.Container{{ + Name: "test", + VolumeMounts: []corev1.VolumeMount{ + { + Name: "fake-desired-config", + ReadOnly: false, + MountPath: "/etc/etcd/desired", + }, + }, + }, { + Name: "test-3", + VolumeMounts: []corev1.VolumeMount{ + { + Name: "fake-desired-config-2", + ReadOnly: false, + MountPath: "/etc/etcd/desired2", + }, + }, + }}, + Containers: []corev1.Container{{ + Name: "test", + VolumeMounts: []corev1.VolumeMount{ + { + Name: "fake-desired-cert", + ReadOnly: true, + MountPath: "/etc/karmada/desired", + }, + }, + }, { + Name: "test-3", + VolumeMounts: []corev1.VolumeMount{ + { + Name: "fake-desired-cert-2", + ReadOnly: true, + MountPath: "/etc/karmada/desired2", + }, + }, + }}, + }}, + observed: &corev1.Pod{Spec: corev1.PodSpec{ + NodeName: "node1", + ServiceAccountName: "fake-observed-sa", + Volumes: []corev1.Volume{ + { + Name: "fake-observed-volume", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: "fake-observed-secret", + }, + }, + }, + }, + InitContainers: []corev1.Container{{ + Name: "test", + VolumeMounts: []corev1.VolumeMount{ + { + Name: "fake-observed-config", + ReadOnly: false, + MountPath: "/etc/etcd/observed", + }, + }, + }, { + Name: "test-2", + VolumeMounts: []corev1.VolumeMount{ + { + Name: "fake-observed-config-2", + ReadOnly: false, + MountPath: "/etc/etcd/observed2", + }, + }, + }}, + Containers: []corev1.Container{{ + Name: "test", + VolumeMounts: []corev1.VolumeMount{ + { + Name: "fake-observed-cert", + ReadOnly: true, + MountPath: "/etc/karmada/observed", + }, + }, + }, { + Name: "test-2", + VolumeMounts: []corev1.VolumeMount{ + { + Name: "fake-observed-cert-2", + ReadOnly: true, + MountPath: "/etc/karmada/observed2", + }, + }, + }}, + }}, + }, + want: &corev1.Pod{Spec: corev1.PodSpec{ + NodeName: "node1", + ServiceAccountName: "fake-observed-sa", + Volumes: []corev1.Volume{ + { + Name: "fake-observed-volume", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: "fake-observed-secret", + }, + }, + }, + }, + InitContainers: []corev1.Container{{ + Name: "test", + VolumeMounts: []corev1.VolumeMount{ + { + Name: "fake-observed-config", + ReadOnly: false, + MountPath: "/etc/etcd/observed", + }, + }, + }, { + Name: "test-3", + VolumeMounts: []corev1.VolumeMount{ + { + Name: "fake-desired-config-2", + ReadOnly: false, + MountPath: "/etc/etcd/desired2", + }, + }, + }}, + Containers: []corev1.Container{{ + Name: "test", + VolumeMounts: []corev1.VolumeMount{ + { + Name: "fake-observed-cert", + ReadOnly: true, + MountPath: "/etc/karmada/observed", + }, + }, + }, { + Name: "test-3", + VolumeMounts: []corev1.VolumeMount{ + { + Name: "fake-desired-cert-2", + ReadOnly: true, + MountPath: "/etc/karmada/desired2", + }, + }, + }}, + }}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + unstructuredDesiredObj, err := helper.ToUnstructured(tt.args.desired) + if err != nil { + klog.Errorf("Failed to transform desired, error: %v", err) + return + } + unstructuredObservedObj, err := helper.ToUnstructured(tt.args.observed) + if err != nil { + klog.Errorf("Failed to transform observed, error: %v", err) + return + } + got, err := retainPodFields(unstructuredDesiredObj, unstructuredObservedObj) + if (err != nil) != tt.wantErr { + t.Errorf("retainPodFields() error = %v, wantErr %v", err, tt.wantErr) + return + } + unstructuredWantObj, err := helper.ToUnstructured(tt.want) + if err != nil { + klog.Errorf("Failed to transform want, error: %v", err) + return + } + assert.Equalf(t, unstructuredWantObj, got, "retainPodFields(%v, %v)", unstructuredDesiredObj, unstructuredObservedObj) + }) + } +} + +func Test_getAllDefaultRetentionInterpreter(t *testing.T) { + expectedKinds := []schema.GroupVersionKind{ + {Group: "apps", Version: "v1", Kind: "Deployment"}, + {Group: "", Version: "v1", Kind: "Pod"}, + {Group: "", Version: "v1", Kind: "Service"}, + {Group: "", Version: "v1", Kind: "ServiceAccount"}, + {Group: "", Version: "v1", Kind: "PersistentVolumeClaim"}, + {Group: "", Version: "v1", Kind: "PersistentVolume"}, + {Group: "batch", Version: "v1", Kind: "Job"}, + {Group: "", Version: "v1", Kind: "Secret"}, + } + + got := getAllDefaultRetentionInterpreter() + + if len(got) != len(expectedKinds) { + t.Errorf("getAllDefaultRetentionInterpreter() length = %d, want %d", len(got), len(expectedKinds)) + } + + for _, key := range expectedKinds { + if _, exists := got[key]; !exists { + t.Errorf("getAllDefaultRetentionInterpreter() missing key %v", key) + } + } +} diff --git a/pkg/resourceinterpreter/default/native/revisereplica_test.go b/pkg/resourceinterpreter/default/native/revisereplica_test.go index 192f90bcdf97..39b80429a0e5 100644 --- a/pkg/resourceinterpreter/default/native/revisereplica_test.go +++ b/pkg/resourceinterpreter/default/native/revisereplica_test.go @@ -21,6 +21,7 @@ import ( "testing" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" ) func TestReviseDeploymentReplica(t *testing.T) { @@ -248,3 +249,24 @@ func TestReviseStatefulSetReplica(t *testing.T) { }) } } + +func TestGetAllDefaultReviseReplicaInterpreter(t *testing.T) { + expectedKinds := []schema.GroupVersionKind{ + {Group: "apps", Version: "v1", Kind: "Deployment"}, + {Group: "apps", Version: "v1", Kind: "StatefulSet"}, + {Group: "batch", Version: "v1", Kind: "Job"}, + } + + got := getAllDefaultReviseReplicaInterpreter() + + if len(got) != len(expectedKinds) { + t.Errorf("getAllDefaultReviseReplicaInterpreter() returned map of length %v, want %v", len(got), len(expectedKinds)) + } + + for _, key := range expectedKinds { + _, exists := got[key] + if !exists { + t.Errorf("getAllDefaultReviseReplicaInterpreter() missing key %v", key) + } + } +} diff --git a/pkg/resourceinterpreter/default/thirdparty/resourcecustomizations/helm.toolkit.fluxcd.io/v2beta1/HelmRelease/customizations.yaml b/pkg/resourceinterpreter/default/thirdparty/resourcecustomizations/helm.toolkit.fluxcd.io/v2beta1/HelmRelease/customizations.yaml index cf98bc195943..8fc76b56f09f 100644 --- a/pkg/resourceinterpreter/default/thirdparty/resourcecustomizations/helm.toolkit.fluxcd.io/v2beta1/HelmRelease/customizations.yaml +++ b/pkg/resourceinterpreter/default/thirdparty/resourcecustomizations/helm.toolkit.fluxcd.io/v2beta1/HelmRelease/customizations.yaml @@ -22,51 +22,76 @@ spec: statusAggregation: luaScript: > function AggregateStatus(desiredObj, statusItems) + if desiredObj.status == nil then + desiredObj.status = {} + end + if desiredObj.metadata.generation == nil then + desiredObj.metadata.generation = 0 + end + if desiredObj.status.observedGeneration == nil then + desiredObj.status.observedGeneration = 0 + end + + -- Initialize status fields if status doest not exist + -- If the Kustomization is not spread to any cluster, its status also should be aggregated if statusItems == nil then + desiredObj.status.observedGeneration = desiredObj.metadata.generation + desiredObj.status.lastAttemptedRevision = '' + desiredObj.status.lastAppliedRevision = '' + desiredObj.status.lastAttemptedValuesChecksum = '' + desiredObj.status.helmChart = '' + desiredObj.status.lastReleaseRevision = '' + desiredObj.status.failures = 0 + desiredObj.status.upgradeFailures = 0 + desiredObj.status.installFailures = 0 + desiredObj.status.conditions = {} return desiredObj end - desiredObj.status = {} - desiredObj.status.conditions = {} - conditions = {} + + local conditions = {} + local generation = desiredObj.metadata.generation + local lastAttemptedRevision = desiredObj.status.lastAttemptedRevision + local lastAppliedRevision = desiredObj.status.lastAppliedRevision + local lastAttemptedValuesChecksum = desiredObj.status.lastAttemptedValuesChecksum + local helmChart = desiredObj.status.helmChart + local lastReleaseRevision = desiredObj.status.lastReleaseRevision + local failures = desiredObj.status.failures + local upgradeFailures = desiredObj.status.upgradeFailures + local installFailures = desiredObj.status.installFailures + + -- Count all members that their status is updated to the latest generation + local observedResourceTemplateGenerationCount = 0 + local conditionsIndex = 1 for i = 1, #statusItems do if statusItems[i].status ~= nil and statusItems[i].status.lastAttemptedRevision ~= nil and statusItems[i].status.lastAttemptedRevision ~= '' then - desiredObj.status.lastAttemptedRevision = statusItems[i].status.lastAttemptedRevision + lastAttemptedRevision = statusItems[i].status.lastAttemptedRevision end if statusItems[i].status ~= nil and statusItems[i].status.lastAppliedRevision ~= nil and statusItems[i].status.lastAppliedRevision ~= '' then - desiredObj.status.lastAppliedRevision = statusItems[i].status.lastAppliedRevision + lastAppliedRevision = statusItems[i].status.lastAppliedRevision end - if statusItems[i].status ~= nil and statusItems[i].status.lastHandledReconcileAt ~= nil and statusItems[i].status.lastHandledReconcileAt ~= '' then - desiredObj.status.lastHandledReconcileAt = statusItems[i].status.lastHandledReconcileAt - end if statusItems[i].status ~= nil and statusItems[i].status.lastAttemptedValuesChecksum ~= nil and statusItems[i].status.lastAttemptedValuesChecksum ~= '' then - desiredObj.status.lastAttemptedValuesChecksum = statusItems[i].status.lastAttemptedValuesChecksum + lastAttemptedValuesChecksum = statusItems[i].status.lastAttemptedValuesChecksum end if statusItems[i].status ~= nil and statusItems[i].status.helmChart ~= nil and statusItems[i].status.helmChart ~= '' then - desiredObj.status.helmChart = statusItems[i].status.helmChart + helmChart = statusItems[i].status.helmChart end if statusItems[i].status ~= nil and statusItems[i].status.lastReleaseRevision ~= nil then - desiredObj.status.lastReleaseRevision = statusItems[i].status.lastReleaseRevision + lastReleaseRevision = statusItems[i].status.lastReleaseRevision end if statusItems[i].status ~= nil and statusItems[i].status.failures ~= nil then if desiredObj.status.failures ~= nil then - desiredObj.status.failures = desiredObj.status.failures + statusItems[i].status.failures - else - desiredObj.status.failures = statusItems[i].status.failures + failures = failures + statusItems[i].status.failures end end if statusItems[i].status ~= nil and statusItems[i].status.upgradeFailures ~= nil then if desiredObj.status.upgradeFailures ~= nil then - desiredObj.status.upgradeFailures = desiredObj.status.upgradeFailures + statusItems[i].status.upgradeFailures - else - desiredObj.status.upgradeFailures = statusItems[i].status.upgradeFailures + upgradeFailures = upgradeFailures + statusItems[i].status.upgradeFailures end end if statusItems[i].status ~= nil and statusItems[i].status.installFailures ~= nil then if desiredObj.status.installFailures ~= nil then - desiredObj.status.installFailures = desiredObj.status.installFailures + statusItems[i].status.installFailures - else - desiredObj.status.installFailures = statusItems[i].status.installFailures + installFailures = installFailures + statusItems[i].status.installFailures end end if statusItems[i].status ~= nil and statusItems[i].status.conditions ~= nil then @@ -86,9 +111,41 @@ spec: end end end + + -- Check if the member's status is updated to the latest generation + local resourceTemplateGeneration = 0 + if statusItems[i].status ~= nil and statusItems[i].status.resourceTemplateGeneration ~= nil then + resourceTemplateGeneration = statusItems[i].status.resourceTemplateGeneration + end + local memberGeneration = 0 + if statusItems[i].status ~= nil and statusItems[i].status.generation ~= nil then + memberGeneration = statusItems[i].status.generation + end + local memberObservedGeneration = 0 + if statusItems[i].status ~= nil and statusItems[i].status.observedGeneration ~= nil then + memberObservedGeneration = statusItems[i].status.observedGeneration + end + if resourceTemplateGeneration == generation and memberGeneration == memberObservedGeneration then + observedResourceTemplateGenerationCount = observedResourceTemplateGenerationCount + 1 + end + end + + -- Update the observed generation based on the observedResourceTemplateGenerationCount + if observedResourceTemplateGenerationCount == #statusItems then + desiredObj.status.observedGeneration = generation + else + desiredObj.status.observedGeneration = observedGeneration end - desiredObj.status.observedGeneration = desiredObj.metadata.generation + desiredObj.status.conditions = conditions + desiredObj.status.lastAttemptedRevision = lastAttemptedRevision + desiredObj.status.lastAppliedRevision = lastAppliedRevision + desiredObj.status.lastAttemptedValuesChecksum = lastAttemptedValuesChecksum + desiredObj.status.helmChart = helmChart + desiredObj.status.lastReleaseRevision = lastReleaseRevision + desiredObj.status.failures = failures + desiredObj.status.upgradeFailures = upgradeFailures + desiredObj.status.installFailures = installFailures return desiredObj end retention: @@ -102,11 +159,37 @@ spec: statusReflection: luaScript: > function ReflectStatus (observedObj) - status = {} - if observedObj == nil or observedObj.status == nil then + local status = {} + if observedObj == nil or observedObj.status == nil then + return status + end + + status.conditions = observedObj.status.conditions + status.observedGeneration = observedObj.status.observedGeneration + status.lastAttemptedRevision = observedObj.status.lastAttemptedRevision + status.lastAppliedRevision = observedObj.status.lastAppliedRevision + status.lastAttemptedValuesChecksum = observedObj.status.lastAttemptedValuesChecksum + status.helmChart = observedObj.status.helmChart + status.lastReleaseRevision = observedObj.status.lastReleaseRevision + status.failures = observedObj.status.failures + status.upgradeFailures = observedObj.status.upgradeFailures + status.installFailures = observedObj.status.installFailures + + -- handle resource generation report + if observedObj.metadata == nil then return status end - return observedObj.status + status.generation = observedObj.metadata.generation + + if observedObj.metadata.annotations == nil then + return status + end + local resourceTemplateGeneration = tonumber(observedObj.metadata.annotations["resourcetemplate.karmada.io/generation"]) + if resourceTemplateGeneration ~= nil then + status.resourceTemplateGeneration = resourceTemplateGeneration + end + + return status end dependencyInterpretation: luaScript: > diff --git a/pkg/resourceinterpreter/default/thirdparty/resourcecustomizations/helm.toolkit.fluxcd.io/v2beta1/HelmRelease/testdata/desired-helmrelease.yaml b/pkg/resourceinterpreter/default/thirdparty/resourcecustomizations/helm.toolkit.fluxcd.io/v2beta1/HelmRelease/testdata/desired-helmrelease.yaml index 5a5d6e6d4b9f..57a7720a7d4f 100644 --- a/pkg/resourceinterpreter/default/thirdparty/resourcecustomizations/helm.toolkit.fluxcd.io/v2beta1/HelmRelease/testdata/desired-helmrelease.yaml +++ b/pkg/resourceinterpreter/default/thirdparty/resourcecustomizations/helm.toolkit.fluxcd.io/v2beta1/HelmRelease/testdata/desired-helmrelease.yaml @@ -3,6 +3,7 @@ kind: HelmRelease metadata: name: sample namespace: default + generation: 1 spec: interval: 5m chart: diff --git a/pkg/resourceinterpreter/default/thirdparty/resourcecustomizations/helm.toolkit.fluxcd.io/v2beta1/HelmRelease/testdata/observed-helmrelease.yaml b/pkg/resourceinterpreter/default/thirdparty/resourcecustomizations/helm.toolkit.fluxcd.io/v2beta1/HelmRelease/testdata/observed-helmrelease.yaml index c00f89b5711d..9fd2eb920c9a 100644 --- a/pkg/resourceinterpreter/default/thirdparty/resourcecustomizations/helm.toolkit.fluxcd.io/v2beta1/HelmRelease/testdata/observed-helmrelease.yaml +++ b/pkg/resourceinterpreter/default/thirdparty/resourcecustomizations/helm.toolkit.fluxcd.io/v2beta1/HelmRelease/testdata/observed-helmrelease.yaml @@ -1,8 +1,11 @@ apiVersion: helm.toolkit.fluxcd.io/v2beta1 kind: HelmRelease metadata: + annotations: + resourcetemplate.karmada.io/generation: "1" name: sample namespace: default + generation: 1 spec: interval: 5m chart: diff --git a/pkg/resourceinterpreter/default/thirdparty/resourcecustomizations/helm.toolkit.fluxcd.io/v2beta1/HelmRelease/testdata/status-file.yaml b/pkg/resourceinterpreter/default/thirdparty/resourcecustomizations/helm.toolkit.fluxcd.io/v2beta1/HelmRelease/testdata/status-file.yaml index 9589cd8e0c23..9c5724f0e39d 100644 --- a/pkg/resourceinterpreter/default/thirdparty/resourcecustomizations/helm.toolkit.fluxcd.io/v2beta1/HelmRelease/testdata/status-file.yaml +++ b/pkg/resourceinterpreter/default/thirdparty/resourcecustomizations/helm.toolkit.fluxcd.io/v2beta1/HelmRelease/testdata/status-file.yaml @@ -13,12 +13,14 @@ status: reason: InstallSucceeded status: "True" type: Released + generation: 1 helmChart: test-helmrelease/test-helmrelease-sample lastAppliedRevision: 6.3.5 lastAttemptedRevision: 6.3.5 lastAttemptedValuesChecksum: da39a3ee5e6b4b0d3255bfef95601890afd80709 lastReleaseRevision: 1 observedGeneration: 1 + resourceTemplateGeneration: 1 --- applied: true clusterName: member3 @@ -35,9 +37,11 @@ status: reason: InstallSucceeded status: "True" type: Released + generation: 1 helmChart: test-helmrelease/test-helmrelease-sample lastAppliedRevision: 6.3.5 lastAttemptedRevision: 6.3.5 lastAttemptedValuesChecksum: da39a3ee5e6b4b0d3255bfef95601890afd80709 lastReleaseRevision: 1 observedGeneration: 1 + resourceTemplateGeneration: 1 diff --git a/pkg/scheduler/core/assignment.go b/pkg/scheduler/core/assignment.go index ac757b33cb48..14df16c6e056 100644 --- a/pkg/scheduler/core/assignment.go +++ b/pkg/scheduler/core/assignment.go @@ -158,7 +158,7 @@ func (as *assignState) resortAvailableClusters() []workv1alpha2.TargetCluster { var ( prev = make([]workv1alpha2.TargetCluster, 0, len(prior)) - left = make([]workv1alpha2.TargetCluster, 0, len(as.scheduledClusters)-len(prior)) + left = make([]workv1alpha2.TargetCluster, 0, len(as.availableClusters)-len(prior)) ) for _, cluster := range as.availableClusters { diff --git a/pkg/scheduler/core/spreadconstraint/select_groups.go b/pkg/scheduler/core/spreadconstraint/select_groups.go index 0030adf0e1f1..1140d6b4eb56 100755 --- a/pkg/scheduler/core/spreadconstraint/select_groups.go +++ b/pkg/scheduler/core/spreadconstraint/select_groups.go @@ -175,6 +175,12 @@ func findFeasiblePaths(groups []*GroupInfo, minConstraint, maxConstraint, target sum += groups[i].value rootPath.enqueue(groups[i]) dfsFunc(sum, i+1) + + // stop backtracking when we have to traverse all groups to satisfy the minimum constraint. + if len(groups) == minConstraint { + break + } + sum -= groups[i].value rootPath.popLast() } diff --git a/pkg/scheduler/scheduler_test.go b/pkg/scheduler/scheduler_test.go index da83e28fec2b..90c870c0df98 100644 --- a/pkg/scheduler/scheduler_test.go +++ b/pkg/scheduler/scheduler_test.go @@ -18,6 +18,7 @@ package scheduler import ( "context" + "fmt" "reflect" "testing" "time" @@ -26,10 +27,12 @@ import ( "k8s.io/apimachinery/pkg/runtime" dynamicfake "k8s.io/client-go/dynamic/fake" "k8s.io/client-go/kubernetes/fake" + "k8s.io/client-go/tools/record" workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" karmadafake "github.com/karmada-io/karmada/pkg/generated/clientset/versioned/fake" "github.com/karmada-io/karmada/pkg/util" + "github.com/karmada-io/karmada/pkg/util/grpcconnection" ) func TestCreateScheduler(t *testing.T) { @@ -37,12 +40,22 @@ func TestCreateScheduler(t *testing.T) { karmadaClient := karmadafake.NewSimpleClientset() kubeClient := fake.NewSimpleClientset() port := 10025 + servicePrefix := "test-service-prefix" + schedulerName := "test-scheduler" + timeout := metav1.Duration{Duration: 5 * time.Second} testcases := []struct { - name string - opts []Option - enableSchedulerEstimator bool - schedulerEstimatorPort int + name string + opts []Option + enableSchedulerEstimator bool + schedulerEstimatorPort int + disableSchedulerEstimatorInPullMode bool + schedulerEstimatorTimeout metav1.Duration + schedulerEstimatorServicePrefix string + schedulerName string + schedulerEstimatorClientConfig *grpcconnection.ClientConfig + enableEmptyWorkloadPropagation bool + plugins []string }{ { name: "scheduler with default configuration", @@ -66,6 +79,53 @@ func TestCreateScheduler(t *testing.T) { }, enableSchedulerEstimator: false, }, + { + name: "scheduler with disableSchedulerEstimatorInPullMode enabled", + opts: []Option{ + WithEnableSchedulerEstimator(true), + WithSchedulerEstimatorConnection(port, "", "", "", false), + WithDisableSchedulerEstimatorInPullMode(true), + }, + enableSchedulerEstimator: true, + schedulerEstimatorPort: port, + disableSchedulerEstimatorInPullMode: true, + }, + { + name: "scheduler with SchedulerEstimatorServicePrefix enabled", + opts: []Option{ + WithEnableSchedulerEstimator(true), + WithSchedulerEstimatorConnection(port, "", "", "", false), + WithSchedulerEstimatorServicePrefix(servicePrefix), + }, + enableSchedulerEstimator: true, + schedulerEstimatorPort: port, + schedulerEstimatorServicePrefix: servicePrefix, + }, + { + name: "scheduler with SchedulerName enabled", + opts: []Option{ + WithSchedulerName(schedulerName), + }, + schedulerName: schedulerName, + }, + { + name: "scheduler with EnableEmptyWorkloadPropagation enabled", + opts: []Option{ + WithEnableEmptyWorkloadPropagation(true), + }, + enableEmptyWorkloadPropagation: true, + }, + { + name: "scheduler with SchedulerEstimatorTimeout enabled", + opts: []Option{ + WithEnableSchedulerEstimator(true), + WithSchedulerEstimatorConnection(port, "", "", "", false), + WithSchedulerEstimatorTimeout(timeout), + }, + enableSchedulerEstimator: true, + schedulerEstimatorPort: port, + schedulerEstimatorTimeout: timeout, + }, } for _, tc := range testcases { @@ -82,10 +142,25 @@ func TestCreateScheduler(t *testing.T) { if tc.enableSchedulerEstimator && tc.schedulerEstimatorPort != sche.schedulerEstimatorClientConfig.TargetPort { t.Errorf("unexpected schedulerEstimatorPort want %v, got %v", tc.schedulerEstimatorPort, sche.schedulerEstimatorClientConfig.TargetPort) } + + if tc.disableSchedulerEstimatorInPullMode != sche.disableSchedulerEstimatorInPullMode { + t.Errorf("unexpected disableSchedulerEstimatorInPullMode want %v, got %v", tc.disableSchedulerEstimatorInPullMode, sche.disableSchedulerEstimatorInPullMode) + } + + if tc.schedulerEstimatorServicePrefix != sche.schedulerEstimatorServicePrefix { + t.Errorf("unexpected schedulerEstimatorServicePrefix want %v, got %v", tc.schedulerEstimatorServicePrefix, sche.schedulerEstimatorServicePrefix) + } + + if tc.schedulerName != sche.schedulerName { + t.Errorf("unexpected schedulerName want %v, got %v", tc.schedulerName, sche.schedulerName) + } + + if tc.enableEmptyWorkloadPropagation != sche.enableEmptyWorkloadPropagation { + t.Errorf("unexpected enableEmptyWorkloadPropagation want %v, got %v", tc.enableEmptyWorkloadPropagation, sche.enableEmptyWorkloadPropagation) + } }) } } - func Test_patchBindingStatusCondition(t *testing.T) { oneHourBefore := time.Now().Add(-1 * time.Hour).Round(time.Second) oneHourAfter := time.Now().Add(1 * time.Hour).Round(time.Second) @@ -500,3 +575,228 @@ func Test_patchClusterBindingStatusWithAffinityName(t *testing.T) { }) } } + +func Test_recordScheduleResultEventForResourceBinding(t *testing.T) { + fakeRecorder := record.NewFakeRecorder(10) + scheduler := &Scheduler{eventRecorder: fakeRecorder} + + tests := []struct { + name string + rb *workv1alpha2.ResourceBinding + scheduleResult []workv1alpha2.TargetCluster + schedulerErr error + expectedEvents int + expectedMsg string + }{ + { + name: "nil ResourceBinding", + rb: nil, + scheduleResult: nil, + schedulerErr: nil, + expectedEvents: 0, + expectedMsg: "", + }, + { + name: "successful scheduling", + rb: &workv1alpha2.ResourceBinding{ + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + Kind: "Deployment", + APIVersion: "apps/v1", + Namespace: "default", + Name: "test-deployment", + UID: "12345", + }, + }, + }, + scheduleResult: []workv1alpha2.TargetCluster{ + {Name: "cluster1", Replicas: 1}, + {Name: "cluster2", Replicas: 2}, + }, + schedulerErr: nil, + expectedEvents: 2, + expectedMsg: fmt.Sprintf("%s Result: {%s}", successfulSchedulingMessage, targetClustersToString([]workv1alpha2.TargetCluster{ + {Name: "cluster1", Replicas: 1}, + {Name: "cluster2", Replicas: 2}, + }))}, + { + name: "scheduling error", + rb: &workv1alpha2.ResourceBinding{ + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + Kind: "Deployment", + APIVersion: "apps/v1", + Namespace: "default", + Name: "test-deployment", + UID: "12345", + }, + }, + }, + scheduleResult: nil, + schedulerErr: fmt.Errorf("scheduling error"), + expectedEvents: 2, + expectedMsg: "scheduling error", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + fakeRecorder.Events = make(chan string, 10) + + scheduler.recordScheduleResultEventForResourceBinding(test.rb, test.scheduleResult, test.schedulerErr) + + if len(fakeRecorder.Events) != test.expectedEvents { + t.Errorf("expected %d events, got %d", test.expectedEvents, len(fakeRecorder.Events)) + } + + for i := 0; i < test.expectedEvents; i++ { + select { + case event := <-fakeRecorder.Events: + if !contains(event, test.expectedMsg) { + t.Errorf("expected event message to contain %q, got %q", test.expectedMsg, event) + } + default: + t.Error("expected event not found") + } + } + }) + } +} + +func contains(event, msg string) bool { + return len(event) >= len(msg) && event[len(event)-len(msg):] == msg +} + +func Test_recordScheduleResultEventForClusterResourceBinding(t *testing.T) { + fakeRecorder := record.NewFakeRecorder(10) + scheduler := &Scheduler{eventRecorder: fakeRecorder} + + tests := []struct { + name string + crb *workv1alpha2.ClusterResourceBinding + scheduleResult []workv1alpha2.TargetCluster + schedulerErr error + expectedEvents int + expectedMsg string + }{ + { + name: "nil ClusterResourceBinding", + crb: nil, + scheduleResult: nil, + schedulerErr: nil, + expectedEvents: 0, + expectedMsg: "", + }, + { + name: "successful scheduling", + crb: &workv1alpha2.ClusterResourceBinding{ + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + Kind: "Deployment", + APIVersion: "apps/v1", + Namespace: "default", + Name: "test-deployment", + UID: "12345", + }, + }, + }, + scheduleResult: []workv1alpha2.TargetCluster{ + {Name: "cluster1", Replicas: 1}, + {Name: "cluster2", Replicas: 2}, + }, + schedulerErr: nil, + expectedEvents: 2, + expectedMsg: fmt.Sprintf("%s Result {%s}", successfulSchedulingMessage, targetClustersToString([]workv1alpha2.TargetCluster{ + {Name: "cluster1", Replicas: 1}, + {Name: "cluster2", Replicas: 2}, + })), + }, + { + name: "scheduling error", + crb: &workv1alpha2.ClusterResourceBinding{ + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + Kind: "Deployment", + APIVersion: "apps/v1", + Namespace: "default", + Name: "test-deployment", + UID: "12345", + }, + }, + }, + scheduleResult: nil, + schedulerErr: fmt.Errorf("scheduling error"), + expectedEvents: 2, + expectedMsg: "scheduling error", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + fakeRecorder.Events = make(chan string, 10) + + scheduler.recordScheduleResultEventForClusterResourceBinding(test.crb, test.scheduleResult, test.schedulerErr) + + if len(fakeRecorder.Events) != test.expectedEvents { + t.Errorf("expected %d events, got %d", test.expectedEvents, len(fakeRecorder.Events)) + } + + for i := 0; i < test.expectedEvents; i++ { + select { + case event := <-fakeRecorder.Events: + if !contains(event, test.expectedMsg) { + t.Errorf("expected event message to contain %q, got %q", test.expectedMsg, event) + } + default: + t.Error("expected event not found") + } + } + }) + } +} + +func Test_targetClustersToString(t *testing.T) { + tests := []struct { + name string + tcs []workv1alpha2.TargetCluster + expectedOutput string + }{ + { + name: "empty slice", + tcs: []workv1alpha2.TargetCluster{}, + expectedOutput: "", + }, + { + name: "single cluster", + tcs: []workv1alpha2.TargetCluster{ + {Name: "cluster1", Replicas: 1}, + }, + expectedOutput: "cluster1:1", + }, + { + name: "multiple clusters", + tcs: []workv1alpha2.TargetCluster{ + {Name: "cluster1", Replicas: 1}, + {Name: "cluster2", Replicas: 2}, + }, + expectedOutput: "cluster1:1, cluster2:2", + }, + { + name: "clusters with zero replicas", + tcs: []workv1alpha2.TargetCluster{ + {Name: "cluster1", Replicas: 0}, + {Name: "cluster2", Replicas: 2}, + }, + expectedOutput: "cluster1:0, cluster2:2", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + result := targetClustersToString(test.tcs) + if result != test.expectedOutput { + t.Errorf("expected %q, got %q", test.expectedOutput, result) + } + }) + } +} diff --git a/pkg/servicenameresolutiondetector/coredns/detector_test.go b/pkg/servicenameresolutiondetector/coredns/detector_test.go new file mode 100644 index 000000000000..3f9d9e05acd7 --- /dev/null +++ b/pkg/servicenameresolutiondetector/coredns/detector_test.go @@ -0,0 +1,586 @@ +/* +Copyright 2024 The Karmada 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 coredns + +import ( + "context" + "testing" + "time" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/informers" + "k8s.io/client-go/kubernetes/fake" + componentbaseconfig "k8s.io/component-base/config" + "k8s.io/klog/v2" + + clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1" + karmadafake "github.com/karmada-io/karmada/pkg/generated/clientset/versioned/fake" +) + +type mockConditionStore struct { + conditions []metav1.Condition +} + +func (m *mockConditionStore) ListAll() ([]metav1.Condition, error) { + return m.conditions, nil +} + +func (m *mockConditionStore) Load(_ string) (*metav1.Condition, error) { + return nil, nil +} + +func (m *mockConditionStore) Store(_ string, _ *metav1.Condition) error { + return nil +} + +// Note: During test execution, you may observe log messages including DNS lookup failures +// and "node not found" errors. These messages do not indicate test failures, but rather +// simulate real-world scenarios where network issues or resource unavailability might occur. +// The detector is designed to handle these situations gracefully, which is reflected in the +// passing tests. +// +// Specifically: +// 1. DNS lookup failures ("nslookup failed") occur because the test environment doesn't have +// a real DNS setup. In a production environment, these lookups would typically succeed. +// 2. "Node not found" messages appear because the test is simulating scenarios where a node +// might not be immediately available. +// +// These log messages provide insight into the detector's behavior under less-than-ideal conditions, +// demonstrating its ability to operate correctly even when facing network or resource issues. + +func TestNewCorednsDetector(t *testing.T) { + tests := []struct { + name string + hostName string + clusterName string + leConfig componentbaseconfig.LeaderElectionConfiguration + expectedErr bool + }{ + { + name: "Valid detector creation", + hostName: "test-host", + clusterName: "test-cluster", + leConfig: componentbaseconfig.LeaderElectionConfiguration{LeaderElect: false}, + expectedErr: false, + }, + { + name: "Valid detector creation with empty host name", + hostName: "", + clusterName: "test-cluster", + leConfig: componentbaseconfig.LeaderElectionConfiguration{LeaderElect: false}, + expectedErr: false, + }, + { + name: "Valid detector creation with empty cluster name", + hostName: "test-host", + clusterName: "", + leConfig: componentbaseconfig.LeaderElectionConfiguration{LeaderElect: false}, + expectedErr: false, + }, + { + name: "Detector creation with LeaderElect true", + hostName: "test-host", + clusterName: "test-cluster", + leConfig: componentbaseconfig.LeaderElectionConfiguration{ + LeaderElect: true, + ResourceLock: "leases", + ResourceName: "test-resource", + ResourceNamespace: "default", + }, + expectedErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + memberClusterClient := fake.NewSimpleClientset() + karmadaClient := karmadafake.NewSimpleClientset() + informerFactory := informers.NewSharedInformerFactory(memberClusterClient, 0) + + cfg := &Config{ + PeriodSeconds: time.Second, + SuccessThreshold: time.Minute, + FailureThreshold: time.Minute, + StaleThreshold: time.Minute, + } + + detector, err := NewCorednsDetector(memberClusterClient, karmadaClient, informerFactory, tt.leConfig, cfg, tt.hostName, tt.clusterName) + + if tt.expectedErr && err == nil { + t.Fatal("Expected an error, but got none") + } + if !tt.expectedErr && err != nil { + t.Fatalf("Unexpected error: %v", err) + } + if err == nil { + if detector == nil { + t.Fatal("Expected detector to not be nil") + } + if detector.nodeName != tt.hostName { + t.Errorf("Expected nodeName to be '%s', got '%s'", tt.hostName, detector.nodeName) + } + if detector.clusterName != tt.clusterName { + t.Errorf("Expected clusterName to be '%s', got '%s'", tt.clusterName, detector.clusterName) + } + } + }) + } +} + +func TestLookupOnce(t *testing.T) { + tests := []struct { + name string + expectedType string + expectedStatus []metav1.ConditionStatus + }{ + { + name: "Valid lookup", + expectedType: condType, + expectedStatus: []metav1.ConditionStatus{metav1.ConditionTrue, metav1.ConditionFalse}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + logger := klog.NewKlogr() + condition := lookupOnce(logger) + + if condition.Type != tt.expectedType { + t.Errorf("Expected condition type to be '%s', got '%s'", tt.expectedType, condition.Type) + } + + validStatus := false + for _, status := range tt.expectedStatus { + if condition.Status == status { + validStatus = true + break + } + } + if !validStatus { + t.Errorf("Expected condition status to be one of %v, got '%s'", tt.expectedStatus, condition.Status) + } + + if condition.Status == metav1.ConditionFalse { + if condition.Reason != serviceDomainNameResolutionFailed { + t.Errorf("Expected reason to be '%s', got '%s'", serviceDomainNameResolutionFailed, condition.Reason) + } + } + }) + } +} + +func TestShouldAlarm(t *testing.T) { + tests := []struct { + name string + conditions []metav1.Condition + expectedSkip bool + expectedAlarm bool + expectedError bool + }{ + { + name: "No conditions", + conditions: []metav1.Condition{}, + expectedSkip: true, + expectedAlarm: false, + }, + { + name: "All conditions false", + conditions: []metav1.Condition{ + {Status: metav1.ConditionFalse}, + {Status: metav1.ConditionFalse}, + }, + expectedSkip: false, + expectedAlarm: true, + }, + { + name: "Mixed conditions", + conditions: []metav1.Condition{ + {Status: metav1.ConditionFalse}, + {Status: metav1.ConditionTrue}, + }, + expectedSkip: false, + expectedAlarm: false, + }, + { + name: "With unknown condition", + conditions: []metav1.Condition{ + {Status: metav1.ConditionUnknown}, + {Status: metav1.ConditionFalse}, + }, + expectedSkip: true, + expectedAlarm: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + d := &Detector{ + conditionStore: &mockConditionStore{conditions: tt.conditions}, + } + + skip, alarm, err := d.shouldAlarm() + + if tt.expectedError && err == nil { + t.Error("Expected an error, but got none") + } + if !tt.expectedError && err != nil { + t.Errorf("Unexpected error: %v", err) + } + if skip != tt.expectedSkip { + t.Errorf("Expected skip to be %v, but got %v", tt.expectedSkip, skip) + } + if alarm != tt.expectedAlarm { + t.Errorf("Expected alarm to be %v, but got %v", tt.expectedAlarm, alarm) + } + }) + } +} +func TestNewClusterCondition(t *testing.T) { + tests := []struct { + name string + alarm bool + expectedStatus metav1.ConditionStatus + expectedReason string + expectedMessage string + }{ + { + name: "Alarm is true", + alarm: true, + expectedStatus: metav1.ConditionFalse, + expectedReason: serviceDomainNameResolutionFailed, + expectedMessage: "service domain name resolution is unready", + }, + { + name: "Alarm is false", + alarm: false, + expectedStatus: metav1.ConditionTrue, + expectedReason: serviceDomainNameResolutionReady, + expectedMessage: "service domain name resolution is ready", + }, + } + + detector := &Detector{} + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cond, err := detector.newClusterCondition(tt.alarm) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + if cond.Status != tt.expectedStatus { + t.Errorf("Expected condition status to be %s, got %s", tt.expectedStatus, cond.Status) + } + if cond.Reason != tt.expectedReason { + t.Errorf("Expected condition reason to be %s, got %s", tt.expectedReason, cond.Reason) + } + if cond.Message != tt.expectedMessage { + t.Errorf("Expected condition message to be %s, got %s", tt.expectedMessage, cond.Message) + } + }) + } +} + +func TestDetectorRun(t *testing.T) { + tests := []struct { + name string + setupFunc func(*Detector) + expectPanic bool + }{ + { + name: "Normal run", + setupFunc: func(*Detector) {}, + expectPanic: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + memberClusterClient := fake.NewSimpleClientset() + karmadaClient := karmadafake.NewSimpleClientset() + informerFactory := informers.NewSharedInformerFactory(memberClusterClient, 0) + + cfg := &Config{ + PeriodSeconds: time.Second, + SuccessThreshold: time.Minute, + FailureThreshold: time.Minute, + StaleThreshold: time.Minute, + } + + leConfig := componentbaseconfig.LeaderElectionConfiguration{ + LeaderElect: false, + } + + detector, err := NewCorednsDetector( + memberClusterClient, + karmadaClient, + informerFactory, + leConfig, + cfg, + "test-host", + "test-cluster", + ) + if err != nil { + t.Fatalf("Failed to create CoreDNS detector: %v", err) + } + + tt.setupFunc(detector) + + informerFactory.Start(nil) + + ctx, cancel := context.WithCancel(context.Background()) + + panicked := make(chan bool) + go func() { + defer func() { + if r := recover(); r != nil { + panicked <- true + } + close(panicked) + }() + detector.Run(ctx) + }() + + time.Sleep(2 * time.Second) + cancel() + detector.queue.ShutDown() + + if tt.expectPanic { + if !<-panicked { + t.Error("Expected Run to panic, but it didn't") + } + } else { + if <-panicked { + t.Error("Run panicked unexpectedly") + } + } + }) + } +} + +func TestDetectorWorker(t *testing.T) { + tests := []struct { + name string + setupFunc func(*Detector) + expectedItems int + }{ + { + name: "Process one item", + setupFunc: func(d *Detector) { + d.queue.Add(0) + }, + expectedItems: 0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + memberClusterClient := fake.NewSimpleClientset() + karmadaClient := karmadafake.NewSimpleClientset() + informerFactory := informers.NewSharedInformerFactory(memberClusterClient, 0) + + cfg := &Config{ + PeriodSeconds: time.Second, + SuccessThreshold: time.Minute, + FailureThreshold: time.Minute, + StaleThreshold: time.Minute, + } + + leConfig := componentbaseconfig.LeaderElectionConfiguration{ + LeaderElect: false, + } + + detector, err := NewCorednsDetector( + memberClusterClient, + karmadaClient, + informerFactory, + leConfig, + cfg, + "test-host", + "test-cluster", + ) + if err != nil { + t.Fatalf("Failed to create CoreDNS detector: %v", err) + } + + informerFactory.Start(nil) + informerFactory.WaitForCacheSync(nil) + + _, err = memberClusterClient.CoreV1().Nodes().Create(context.Background(), &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-host", + }, + }, metav1.CreateOptions{}) + if err != nil { + t.Fatalf("Failed to create test node: %v", err) + } + + tt.setupFunc(detector) + + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + + go detector.worker(ctx) + + time.Sleep(1 * time.Second) + + if detector.queue.Len() != tt.expectedItems { + t.Errorf("Expected queue to have %d items, but it has %d items", tt.expectedItems, detector.queue.Len()) + } + }) + } +} + +func TestDetectorProcessNextWorkItem(t *testing.T) { + tests := []struct { + name string + setupFunc func(*Detector) + expectedResult bool + expectedItems int + }{ + { + name: "Process one item", + setupFunc: func(d *Detector) { + d.queue.Add(0) + }, + expectedResult: true, + expectedItems: 0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + memberClusterClient := fake.NewSimpleClientset() + karmadaClient := karmadafake.NewSimpleClientset() + informerFactory := informers.NewSharedInformerFactory(memberClusterClient, 0) + + cfg := &Config{ + PeriodSeconds: time.Second, + SuccessThreshold: time.Minute, + FailureThreshold: time.Minute, + StaleThreshold: time.Minute, + } + + leConfig := componentbaseconfig.LeaderElectionConfiguration{ + LeaderElect: false, + } + + detector, err := NewCorednsDetector( + memberClusterClient, + karmadaClient, + informerFactory, + leConfig, + cfg, + "test-host", + "test-cluster", + ) + if err != nil { + t.Fatalf("Failed to create CoreDNS detector: %v", err) + } + + informerFactory.Start(nil) + informerFactory.WaitForCacheSync(nil) + + _, err = memberClusterClient.CoreV1().Nodes().Create(context.Background(), &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-host", + }, + }, metav1.CreateOptions{}) + if err != nil { + t.Fatalf("Failed to create test node: %v", err) + } + + tt.setupFunc(detector) + + ctx := context.Background() + + result := detector.processNextWorkItem(ctx) + + if result != tt.expectedResult { + t.Errorf("Expected processNextWorkItem to return %v, but got %v", tt.expectedResult, result) + } + + if detector.queue.Len() != tt.expectedItems { + t.Errorf("Expected queue to have %d items, but it has %d items", tt.expectedItems, detector.queue.Len()) + } + }) + } +} + +func TestDetectorSync(t *testing.T) { + tests := []struct { + name string + setupFunc func(*Detector, *karmadafake.Clientset) + expectedError bool + expectedConds int + }{ + { + name: "Successful sync", + setupFunc: func(d *Detector, kc *karmadafake.Clientset) { + d.conditionStore = &mockConditionStore{ + conditions: []metav1.Condition{ + {Status: metav1.ConditionTrue}, + }, + } + cluster := &clusterv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-cluster", + }, + } + _, err := kc.ClusterV1alpha1().Clusters().Create(context.Background(), cluster, metav1.CreateOptions{}) + if err != nil { + t.Fatalf("Failed to create test cluster: %v", err) + } + }, + expectedError: false, + expectedConds: 1, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + karmadaClient := karmadafake.NewSimpleClientset() + + d := &Detector{ + karmadaClient: karmadaClient, + clusterName: "test-cluster", + } + + tt.setupFunc(d, karmadaClient) + + err := d.sync(context.Background()) + + if tt.expectedError && err == nil { + t.Fatal("Expected an error, but got none") + } + if !tt.expectedError && err != nil { + t.Fatalf("Unexpected error from sync: %v", err) + } + + if err == nil { + updatedCluster, err := karmadaClient.ClusterV1alpha1().Clusters().Get(context.Background(), "test-cluster", metav1.GetOptions{}) + if err != nil { + t.Fatalf("Failed to get updated cluster: %v", err) + } + + if len(updatedCluster.Status.Conditions) != tt.expectedConds { + t.Errorf("Expected %d conditions, but got %d", tt.expectedConds, len(updatedCluster.Status.Conditions)) + } + } + }) + } +} diff --git a/pkg/servicenameresolutiondetector/store/condition_cache_test.go b/pkg/servicenameresolutiondetector/store/condition_cache_test.go new file mode 100644 index 000000000000..927acb4b5eec --- /dev/null +++ b/pkg/servicenameresolutiondetector/store/condition_cache_test.go @@ -0,0 +1,211 @@ +/* +Copyright 2024 The Karmada 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 store + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestNewConditionCache(t *testing.T) { + successThreshold := 5 * time.Minute + failureThreshold := 3 * time.Minute + + cache := NewConditionCache(successThreshold, failureThreshold) + + assert.Equal(t, successThreshold, cache.successThreshold) + assert.Equal(t, failureThreshold, cache.failureThreshold) +} + +func TestConditionCache_ThresholdAdjustedCondition(t *testing.T) { + testCases := []struct { + name string + key string + curr *metav1.Condition + observed *metav1.Condition + existingCond *detectCondition + successThreshold time.Duration + failureThreshold time.Duration + expected *metav1.Condition + }{ + { + name: "First detection", + key: "test1", + curr: nil, + observed: &metav1.Condition{ + Type: "TestType", + Status: metav1.ConditionTrue, + }, + existingCond: nil, + successThreshold: 5 * time.Minute, + failureThreshold: 3 * time.Minute, + expected: &metav1.Condition{ + Type: "TestType", + Status: metav1.ConditionTrue, + }, + }, + { + name: "Status changed, within threshold", + key: "test2", + curr: &metav1.Condition{ + Type: "TestType", + Status: metav1.ConditionTrue, + }, + observed: &metav1.Condition{ + Type: "TestType", + Status: metav1.ConditionFalse, + }, + existingCond: &detectCondition{ + condition: metav1.Condition{ + Type: "TestType", + Status: metav1.ConditionTrue, + }, + thresholdStartTime: time.Now().Add(-1 * time.Minute), + }, + successThreshold: 5 * time.Minute, + failureThreshold: 3 * time.Minute, + expected: &metav1.Condition{ + Type: "TestType", + Status: metav1.ConditionTrue, + }, + }, + { + name: "Status changed, threshold exceeded", + key: "test3", + curr: &metav1.Condition{ + Type: "TestType", + Status: metav1.ConditionTrue, + }, + observed: &metav1.Condition{ + Type: "TestType", + Status: metav1.ConditionFalse, + }, + existingCond: &detectCondition{ + condition: metav1.Condition{ + Type: "TestType", + Status: metav1.ConditionFalse, + }, + thresholdStartTime: time.Now().Add(-4 * time.Minute), + }, + successThreshold: 5 * time.Minute, + failureThreshold: 3 * time.Minute, + expected: &metav1.Condition{ + Type: "TestType", + Status: metav1.ConditionFalse, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + cache := NewConditionCache(tc.successThreshold, tc.failureThreshold) + if tc.existingCond != nil { + cache.update(tc.key, tc.existingCond) + } + + result := cache.ThresholdAdjustedCondition(tc.key, tc.curr, tc.observed) + + assert.Equal(t, tc.expected.Type, result.Type) + assert.Equal(t, tc.expected.Status, result.Status) + }) + } +} + +func TestConditionCache_GetAndUpdate(t *testing.T) { + testCases := []struct { + name string + key string + initialValue *detectCondition + updatedValue *detectCondition + expectedBefore *detectCondition + expectedAfter *detectCondition + }{ + { + name: "Get non-existent key", + key: "testKey1", + initialValue: nil, + updatedValue: nil, + expectedBefore: nil, + expectedAfter: nil, + }, + { + name: "Update and get existing key", + key: "testKey2", + initialValue: &detectCondition{ + condition: metav1.Condition{ + Type: "TestType", + Status: metav1.ConditionTrue, + }, + thresholdStartTime: time.Now(), + }, + updatedValue: &detectCondition{ + condition: metav1.Condition{ + Type: "TestType", + Status: metav1.ConditionFalse, + }, + thresholdStartTime: time.Now(), + }, + expectedBefore: &detectCondition{ + condition: metav1.Condition{ + Type: "TestType", + Status: metav1.ConditionTrue, + }, + }, + expectedAfter: &detectCondition{ + condition: metav1.Condition{ + Type: "TestType", + Status: metav1.ConditionFalse, + }, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + cache := NewConditionCache(5*time.Minute, 3*time.Minute) + + if tc.initialValue != nil { + cache.update(tc.key, tc.initialValue) + } + + result := cache.get(tc.key) + if tc.expectedBefore == nil { + assert.Nil(t, result) + } else { + assert.NotNil(t, result) + assert.Equal(t, tc.expectedBefore.condition.Type, result.condition.Type) + assert.Equal(t, tc.expectedBefore.condition.Status, result.condition.Status) + } + + if tc.updatedValue != nil { + cache.update(tc.key, tc.updatedValue) + } + + result = cache.get(tc.key) + if tc.expectedAfter == nil { + assert.Nil(t, result) + } else { + assert.NotNil(t, result) + assert.Equal(t, tc.expectedAfter.condition.Type, result.condition.Type) + assert.Equal(t, tc.expectedAfter.condition.Status, result.condition.Status) + } + }) + } +} diff --git a/pkg/servicenameresolutiondetector/store/node_store_test.go b/pkg/servicenameresolutiondetector/store/node_store_test.go new file mode 100644 index 000000000000..364962f33126 --- /dev/null +++ b/pkg/servicenameresolutiondetector/store/node_store_test.go @@ -0,0 +1,359 @@ +/* +Copyright 2024 The Karmada 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 store + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/fake" + listcorev1 "k8s.io/client-go/listers/core/v1" + "k8s.io/client-go/tools/cache" +) + +func TestNodeStore(t *testing.T) { + clientset := fake.NewSimpleClientset() + + nodeInformer := cache.NewSharedIndexInformer( + &cache.ListWatch{}, + &corev1.Node{}, + 0, + cache.Indexers{}, + ) + nodeLister := listcorev1.NewNodeLister(nodeInformer.GetIndexer()) + + store := NewNodeConditionStore( + clientset.CoreV1().Nodes(), + nodeLister, + string(corev1.NodeReady), + 5*time.Minute, + ) + + testCases := []struct { + name string + setupNodes []*corev1.Node + operation string + key string + inputCondition *metav1.Condition + expectedResult interface{} + expectedError bool + }{ + { + name: "Load existing node condition", + setupNodes: []*corev1.Node{ + { + ObjectMeta: metav1.ObjectMeta{Name: "node1"}, + Status: corev1.NodeStatus{ + Conditions: []corev1.NodeCondition{ + {Type: corev1.NodeReady, Status: corev1.ConditionTrue}, + }, + }, + }, + }, + operation: "Load", + key: "node1", + expectedResult: &metav1.Condition{ + Type: string(corev1.NodeReady), + Status: metav1.ConditionTrue, + }, + expectedError: false, + }, + { + name: "Load non-existent node", + setupNodes: []*corev1.Node{}, + operation: "Load", + key: "non-existent", + expectedError: true, + }, + { + name: "Store condition for existing node", + setupNodes: []*corev1.Node{ + { + ObjectMeta: metav1.ObjectMeta{Name: "node2"}, + Status: corev1.NodeStatus{}, + }, + }, + operation: "Store", + key: "node2", + inputCondition: &metav1.Condition{ + Type: string(corev1.NodeReady), + Status: metav1.ConditionTrue, + }, + expectedError: false, + }, + { + name: "Load existing node with mismatched condition type", + setupNodes: []*corev1.Node{ + { + ObjectMeta: metav1.ObjectMeta{Name: "node3"}, + Status: corev1.NodeStatus{ + Conditions: []corev1.NodeCondition{ + {Type: corev1.NodeDiskPressure, Status: corev1.ConditionFalse}, + }, + }, + }, + }, + operation: "Load", + key: "node3", + expectedResult: (*metav1.Condition)(nil), + expectedError: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Clear the store + err := nodeInformer.GetStore().Replace(nil, "") + assert.NoError(t, err) + + // Setup nodes + for _, node := range tc.setupNodes { + err := nodeInformer.GetStore().Add(node) + assert.NoError(t, err) + _, err = clientset.CoreV1().Nodes().Create(context.TODO(), node, metav1.CreateOptions{}) + assert.NoError(t, err) + } + + var result interface{} + var opErr error + + switch tc.operation { + case "Load": + result, opErr = store.Load(tc.key) + case "Store": + opErr = store.Store(tc.key, tc.inputCondition) + } + + if tc.expectedError { + assert.Error(t, opErr) + } else { + assert.NoError(t, opErr) + if tc.expectedResult != nil { + assert.Equal(t, tc.expectedResult, result) + } + } + }) + } +} + +func TestNodeStore_ListAll(t *testing.T) { + clientset := fake.NewSimpleClientset() + nodeInformer := cache.NewSharedIndexInformer( + &cache.ListWatch{}, + &corev1.Node{}, + 0, + cache.Indexers{}, + ) + nodeLister := listcorev1.NewNodeLister(nodeInformer.GetIndexer()) + + store := NewNodeConditionStore( + clientset.CoreV1().Nodes(), + nodeLister, + string(corev1.NodeReady), + 5*time.Minute, + ) + + testCases := []struct { + name string + nodes []*corev1.Node + expectedResult []metav1.Condition + expectedError bool + }{ + { + name: "List all ready nodes", + nodes: []*corev1.Node{ + { + ObjectMeta: metav1.ObjectMeta{Name: "node1"}, + Status: corev1.NodeStatus{ + Conditions: []corev1.NodeCondition{ + {Type: corev1.NodeReady, Status: corev1.ConditionTrue, LastHeartbeatTime: metav1.Now()}, + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{Name: "node2"}, + Status: corev1.NodeStatus{ + Conditions: []corev1.NodeCondition{ + {Type: corev1.NodeReady, Status: corev1.ConditionTrue, LastHeartbeatTime: metav1.Now()}, + }, + }, + }, + }, + expectedResult: []metav1.Condition{ + {Type: string(corev1.NodeReady), Status: metav1.ConditionTrue}, + {Type: string(corev1.NodeReady), Status: metav1.ConditionTrue}, + }, + expectedError: false, + }, + { + name: "List with not ready and stale nodes", + nodes: []*corev1.Node{ + { + ObjectMeta: metav1.ObjectMeta{Name: "node1"}, + Status: corev1.NodeStatus{ + Conditions: []corev1.NodeCondition{ + {Type: corev1.NodeReady, Status: corev1.ConditionTrue, LastHeartbeatTime: metav1.Now()}, + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{Name: "node2"}, + Status: corev1.NodeStatus{ + Conditions: []corev1.NodeCondition{ + {Type: corev1.NodeReady, Status: corev1.ConditionFalse, LastHeartbeatTime: metav1.Now()}, + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{Name: "node3"}, + Status: corev1.NodeStatus{ + Conditions: []corev1.NodeCondition{ + {Type: corev1.NodeReady, Status: corev1.ConditionTrue, LastHeartbeatTime: metav1.NewTime(time.Now().Add(-10 * time.Minute))}, + }, + }, + }, + }, + expectedResult: []metav1.Condition{ + {Type: string(corev1.NodeReady), Status: metav1.ConditionTrue}, + {Type: string(corev1.NodeReady), Status: metav1.ConditionUnknown}, + }, + expectedError: false, + }, + { + name: "Empty node list", + nodes: []*corev1.Node{}, + expectedResult: []metav1.Condition{}, + expectedError: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + nodeInterfaces := make([]interface{}, len(tc.nodes)) + for i, node := range tc.nodes { + nodeInterfaces[i] = node + } + + err := nodeInformer.GetStore().Replace(nodeInterfaces, "") + assert.NoError(t, err) + + result, err := store.ListAll() + + if tc.expectedError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, len(tc.expectedResult), len(result)) + + expectedMap := make(map[string]int) + resultMap := make(map[string]int) + + for _, cond := range tc.expectedResult { + key := fmt.Sprintf("%s:%s", cond.Type, cond.Status) + expectedMap[key]++ + } + + for _, cond := range result { + key := fmt.Sprintf("%s:%s", cond.Type, cond.Status) + resultMap[key]++ + } + + assert.Equal(t, expectedMap, resultMap) + } + }) + } +} + +func TestSetNodeStatusCondition(t *testing.T) { + testCases := []struct { + name string + existingCondition *corev1.NodeCondition + newCondition corev1.NodeCondition + expectedCondition corev1.NodeCondition + }{ + { + name: "Update existing condition with status change", + existingCondition: &corev1.NodeCondition{ + Type: corev1.NodeReady, + Status: corev1.ConditionTrue, + LastTransitionTime: metav1.NewTime(time.Now().Add(-1 * time.Hour)), + LastHeartbeatTime: metav1.NewTime(time.Now().Add(-1 * time.Hour)), + }, + newCondition: corev1.NodeCondition{ + Type: corev1.NodeReady, + Status: corev1.ConditionFalse, + Reason: "TestReason", + Message: "Test message", + }, + expectedCondition: corev1.NodeCondition{ + Type: corev1.NodeReady, + Status: corev1.ConditionFalse, + Reason: "TestReason", + Message: "Test message", + }, + }, + { + name: "Update existing condition without status change", + existingCondition: &corev1.NodeCondition{ + Type: corev1.NodeReady, + Status: corev1.ConditionTrue, + LastTransitionTime: metav1.NewTime(time.Now().Add(-1 * time.Hour)), + LastHeartbeatTime: metav1.NewTime(time.Now().Add(-1 * time.Hour)), + }, + newCondition: corev1.NodeCondition{ + Type: corev1.NodeReady, + Status: corev1.ConditionTrue, + Reason: "UpdatedReason", + Message: "Updated message", + }, + expectedCondition: corev1.NodeCondition{ + Type: corev1.NodeReady, + Status: corev1.ConditionTrue, + Reason: "UpdatedReason", + Message: "Updated message", + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + conditions := []corev1.NodeCondition{*tc.existingCondition} + SetNodeStatusCondition(&conditions, tc.newCondition) + + assert.Equal(t, 1, len(conditions)) + updatedCondition := conditions[0] + + assert.Equal(t, tc.expectedCondition.Type, updatedCondition.Type) + assert.Equal(t, tc.expectedCondition.Status, updatedCondition.Status) + assert.Equal(t, tc.expectedCondition.Reason, updatedCondition.Reason) + assert.Equal(t, tc.expectedCondition.Message, updatedCondition.Message) + + if tc.existingCondition.Status != tc.newCondition.Status { + assert.True(t, updatedCondition.LastTransitionTime.After(tc.existingCondition.LastTransitionTime.Time)) + } else { + assert.Equal(t, tc.existingCondition.LastTransitionTime, updatedCondition.LastTransitionTime) + } + + assert.True(t, updatedCondition.LastHeartbeatTime.After(tc.existingCondition.LastHeartbeatTime.Time)) + }) + } +} diff --git a/pkg/util/annotation_test.go b/pkg/util/annotation_test.go index 84cdfbdd377c..1174391ada71 100644 --- a/pkg/util/annotation_test.go +++ b/pkg/util/annotation_test.go @@ -288,7 +288,7 @@ func TestRecordManagedAnnotations(t *testing.T) { }, }, { - name: "object has has annotations", + name: "object has annotations", object: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", @@ -322,7 +322,7 @@ func TestRecordManagedAnnotations(t *testing.T) { }, }, { - name: "object has has annotations and labels", + name: "object has annotations and labels", object: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", @@ -361,6 +361,47 @@ func TestRecordManagedAnnotations(t *testing.T) { }, }, }, + { + name: "object has recorded annotations and labels", + object: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "demo-deployment-1", + "annotations": map[string]interface{}{ + workv1alpha2.ManagedAnnotation: "foo,resourcetemplate.karmada.io/managed-annotations,resourcetemplate.karmada.io/managed-labels", + "foo": "foo", + }, + "labels": map[string]interface{}{ + "bar": "bar", + }, + }, + "spec": map[string]interface{}{ + "replicas": 2, + }, + }, + }, + expected: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "demo-deployment-1", + "annotations": map[string]interface{}{ + workv1alpha2.ManagedAnnotation: "foo,resourcetemplate.karmada.io/managed-annotations,resourcetemplate.karmada.io/managed-labels", + "foo": "foo", + }, + "labels": map[string]interface{}{ + "bar": "bar", + }, + }, + "spec": map[string]interface{}{ + "replicas": 2, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -425,3 +466,283 @@ func TestMergeAnnotation(t *testing.T) { }) } } + +func TestDedupeAndMergeAnnotations(t *testing.T) { + tests := []struct { + name string + existAnnotation map[string]string + newAnnotation map[string]string + expectedAnnotation map[string]string + }{ + { + name: "nil both annotation", + existAnnotation: nil, + newAnnotation: nil, + expectedAnnotation: nil, + }, + { + name: "nil existing annotation", + existAnnotation: nil, + newAnnotation: map[string]string{ + "newAnnotationKey": "newAnnotationValues", + }, + expectedAnnotation: map[string]string{ + "newAnnotationKey": "newAnnotationValues", + }, + }, + { + name: "nil new annotation", + existAnnotation: map[string]string{ + "existAnnotationKey": "existAnnotationValues", + }, + newAnnotation: nil, + expectedAnnotation: map[string]string{ + "existAnnotationKey": "existAnnotationValues", + }, + }, + { + name: "same annotation", + existAnnotation: map[string]string{ + "existAnnotationKey": "existAnnotationValues", + }, + newAnnotation: map[string]string{ + "existAnnotationKey": "existAnnotationValues", + }, + expectedAnnotation: map[string]string{ + "existAnnotationKey": "existAnnotationValues", + }, + }, + { + name: "different annotation", + existAnnotation: map[string]string{ + "existAnnotationKey": "existAnnotationValues", + }, + newAnnotation: map[string]string{ + "newAnnotationKey": "newAnnotationValues", + }, + expectedAnnotation: map[string]string{ + "existAnnotationKey": "existAnnotationValues", + "newAnnotationKey": "newAnnotationValues", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.existAnnotation = DedupeAndMergeAnnotations(tt.existAnnotation, tt.newAnnotation) + if !reflect.DeepEqual(tt.existAnnotation, tt.expectedAnnotation) { + t.Errorf("DedupeAndMergeAnnotations(), existAnnotation = %v, want %v", tt.existAnnotation, tt.expectedAnnotation) + } + }) + } +} + +func TestRemoveAnnotations(t *testing.T) { + type args struct { + obj *unstructured.Unstructured + keys []string + } + tests := []struct { + name string + args args + expected *unstructured.Unstructured + }{ + { + name: "empty keys", + args: args{ + obj: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "demo-deployment", + "annotations": map[string]interface{}{"foo": "bar"}, + }, + "spec": map[string]interface{}{ + "replicas": 2, + }, + }, + }, + keys: []string{}, + }, + expected: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "demo-deployment", + "annotations": map[string]interface{}{"foo": "bar"}, + }, + "spec": map[string]interface{}{ + "replicas": 2, + }, + }, + }, + }, + { + name: "nil object annotations", + args: args{ + obj: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "demo-deployment", + }, + "spec": map[string]interface{}{ + "replicas": 2, + }, + }, + }, + keys: []string{"foo"}, + }, + expected: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "demo-deployment", + }, + "spec": map[string]interface{}{ + "replicas": 2, + }, + }, + }, + }, + { + name: "same keys", + args: args{ + obj: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "demo-deployment", + "annotations": map[string]interface{}{"foo": "bar"}, + }, + "spec": map[string]interface{}{ + "replicas": 2, + }, + }, + }, + keys: []string{"foo"}, + }, + expected: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "demo-deployment", + "annotations": map[string]interface{}{}, + }, + "spec": map[string]interface{}{ + "replicas": 2, + }, + }, + }, + }, + { + name: "different keys", + args: args{ + obj: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "demo-deployment", + "annotations": map[string]interface{}{"foo": "bar"}, + }, + "spec": map[string]interface{}{ + "replicas": 2, + }, + }, + }, + keys: []string{"foo1"}, + }, + expected: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "demo-deployment", + "annotations": map[string]interface{}{"foo": "bar"}, + }, + "spec": map[string]interface{}{ + "replicas": 2, + }, + }, + }, + }, + { + name: "same keys of different length", + args: args{ + obj: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "demo-deployment", + "annotations": map[string]interface{}{"foo": "bar", "foo1": "bar1"}, + }, + "spec": map[string]interface{}{ + "replicas": 2, + }, + }, + }, + keys: []string{"foo", "foo1"}, + }, + expected: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "demo-deployment", + "annotations": map[string]interface{}{}, + }, + "spec": map[string]interface{}{ + "replicas": 2, + }, + }, + }, + }, + { + name: "different keys of different length", + args: args{ + obj: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "demo-deployment", + "annotations": map[string]interface{}{"foo": "bar", "foo1": "bar1"}, + }, + "spec": map[string]interface{}{ + "replicas": 2, + }, + }, + }, + keys: []string{"foo2", "foo3"}, + }, + expected: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "demo-deployment", + "annotations": map[string]interface{}{"foo": "bar", "foo1": "bar1"}, + }, + "spec": map[string]interface{}{ + "replicas": 2, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + RemoveAnnotations(tt.args.obj, tt.args.keys...) + if !reflect.DeepEqual(tt.args.obj, tt.expected) { + t.Errorf("RemoveAnnotations(), tt.args.obj = %v, want %v", tt.args.obj, tt.expected) + } + }) + } +} diff --git a/pkg/util/common_test.go b/pkg/util/common_test.go index 4135e28b280a..934064021b01 100644 --- a/pkg/util/common_test.go +++ b/pkg/util/common_test.go @@ -54,51 +54,74 @@ var ( ) func TestDiffKey(t *testing.T) { - t.Run("all old remove, all new added", func(t *testing.T) { - previous := map[string]sigMultiCluster{ - "kubefed": kubefed, - } - current := map[string]string{ - "karmada": "v1.6.0", - } - added, removed := DiffKey(previous, current) - if len(added) != 1 || added[0] != "karmada" { - t.Errorf("added = %v, want []string{\"karmada\"}", added) - } - if len(removed) != 1 || removed[0] != "kubefed" { - t.Errorf("removed = %v, want []string{\"kubefed\"}", removed) - } - }) - t.Run("no old, all new added", func(t *testing.T) { - previous := map[string]sigMultiCluster{} - current := map[string]string{ - "karmada": "v1.6.0", - } - added, removed := DiffKey(previous, current) - if len(added) != 1 || added[0] != "karmada" { - t.Errorf("added = %v, want []string{\"karmada\"}", added) - } - if len(removed) != 0 { - t.Errorf("removed = %v, want nil", removed) - } - }) - t.Run("removed, added and remained", func(t *testing.T) { - previous := map[string]sigMultiCluster{ - "kubefed": kubefed, - "virtual-kubelet": virtualKubelet, - } - current := map[string]string{ - "karmada": "v1.6.0", - "virtual-kubelet": virtualKubelet.Comment, - } - added, removed := DiffKey(previous, current) - if len(added) != 1 || added[0] != "karmada" { - t.Errorf("added = %v, want []string{\"karmada\"}", added) - } - if len(removed) != 1 || removed[0] != "kubefed" { - t.Errorf("removed = %v, want []string{\"kubefed\"}", removed) - } - }) + tests := []struct { + name string + previous map[string]sigMultiCluster + current map[string]string + expectedAdded []string + expectedRemoved []string + }{ + { + name: "all old remove, all new added", + previous: map[string]sigMultiCluster{ + "kubefed": kubefed, + }, + current: map[string]string{ + "karmada": "v1.6.0", + }, + expectedAdded: []string{"karmada"}, + expectedRemoved: []string{"kubefed"}, + }, + { + name: "no old, no new", + previous: nil, + current: nil, + expectedAdded: nil, + expectedRemoved: nil, + }, + { + name: "no old, all new added", + previous: nil, + current: map[string]string{ + "karmada": "v1.6.0", + }, + expectedAdded: []string{"karmada"}, + expectedRemoved: nil, + }, + { + name: "all old removed, no new", + previous: map[string]sigMultiCluster{ + "kubefed": kubefed, + }, + current: nil, + expectedAdded: nil, + expectedRemoved: []string{"kubefed"}, + }, + { + name: "removed, added and remained", + previous: map[string]sigMultiCluster{ + "kubefed": kubefed, + "virtual-kubelet": virtualKubelet, + }, + current: map[string]string{ + "karmada": "v1.6.0", + "virtual-kubelet": virtualKubelet.Comment, + }, + expectedAdded: []string{"karmada"}, + expectedRemoved: []string{"kubefed"}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + added, removed := DiffKey(tt.previous, tt.current) + if !reflect.DeepEqual(added, tt.expectedAdded) { + t.Errorf("added = %v, want %v", added, tt.expectedAdded) + } + if !reflect.DeepEqual(removed, tt.expectedRemoved) { + t.Errorf("removed = %v want %v", removed, tt.expectedRemoved) + } + }) + } } func TestStringerJoin(t *testing.T) { @@ -111,15 +134,33 @@ func TestStringerJoin(t *testing.T) { } func TestKeys(t *testing.T) { - mcs := map[string]sigMultiCluster{ - kubefed.Name: kubefed, - karmada.Name: karmada, + tests := []struct { + name string + mcs map[string]sigMultiCluster + expect []string + }{ + { + name: "keys exist", + mcs: map[string]sigMultiCluster{ + kubefed.Name: kubefed, + karmada.Name: karmada, + }, + expect: []string{kubefed.Name, karmada.Name}, + }, + { + name: "empty keys", + mcs: nil, + expect: nil, + }, } - got := Keys(mcs) - expect := []string{kubefed.Name, karmada.Name} - sort.Strings(got) - sort.Strings(expect) - if !reflect.DeepEqual(got, expect) { - t.Errorf("got = %v, want %v", got, expect) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := Keys(tt.mcs) + sort.Strings(got) + sort.Strings(tt.expect) + if !reflect.DeepEqual(got, tt.expect) { + t.Errorf("got = %v, want %v", got, tt.expect) + } + }) } } diff --git a/pkg/util/eventfilter/eventfilter_test.go b/pkg/util/eventfilter/eventfilter_test.go index bfaf27db95bd..8ed99cfd54e6 100644 --- a/pkg/util/eventfilter/eventfilter_test.go +++ b/pkg/util/eventfilter/eventfilter_test.go @@ -26,6 +26,7 @@ import ( "k8s.io/utils/ptr" workloadv1alpha1 "github.com/karmada-io/karmada/examples/customresourceinterpreter/apis/workload/v1alpha1" + policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1" "github.com/karmada-io/karmada/pkg/util/helper" ) @@ -196,6 +197,104 @@ func TestSpecificationChanged(t *testing.T) { }, wantChange: true, }, + { + name: "No change in Service", + oldObj: &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "123456", + ManagedFields: []metav1.ManagedFieldsEntry{{}}, + }, + Spec: corev1.ServiceSpec{ + Ports: []corev1.ServicePort{{Port: 80}}, + }, + }, + newObj: &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "123457", + ManagedFields: []metav1.ManagedFieldsEntry{{}, {}}, + }, + Spec: corev1.ServiceSpec{ + Ports: []corev1.ServicePort{{Port: 80}}, + }, + }, + wantChange: false, + }, + { + name: "Change in Service ports", + oldObj: &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "123456", + ManagedFields: []metav1.ManagedFieldsEntry{{}}, + }, + Spec: corev1.ServiceSpec{ + Ports: []corev1.ServicePort{{Port: 80}}, + }, + }, + newObj: &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "123457", + ManagedFields: []metav1.ManagedFieldsEntry{{}, {}}, + }, + Spec: corev1.ServiceSpec{ + Ports: []corev1.ServicePort{{Port: 8080}}, + }, + }, + wantChange: true, + }, + { + name: "Change in labels", + oldObj: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "123456", + Labels: map[string]string{"app": "v1"}, + }, + Data: map[string]string{"key": "value"}, + }, + newObj: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "123457", + Labels: map[string]string{"app": "v2"}, + }, + Data: map[string]string{"key": "value"}, + }, + wantChange: true, + }, + { + name: "Change in annotations", + oldObj: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "123456", + Annotations: map[string]string{"note": "v1"}, + }, + Data: map[string]string{"key": "value"}, + }, + newObj: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "123457", + Annotations: map[string]string{"note": "v2"}, + }, + Data: map[string]string{"key": "value"}, + }, + wantChange: true, + }, + { + name: "Change with user Karmada labels", + oldObj: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "123456", + Labels: map[string]string{policyv1alpha1.NamespaceSkipAutoPropagationLabel: "true"}, + }, + Data: map[string]string{"key": "value"}, + }, + newObj: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "123457", + Labels: map[string]string{policyv1alpha1.NamespaceSkipAutoPropagationLabel: "false"}, + }, + Data: map[string]string{"key": "value"}, + }, + wantChange: true, + }, } for _, tt := range tests { @@ -219,3 +318,85 @@ func TestSpecificationChanged(t *testing.T) { }) } } + +func TestResourceChangeByKarmada(t *testing.T) { + tests := []struct { + name string + oldObj interface{} + newObj interface{} + wantChangeByKarmada bool + }{ + { + name: "Change by Karmada", + oldObj: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "123456", + Labels: map[string]string{"app.karmada.io/managed": "true"}, + }, + Data: map[string]string{"key": "value"}, + }, + newObj: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "123457", + Labels: map[string]string{"app.karmada.io/managed": "false"}, + }, + Data: map[string]string{"key": "value"}, + }, + wantChangeByKarmada: true, + }, + { + name: "Change not by Karmada", + oldObj: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "123456", + Labels: map[string]string{"app": "v1"}, + }, + Data: map[string]string{"key": "value"}, + }, + newObj: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "123457", + Labels: map[string]string{"app": "v2"}, + }, + Data: map[string]string{"key": "value"}, + }, + wantChangeByKarmada: false, + }, + { + name: "Change in Karmada annotations", + oldObj: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "123456", + Annotations: map[string]string{"note.karmada.io/managed": "true"}, + }, + Data: map[string]string{"key": "value"}, + }, + newObj: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "123457", + Annotations: map[string]string{"note.karmada.io/managed": "false"}, + }, + Data: map[string]string{"key": "value"}, + }, + wantChangeByKarmada: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + oldUnstructured, err := helper.ToUnstructured(tt.oldObj) + if err != nil { + t.Fatalf("Failed to convert oldObj to unstructured: %v", err) + } + newUnstructured, err := helper.ToUnstructured(tt.newObj) + if err != nil { + t.Fatalf("Failed to convert newObj to unstructured: %v", err) + } + + got := ResourceChangeByKarmada(oldUnstructured, newUnstructured) + if got != tt.wantChangeByKarmada { + t.Errorf("ResourceChangeByKarmada() = %v, want %v", got, tt.wantChangeByKarmada) + } + }) + } +} diff --git a/pkg/util/fedinformer/handlers_test.go b/pkg/util/fedinformer/handlers_test.go new file mode 100644 index 000000000000..41ef2bb12f9c --- /dev/null +++ b/pkg/util/fedinformer/handlers_test.go @@ -0,0 +1,248 @@ +/* +Copyright 2024 The Karmada 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 fedinformer + +import ( + "reflect" + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/tools/cache" +) + +type TestObject struct { + metav1.TypeMeta + metav1.ObjectMeta + Spec string +} + +func (in *TestObject) DeepCopyObject() runtime.Object { + return &TestObject{ + TypeMeta: in.TypeMeta, + ObjectMeta: in.ObjectMeta, + Spec: in.Spec, + } +} + +type CustomResourceEventHandler struct { + handler cache.ResourceEventHandler +} + +func (c *CustomResourceEventHandler) OnAdd(obj interface{}, isInInitialList bool) { + if h, ok := c.handler.(interface{ OnAdd(interface{}, bool) }); ok { + h.OnAdd(obj, isInInitialList) + } else { + c.handler.OnAdd(obj, false) + } +} + +func (c *CustomResourceEventHandler) OnUpdate(oldObj, newObj interface{}) { + c.handler.OnUpdate(oldObj, newObj) +} + +func (c *CustomResourceEventHandler) OnDelete(obj interface{}) { + c.handler.OnDelete(obj) +} + +func TestNewHandlerOnAllEvents(t *testing.T) { + testCases := []struct { + name string + event string + input interface{} + expected runtime.Object + }{ + { + name: "Add event", + event: "add", + input: &TestObject{ObjectMeta: metav1.ObjectMeta{Name: "test-obj-add"}, Spec: "add"}, + expected: &TestObject{ObjectMeta: metav1.ObjectMeta{Name: "test-obj-add"}, Spec: "add"}, + }, + { + name: "Update event", + event: "update", + input: &TestObject{ObjectMeta: metav1.ObjectMeta{Name: "test-obj-update"}, Spec: "update"}, + expected: &TestObject{ObjectMeta: metav1.ObjectMeta{Name: "test-obj-update"}, Spec: "update"}, + }, + { + name: "Delete event", + event: "delete", + input: &TestObject{ObjectMeta: metav1.ObjectMeta{Name: "test-obj-delete"}, Spec: "delete"}, + expected: &TestObject{ObjectMeta: metav1.ObjectMeta{Name: "test-obj-delete"}, Spec: "delete"}, + }, + { + name: "Delete event with DeletedFinalStateUnknown", + event: "delete", + input: cache.DeletedFinalStateUnknown{Obj: &TestObject{ObjectMeta: metav1.ObjectMeta{Name: "test-obj-delete-unknown"}, Spec: "delete-unknown"}}, + expected: &TestObject{ObjectMeta: metav1.ObjectMeta{Name: "test-obj-delete-unknown"}, Spec: "delete-unknown"}, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + var calledWith runtime.Object + fn := func(obj interface{}) { + calledWith = obj.(runtime.Object) + } + + handler := &CustomResourceEventHandler{NewHandlerOnAllEvents(fn)} + + switch tc.event { + case "add": + handler.OnAdd(tc.input, false) + case "update": + oldObj := &TestObject{ObjectMeta: metav1.ObjectMeta{Name: "old-obj"}, Spec: "old"} + handler.OnUpdate(oldObj, tc.input) + case "delete": + handler.OnDelete(tc.input) + } + + if !reflect.DeepEqual(calledWith, tc.expected) { + t.Errorf("expected %v, got %v", tc.expected, calledWith) + } + }) + } +} + +func TestNewHandlerOnEvents(t *testing.T) { + testCases := []struct { + name string + event string + }{ + {"Add event", "add"}, + {"Update event", "update"}, + {"Delete event", "delete"}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + var addCalled, updateCalled, deleteCalled bool + addFunc := func(_ interface{}) { addCalled = true } + updateFunc := func(_, _ interface{}) { updateCalled = true } + deleteFunc := func(_ interface{}) { deleteCalled = true } + + handler := &CustomResourceEventHandler{NewHandlerOnEvents(addFunc, updateFunc, deleteFunc)} + + testObj := &TestObject{ObjectMeta: metav1.ObjectMeta{Name: "test-obj"}} + + switch tc.event { + case "add": + handler.OnAdd(testObj, false) + if !addCalled { + t.Error("AddFunc was not called") + } + case "update": + handler.OnUpdate(testObj, testObj) + if !updateCalled { + t.Error("UpdateFunc was not called") + } + case "delete": + handler.OnDelete(testObj) + if !deleteCalled { + t.Error("DeleteFunc was not called") + } + } + }) + } +} + +func TestNewFilteringHandlerOnAllEvents(t *testing.T) { + testCases := []struct { + name string + event string + input interface{} + expectedAdd bool + expectedUpdate bool + expectedDelete bool + }{ + { + name: "Add passing object", + event: "add", + input: &TestObject{ObjectMeta: metav1.ObjectMeta{Name: "passing-obj"}, Spec: "pass"}, + expectedAdd: true, + expectedUpdate: false, + expectedDelete: false, + }, + { + name: "Add failing object", + event: "add", + input: &TestObject{ObjectMeta: metav1.ObjectMeta{Name: "failing-obj"}, Spec: "fail"}, + expectedAdd: false, + expectedUpdate: false, + expectedDelete: false, + }, + { + name: "Update to passing object", + event: "update", + input: &TestObject{ObjectMeta: metav1.ObjectMeta{Name: "passing-obj"}, Spec: "pass"}, + expectedAdd: false, + expectedUpdate: true, + expectedDelete: false, + }, + { + name: "Update to failing object", + event: "update", + input: &TestObject{ObjectMeta: metav1.ObjectMeta{Name: "failing-obj"}, Spec: "fail"}, + expectedAdd: false, + expectedUpdate: false, + expectedDelete: true, + }, + { + name: "Delete passing object", + event: "delete", + input: &TestObject{ObjectMeta: metav1.ObjectMeta{Name: "passing-obj"}, Spec: "pass"}, + expectedAdd: false, + expectedUpdate: false, + expectedDelete: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + var addCalled, updateCalled, deleteCalled bool + addFunc := func(_ interface{}) { addCalled = true } + updateFunc := func(_, _ interface{}) { updateCalled = true } + deleteFunc := func(_ interface{}) { deleteCalled = true } + + filterFunc := func(obj interface{}) bool { + testObj := obj.(*TestObject) + return testObj.Spec == "pass" + } + + handler := NewFilteringHandlerOnAllEvents(filterFunc, addFunc, updateFunc, deleteFunc) + + switch tc.event { + case "add": + handler.OnAdd(tc.input, false) + case "update": + handler.OnUpdate(&TestObject{Spec: "pass"}, tc.input) + case "delete": + handler.OnDelete(tc.input) + } + + if addCalled != tc.expectedAdd { + t.Errorf("AddFunc called: %v, expected: %v", addCalled, tc.expectedAdd) + } + if updateCalled != tc.expectedUpdate { + t.Errorf("UpdateFunc called: %v, expected: %v", updateCalled, tc.expectedUpdate) + } + if deleteCalled != tc.expectedDelete { + t.Errorf("DeleteFunc called: %v, expected: %v", deleteCalled, tc.expectedDelete) + } + }) + } +} diff --git a/pkg/util/fedinformer/keys/keys_test.go b/pkg/util/fedinformer/keys/keys_test.go index c9ec7178f65c..64c92b00d39d 100644 --- a/pkg/util/fedinformer/keys/keys_test.go +++ b/pkg/util/fedinformer/keys/keys_test.go @@ -73,6 +73,38 @@ var ( Name: "bar", }, } + podWithEmptyGroup = &corev1.Pod{ + TypeMeta: metav1.TypeMeta{ + Kind: "Pod", + APIVersion: "", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "foo", + Name: "bar", + }, + } + + podWithEmptyKind = &corev1.Pod{ + TypeMeta: metav1.TypeMeta{ + Kind: "", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "foo", + Name: "bar", + }, + } + + secretWithEmptyNamespace = &corev1.Secret{ + TypeMeta: metav1.TypeMeta{ + Kind: "Secret", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "", + Name: "bar", + }, + } ) func TestClusterWideKeyFunc(t *testing.T) { @@ -121,6 +153,22 @@ func TestClusterWideKeyFunc(t *testing.T) { object: deploymentObj, expectErr: true, }, + { + name: "resource with empty group", + object: podWithEmptyGroup, + expectErr: true, + }, + { + name: "resource with empty kind", + object: podWithEmptyKind, + expectErr: true, + }, + { + name: "resource with empty namespace", + object: secretWithEmptyNamespace, + expectErr: false, + expectKeyStr: "v1, kind=Secret, bar", + }, } for _, test := range tests { diff --git a/pkg/util/fedinformer/typedmanager/multi-cluster-manager_test.go b/pkg/util/fedinformer/typedmanager/multi-cluster-manager_test.go new file mode 100644 index 000000000000..a18f72fc2d71 --- /dev/null +++ b/pkg/util/fedinformer/typedmanager/multi-cluster-manager_test.go @@ -0,0 +1,160 @@ +/* +Copyright 2024 The Karmada 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 typedmanager + +import ( + "testing" + "time" + + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/kubernetes/fake" + "k8s.io/client-go/tools/cache" + + "github.com/karmada-io/karmada/pkg/util/fedinformer" +) + +func TestMultiClusterInformerManager(t *testing.T) { + stopCh := make(chan struct{}) + defer close(stopCh) + + transforms := map[schema.GroupVersionResource]cache.TransformFunc{ + nodeGVR: fedinformer.NodeTransformFunc, + podGVR: fedinformer.PodTransformFunc, + } + + manager := NewMultiClusterInformerManager(stopCh, transforms) + + t.Run("ForCluster", func(_ *testing.T) { + cluster := "test-cluster" + client := fake.NewSimpleClientset() + resync := 10 * time.Second + + singleManager := manager.ForCluster(cluster, client, resync) + if singleManager == nil { + t.Fatalf("ForCluster() returned nil") + } + + if !manager.IsManagerExist(cluster) { + t.Fatalf("IsManagerExist() returned false for existing cluster") + } + }) + + t.Run("GetSingleClusterManager", func(t *testing.T) { + cluster := "test-cluster" + singleManager := manager.GetSingleClusterManager(cluster) + if singleManager == nil { + t.Fatalf("GetSingleClusterManager() returned nil for existing cluster") + } + + nonExistentCluster := "non-existent-cluster" + singleManager = manager.GetSingleClusterManager(nonExistentCluster) + if singleManager != nil { + t.Fatalf("GetSingleClusterManager() returned non-nil for non-existent cluster") + } + }) + + t.Run("Start and Stop", func(t *testing.T) { + cluster := "test-cluster-2" + client := fake.NewSimpleClientset() + resync := 10 * time.Second + + manager.ForCluster(cluster, client, resync) + manager.Start(cluster) + + manager.Stop(cluster) + + if manager.IsManagerExist(cluster) { + t.Fatalf("IsManagerExist() returned true after Stop()") + } + }) + + t.Run("WaitForCacheSync", func(t *testing.T) { + cluster := "test-cluster-3" + client := fake.NewSimpleClientset() + resync := 10 * time.Millisecond + singleManager := manager.ForCluster(cluster, client, resync) + manager.Start(cluster) + + _, _ = singleManager.Lister(podGVR) + _, _ = singleManager.Lister(nodeGVR) + + time.Sleep(100 * time.Millisecond) + + result := manager.WaitForCacheSync(cluster) + if result == nil { + t.Fatalf("WaitForCacheSync() returned nil result") + } + + for gvr, synced := range result { + t.Logf("Resource %v synced: %v", gvr, synced) + } + + manager.Stop(cluster) + }) + + t.Run("WaitForCacheSyncWithTimeout", func(t *testing.T) { + cluster := "test-cluster-4" + client := fake.NewSimpleClientset() + resync := 10 * time.Millisecond + singleManager := manager.ForCluster(cluster, client, resync) + manager.Start(cluster) + + _, _ = singleManager.Lister(podGVR) + _, _ = singleManager.Lister(nodeGVR) + + timeout := 100 * time.Millisecond + result := manager.WaitForCacheSyncWithTimeout(cluster, timeout) + if result == nil { + t.Fatalf("WaitForCacheSyncWithTimeout() returned nil result") + } + + for gvr, synced := range result { + t.Logf("Resource %v synced: %v", gvr, synced) + } + + manager.Stop(cluster) + }) + + t.Run("WaitForCacheSync and WaitForCacheSyncWithTimeout with non-existent cluster", func(t *testing.T) { + nonExistentCluster := "non-existent-cluster" + + result1 := manager.WaitForCacheSync(nonExistentCluster) + if result1 != nil { + t.Fatalf("WaitForCacheSync() returned non-nil for non-existent cluster") + } + + result2 := manager.WaitForCacheSyncWithTimeout(nonExistentCluster, 1*time.Second) + if result2 != nil { + t.Fatalf("WaitForCacheSyncWithTimeout() returned non-nil for non-existent cluster") + } + }) +} + +func TestGetInstance(t *testing.T) { + instance1 := GetInstance() + instance2 := GetInstance() + + if instance1 != instance2 { + t.Fatalf("GetInstance() returned different instances") + } +} + +func TestStopInstance(_ *testing.T) { + StopInstance() + // Ensure StopInstance doesn't panic + StopInstance() +} diff --git a/pkg/util/fedinformer/typedmanager/single-cluster-manager_test.go b/pkg/util/fedinformer/typedmanager/single-cluster-manager_test.go new file mode 100644 index 000000000000..257739645301 --- /dev/null +++ b/pkg/util/fedinformer/typedmanager/single-cluster-manager_test.go @@ -0,0 +1,183 @@ +/* +Copyright 2024 The Karmada 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 typedmanager + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/kubernetes/fake" + "k8s.io/client-go/tools/cache" +) + +func TestSingleClusterInformerManager(t *testing.T) { + client := fake.NewSimpleClientset() + stopCh := make(chan struct{}) + defer close(stopCh) + + manager := NewSingleClusterInformerManager(client, 0, stopCh, nil) + + t.Run("ForResource", func(t *testing.T) { + handler := &testResourceEventHandler{} + err := manager.ForResource(podGVR, handler) + require.NoError(t, err, "ForResource failed") + + assert.True(t, manager.IsHandlerExist(podGVR, handler), "Handler should exist for podGVR") + }) + + t.Run("Lister", func(t *testing.T) { + lister, err := manager.Lister(podGVR) + require.NoError(t, err, "Lister failed") + assert.NotNil(t, lister, "Lister should not be nil") + }) + + t.Run("Start and Stop", func(_ *testing.T) { + manager.Start() + // Sleep to allow informers to start + time.Sleep(100 * time.Millisecond) + manager.Stop() + }) + + t.Run("WaitForCacheSync", func(t *testing.T) { + manager.Start() + defer manager.Stop() + + synced := manager.WaitForCacheSync() + assert.NotEmpty(t, synced, "WaitForCacheSync should return non-empty map") + }) + + t.Run("WaitForCacheSyncWithTimeout", func(t *testing.T) { + manager.Start() + defer manager.Stop() + + synced := manager.WaitForCacheSyncWithTimeout(5 * time.Second) + assert.NotEmpty(t, synced, "WaitForCacheSyncWithTimeout should return non-empty map") + }) + + t.Run("Context", func(t *testing.T) { + ctx := manager.Context() + assert.NotNil(t, ctx, "Context should not be nil") + }) + + t.Run("GetClient", func(t *testing.T) { + c := manager.GetClient() + assert.NotNil(t, c, "GetClient should not return nil") + }) +} + +func TestSingleClusterInformerManagerWithTransformFunc(t *testing.T) { + client := fake.NewSimpleClientset() + stopCh := make(chan struct{}) + defer close(stopCh) + + transformFunc := func(i interface{}) (interface{}, error) { + return i, nil + } + + transformFuncs := map[schema.GroupVersionResource]cache.TransformFunc{ + podGVR: transformFunc, + } + + manager := NewSingleClusterInformerManager(client, 0, stopCh, transformFuncs) + + t.Run("ForResourceWithTransform", func(t *testing.T) { + handler := &testResourceEventHandler{} + err := manager.ForResource(podGVR, handler) + require.NoError(t, err, "ForResource with transform failed") + }) +} + +func TestSingleClusterInformerManagerMultipleHandlers(t *testing.T) { + client := fake.NewSimpleClientset() + stopCh := make(chan struct{}) + defer close(stopCh) + + manager := NewSingleClusterInformerManager(client, 0, stopCh, nil) + + handler1 := &testResourceEventHandler{} + handler2 := &testResourceEventHandler{} + + t.Run("MultipleHandlers", func(t *testing.T) { + err := manager.ForResource(podGVR, handler1) + require.NoError(t, err, "ForResource failed for handler1") + + err = manager.ForResource(podGVR, handler2) + require.NoError(t, err, "ForResource failed for handler2") + + assert.True(t, manager.IsHandlerExist(podGVR, handler1), "Handler1 should exist for podGVR") + assert.True(t, manager.IsHandlerExist(podGVR, handler2), "Handler2 should exist for podGVR") + }) +} + +func TestSingleClusterInformerManagerDifferentResources(t *testing.T) { + client := fake.NewSimpleClientset() + stopCh := make(chan struct{}) + defer close(stopCh) + + manager := NewSingleClusterInformerManager(client, 0, stopCh, nil) + + t.Run("DifferentResources", func(t *testing.T) { + podHandler := &testResourceEventHandler{} + err := manager.ForResource(podGVR, podHandler) + require.NoError(t, err, "ForResource failed for podGVR") + + nodeHandler := &testResourceEventHandler{} + err = manager.ForResource(nodeGVR, nodeHandler) + require.NoError(t, err, "ForResource failed for nodeGVR") + + assert.True(t, manager.IsHandlerExist(podGVR, podHandler), "PodHandler should exist for podGVR") + assert.True(t, manager.IsHandlerExist(nodeGVR, nodeHandler), "NodeHandler should exist for nodeGVR") + }) +} + +func TestIsInformerSynced(t *testing.T) { + client := fake.NewSimpleClientset() + stopCh := make(chan struct{}) + defer close(stopCh) + manager := NewSingleClusterInformerManager(client, 0, stopCh, nil) + + assert.False(t, manager.IsInformerSynced(podGVR)) + assert.False(t, manager.IsInformerSynced(nodeGVR)) + + handler := &testResourceEventHandler{} + err := manager.ForResource(podGVR, handler) + require.NoError(t, err) + err = manager.ForResource(nodeGVR, handler) + require.NoError(t, err) + + manager.Start() + defer manager.Stop() + + synced := manager.WaitForCacheSyncWithTimeout(5 * time.Second) + + assert.True(t, synced[podGVR], "Pod informer should be synced") + assert.True(t, synced[nodeGVR], "Node informer should be synced") + + time.Sleep(100 * time.Millisecond) + + assert.True(t, manager.IsInformerSynced(podGVR), "Pod informer should be reported as synced") + assert.True(t, manager.IsInformerSynced(nodeGVR), "Node informer should be reported as synced") +} + +type testResourceEventHandler struct{} + +func (t *testResourceEventHandler) OnAdd(_ interface{}, _ bool) {} +func (t *testResourceEventHandler) OnUpdate(_, _ interface{}) {} +func (t *testResourceEventHandler) OnDelete(_ interface{}) {} diff --git a/pkg/util/helper/binding.go b/pkg/util/helper/binding.go index 5f85a1c8acc8..04e2a02b5de1 100644 --- a/pkg/util/helper/binding.go +++ b/pkg/util/helper/binding.go @@ -194,9 +194,9 @@ func ObtainBindingSpecExistingClusters(bindingSpec workv1alpha2.ResourceBindingS // FindOrphanWorks retrieves all works that labeled with current binding(ResourceBinding or ClusterResourceBinding) objects, // then pick the works that not meet current binding declaration. -func FindOrphanWorks(c client.Client, bindingNamespace, bindingName, bindingID string, expectClusters sets.Set[string]) ([]workv1alpha1.Work, error) { +func FindOrphanWorks(ctx context.Context, c client.Client, bindingNamespace, bindingName, bindingID string, expectClusters sets.Set[string]) ([]workv1alpha1.Work, error) { var needJudgeWorks []workv1alpha1.Work - workList, err := GetWorksByBindingID(c, bindingID, bindingNamespace != "") + workList, err := GetWorksByBindingID(ctx, c, bindingID, bindingNamespace != "") if err != nil { klog.Errorf("Failed to get works by binding object (%s/%s): %v", bindingNamespace, bindingName, err) return nil, err @@ -219,10 +219,10 @@ func FindOrphanWorks(c client.Client, bindingNamespace, bindingName, bindingID s } // RemoveOrphanWorks will remove orphan works. -func RemoveOrphanWorks(c client.Client, works []workv1alpha1.Work) error { +func RemoveOrphanWorks(ctx context.Context, c client.Client, works []workv1alpha1.Work) error { var errs []error for workIndex, work := range works { - err := c.Delete(context.TODO(), &works[workIndex]) + err := c.Delete(ctx, &works[workIndex]) if err != nil { klog.Errorf("Failed to delete orphan work %s/%s, err is %v", work.GetNamespace(), work.GetName(), err) errs = append(errs, err) @@ -238,6 +238,7 @@ func RemoveOrphanWorks(c client.Client, works []workv1alpha1.Work) error { // We should abide by the principle of making a deep copy first and then modifying it. // See issue: https://github.com/karmada-io/karmada/issues/3878. func FetchResourceTemplate( + ctx context.Context, dynamicClient dynamic.Interface, informerManager genericmanager.SingleClusterInformerManager, restMapper meta.RESTMapper, @@ -261,7 +262,7 @@ func FetchResourceTemplate( // fall back to call api server in case the cache has not been synchronized yet klog.Warningf("Failed to get resource template (%s/%s/%s) from cache, Error: %v. Fall back to call api server.", resource.Kind, resource.Namespace, resource.Name, err) - object, err = dynamicClient.Resource(gvr).Namespace(resource.Namespace).Get(context.TODO(), resource.Name, metav1.GetOptions{}) + object, err = dynamicClient.Resource(gvr).Namespace(resource.Namespace).Get(ctx, resource.Name, metav1.GetOptions{}) if err != nil { klog.Errorf("Failed to get resource template (%s/%s/%s) from api server, Error: %v", resource.Kind, resource.Namespace, resource.Name, err) @@ -345,8 +346,8 @@ func GetResourceBindings(c client.Client, ls labels.Set) (*workv1alpha2.Resource } // DeleteWorks will delete all Work objects by labels. -func DeleteWorks(c client.Client, namespace, name, bindingID string) error { - workList, err := GetWorksByBindingID(c, bindingID, namespace != "") +func DeleteWorks(ctx context.Context, c client.Client, namespace, name, bindingID string) error { + workList, err := GetWorksByBindingID(ctx, c, bindingID, namespace != "") if err != nil { klog.Errorf("Failed to get works by (Cluster)ResourceBinding(%s/%s) : %v", namespace, name, err) return err @@ -354,7 +355,7 @@ func DeleteWorks(c client.Client, namespace, name, bindingID string) error { var errs []error for index, work := range workList.Items { - if err := c.Delete(context.TODO(), &workList.Items[index]); err != nil { + if err := c.Delete(ctx, &workList.Items[index]); err != nil { if apierrors.IsNotFound(err) { continue } diff --git a/pkg/util/helper/binding_test.go b/pkg/util/helper/binding_test.go index 7bb89c3e0024..4114aa9eff3c 100644 --- a/pkg/util/helper/binding_test.go +++ b/pkg/util/helper/binding_test.go @@ -553,7 +553,7 @@ func TestFindOrphanWorks(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := FindOrphanWorks(tt.args.c, tt.args.bindingNamespace, tt.args.bindingName, tt.args.bindingID, tt.args.expectClusters) + got, err := FindOrphanWorks(context.Background(), tt.args.c, tt.args.bindingNamespace, tt.args.bindingName, tt.args.bindingID, tt.args.expectClusters) if (err != nil) != tt.wantErr { t.Errorf("FindOrphanWorks() error = %v, wantErr %v", err, tt.wantErr) return @@ -608,7 +608,7 @@ func TestRemoveOrphanWorks(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := RemoveOrphanWorks(tt.args.c, tt.args.works); (err != nil) != tt.wantErr { + if err := RemoveOrphanWorks(context.Background(), tt.args.c, tt.args.works); (err != nil) != tt.wantErr { t.Errorf("RemoveOrphanWorks() error = %v, wantErr %v", err, tt.wantErr) } got := &workv1alpha1.WorkList{} @@ -806,7 +806,7 @@ func TestFetchWorkload(t *testing.T) { t.Run(tt.name, func(t *testing.T) { stopCh := make(chan struct{}) mgr := tt.args.informerManager(stopCh) - got, err := FetchResourceTemplate(tt.args.dynamicClient, mgr, tt.args.restMapper, tt.args.resource) + got, err := FetchResourceTemplate(context.TODO(), tt.args.dynamicClient, mgr, tt.args.restMapper, tt.args.resource) if (err != nil) != tt.wantErr { t.Errorf("FetchResourceTemplate() error = %v, wantErr %v", err, tt.wantErr) return @@ -1044,11 +1044,11 @@ func TestDeleteWorkByRBNamespaceAndName(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := DeleteWorks(tt.args.c, tt.args.namespace, tt.args.name, tt.args.bindingID); (err != nil) != tt.wantErr { + if err := DeleteWorks(context.Background(), tt.args.c, tt.args.namespace, tt.args.name, tt.args.bindingID); (err != nil) != tt.wantErr { t.Errorf("DeleteWorks() error = %v, wantErr %v", err, tt.wantErr) } list := &workv1alpha1.WorkList{} - if err := tt.args.c.List(context.TODO(), list); err != nil { + if err := tt.args.c.List(context.Background(), list); err != nil { t.Error(err) return } diff --git a/pkg/util/helper/mcs.go b/pkg/util/helper/mcs.go index 55a9c638c8aa..1a32e349c40b 100644 --- a/pkg/util/helper/mcs.go +++ b/pkg/util/helper/mcs.go @@ -34,11 +34,11 @@ import ( ) // CreateOrUpdateEndpointSlice creates a EndpointSlice object if not exist, or updates if it already exists. -func CreateOrUpdateEndpointSlice(client client.Client, endpointSlice *discoveryv1.EndpointSlice) error { +func CreateOrUpdateEndpointSlice(ctx context.Context, client client.Client, endpointSlice *discoveryv1.EndpointSlice) error { runtimeObject := endpointSlice.DeepCopy() var operationResult controllerutil.OperationResult err := retry.RetryOnConflict(retry.DefaultRetry, func() (err error) { - operationResult, err = controllerutil.CreateOrUpdate(context.TODO(), client, runtimeObject, func() error { + operationResult, err = controllerutil.CreateOrUpdate(ctx, client, runtimeObject, func() error { runtimeObject.AddressType = endpointSlice.AddressType runtimeObject.Endpoints = endpointSlice.Endpoints runtimeObject.Labels = endpointSlice.Labels @@ -75,7 +75,7 @@ func GetEndpointSlices(c client.Client, ls labels.Set) (*discoveryv1.EndpointSli } // DeleteEndpointSlice will delete all EndpointSlice objects by labels. -func DeleteEndpointSlice(c client.Client, selector labels.Set) error { +func DeleteEndpointSlice(ctx context.Context, c client.Client, selector labels.Set) error { endpointSliceList, err := GetEndpointSlices(c, selector) if err != nil { if apierrors.IsNotFound(err) { @@ -87,7 +87,7 @@ func DeleteEndpointSlice(c client.Client, selector labels.Set) error { var errs []error for index, work := range endpointSliceList.Items { - if err := c.Delete(context.TODO(), &endpointSliceList.Items[index]); err != nil { + if err := c.Delete(ctx, &endpointSliceList.Items[index]); err != nil { klog.Errorf("Failed to delete endpointslice(%s/%s): %v", work.Namespace, work.Name, err) errs = append(errs, err) } diff --git a/pkg/util/helper/mcs_test.go b/pkg/util/helper/mcs_test.go index 2839eebe315a..8fd874f09ed8 100644 --- a/pkg/util/helper/mcs_test.go +++ b/pkg/util/helper/mcs_test.go @@ -161,7 +161,7 @@ func TestCreateOrUpdateEndpointSlice(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := CreateOrUpdateEndpointSlice(tt.args.client, tt.args.endpointSlice); (err != nil) != tt.wantErr { + if err := CreateOrUpdateEndpointSlice(context.Background(), tt.args.client, tt.args.endpointSlice); (err != nil) != tt.wantErr { t.Errorf("CreateOrUpdateEndpointSlice() error = %v, wantErr %v", err, tt.wantErr) return } @@ -206,7 +206,7 @@ func TestDeleteEndpointSlice(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := DeleteEndpointSlice(tt.args.c, tt.args.selector); (err != nil) != tt.wantErr { + if err := DeleteEndpointSlice(context.Background(), tt.args.c, tt.args.selector); (err != nil) != tt.wantErr { t.Errorf("DeleteEndpointSlice() error = %v, wantErr %v", err, tt.wantErr) } list := &discoveryv1.EndpointSliceList{} diff --git a/pkg/util/helper/patch.go b/pkg/util/helper/patch.go index 6cd655e646ba..89f9f798376a 100644 --- a/pkg/util/helper/patch.go +++ b/pkg/util/helper/patch.go @@ -19,28 +19,10 @@ package helper import ( "encoding/json" "fmt" - "reflect" jsonpatch "github.com/evanphx/json-patch/v5" ) -// RFC6902 JSONPatch operations -const ( - JSONPatchOPAdd = "add" - JSONPatchOPReplace = "replace" - JSONPatchOPRemove = "remove" - JSONPatchOPMove = "move" - JSONPatchOPCopy = "copy" - JSONPatchOPTest = "test" -) - -type jsonPatch struct { - OP string `json:"op"` - From string `json:"from,omitempty"` - Path string `json:"path"` - Value interface{} `json:"value,omitempty"` -} - // GenMergePatch will return a merge patch document capable of converting the // original object to the modified object. // The merge patch format is primarily intended for use with the HTTP PATCH method @@ -84,40 +66,3 @@ func GenFieldMergePatch(fieldName string, originField interface{}, modifiedField patchBytes = append([]byte(`{"`+fieldName+`":`), patchBytes...) return patchBytes, nil } - -// GenReplaceFieldJSONPatch returns the RFC6902 JSONPatch array as []byte, which is used to simply -// add/replace/delete certain JSON **Object** field. -func GenReplaceFieldJSONPatch(path string, originalFieldValue, newFieldValue interface{}) ([]byte, error) { - if reflect.DeepEqual(originalFieldValue, newFieldValue) { - return nil, nil - } - if newFieldValue == nil { - return GenJSONPatch(JSONPatchOPRemove, "", path, nil) - } - // The implementation of "add" and "replace" for JSON objects is actually the same - // in "github.com/evanphx/json-patch/v5", which is used by Karmada and K8s. - // We implemented it here just to follow the RFC6902. - if originalFieldValue == nil { - return GenJSONPatch(JSONPatchOPAdd, "", path, newFieldValue) - } - return GenJSONPatch(JSONPatchOPReplace, "", path, newFieldValue) -} - -// GenJSONPatch return JSONPatch array as []byte according to RFC6902 -func GenJSONPatch(op, from, path string, value interface{}) ([]byte, error) { - jp := jsonPatch{ - OP: op, - Path: path, - } - switch op { - case JSONPatchOPAdd, JSONPatchOPReplace, JSONPatchOPTest: - jp.Value = value - case JSONPatchOPMove, JSONPatchOPCopy: - jp.From = from - case JSONPatchOPRemove: - default: - return nil, fmt.Errorf("unrecognized JSONPatch OP: %s", op) - } - - return json.Marshal([]jsonPatch{jp}) -} diff --git a/pkg/util/helper/patch_test.go b/pkg/util/helper/patch_test.go index 13ec3f6db4b9..9b4572b93f67 100644 --- a/pkg/util/helper/patch_test.go +++ b/pkg/util/helper/patch_test.go @@ -17,12 +17,8 @@ limitations under the License. package helper import ( - "encoding/json" - "fmt" - "math" "testing" - appsv1 "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" @@ -126,277 +122,3 @@ func TestGenMergePatch(t *testing.T) { }) } } - -func TestGenJSONPatch(t *testing.T) { - type args struct { - op string - from string - path string - value interface{} - } - tests := []struct { - name string - args args - want string - wantErr bool - }{ - { - name: "add object field", - args: args{ - op: "add", - path: "/abc", - value: 1, - }, - want: `[{"op":"add","path":"/abc","value":1}]`, - wantErr: false, - }, - { - name: "replace object field", - args: args{ - op: "replace", - path: "/abc", - value: 1, - }, - want: `[{"op":"replace","path":"/abc","value":1}]`, - wantErr: false, - }, - { - name: "remove object field, redundant args will be ignored", - args: args{ - op: "remove", - from: "123", - path: "/abc", - value: 1, - }, - want: `[{"op":"remove","path":"/abc"}]`, - wantErr: false, - }, - { - name: "move object field", - args: args{ - op: "move", - from: "/abc", - path: "/123", - }, - want: `[{"op":"move","from":"/abc","path":"/123"}]`, - wantErr: false, - }, - { - name: "copy object field, redundant array value will be ignored", - args: args{ - op: "copy", - from: "/123", - path: "/abc", - value: []interface{}{1, "a", false, 4.5}, - }, - want: `[{"op":"copy","from":"/123","path":"/abc"}]`, - wantErr: false, - }, - { - name: "replace object field, input string typed number", - args: args{ - op: "replace", - path: "/abc", - value: "1", - }, - want: `[{"op":"replace","path":"/abc","value":"1"}]`, - wantErr: false, - }, - { - name: "replace object field, input invalid type", - args: args{ - op: "replace", - path: "/abc", - value: make(chan int), - }, - want: "", - wantErr: true, - }, - { - name: "replace object field, input invalid value", - args: args{ - op: "replace", - path: "/abc", - value: math.Inf(1), - }, - want: "", - wantErr: true, - }, - { - name: "replace object field, input struct value", - args: args{ - op: "replace", - path: "/abc", - value: struct { - A string - B int - C float64 - D bool - }{"a", 1, 1.2, true}, - }, - want: `[{"op":"replace","path":"/abc","value":{"A":"a","B":1,"C":1.2,"D":true}}]`, - wantErr: false, - }, - { - name: "test object field, input array value", - args: args{ - op: "test", - path: "/abc", - value: []interface{}{1, "a", false, 4.5}, - }, - want: `[{"op":"test","path":"/abc","value":[1,"a",false,4.5]}]`, - wantErr: false, - }, - { - name: "move object field, input invalid path, but we won't verify it", - args: args{ - op: "move", - from: "123", - path: "abc", - }, - want: `[{"op":"move","from":"123","path":"abc"}]`, - wantErr: false, - }, - { - name: "input invalid op", - args: args{ - op: "whatever", - path: "/abc", - }, - want: "", - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - patchBytes, err := GenJSONPatch(tt.args.op, tt.args.from, tt.args.path, tt.args.value) - if tt.wantErr != (err != nil) { - t.Errorf("wantErr: %v, but got err: %v", tt.wantErr, err) - } - if tt.want != string(patchBytes) { - t.Errorf("want: %s, but got: %s", tt.want, patchBytes) - } - }) - } -} - -func TestGenReplaceFieldJSONPatch(t *testing.T) { - originalObj := &appsv1.Deployment{Status: appsv1.DeploymentStatus{ - ObservedGeneration: 1, - Replicas: 1, - UpdatedReplicas: 1, - ReadyReplicas: 1, - AvailableReplicas: 1, - }} - newObj := originalObj.DeepCopy() - newObj.Status = appsv1.DeploymentStatus{ - ObservedGeneration: 2, - Replicas: 2, - UpdatedReplicas: 2, - ReadyReplicas: 2, - AvailableReplicas: 2, - } - newStatusJSON, _ := json.Marshal(newObj.Status) - pathStatus := "/status" - type args struct { - path string - originalFieldValue interface{} - newFieldValue interface{} - } - tests := []struct { - name string - args args - want func() ([]byte, error) - }{ - { - name: "return nil when no patch is needed", - args: args{ - path: pathStatus, - originalFieldValue: originalObj.Status, - newFieldValue: originalObj.Status, - }, - want: func() ([]byte, error) { - return nil, nil - }, - }, - { - name: "return add JSONPatch when field in original obj is nil", - args: args{ - path: pathStatus, - originalFieldValue: nil, - newFieldValue: newObj.Status, - }, - want: func() ([]byte, error) { - return GenJSONPatch(JSONPatchOPAdd, "", pathStatus, newObj.Status) - }, - }, - { - name: "e2e return add JSONPatch when field in original obj is nil", - args: args{ - path: pathStatus, - originalFieldValue: nil, - newFieldValue: newObj.Status, - }, - want: func() ([]byte, error) { - return []byte(fmt.Sprintf(`[{"op":"add","path":"%s","value":%s}]`, pathStatus, newStatusJSON)), nil - }, - }, - { - name: "return replace JSONPatch when field in original obj in non-nil, whatever what's in the original field", - args: args{ - path: pathStatus, - originalFieldValue: originalObj.Status, - newFieldValue: newObj.Status, - }, - want: func() ([]byte, error) { - return GenJSONPatch(JSONPatchOPReplace, "", pathStatus, newObj.Status) - }, - }, - { - name: "e2e return replace JSONPatch when field in original obj in non-nil, whatever what's in the original field", - args: args{ - path: pathStatus, - originalFieldValue: originalObj.Status, - newFieldValue: newObj.Status, - }, - want: func() ([]byte, error) { - return []byte(fmt.Sprintf(`[{"op":"replace","path":"%s","value":%s}]`, pathStatus, newStatusJSON)), nil - }, - }, - { - name: "return remove JSONPatch when field in new obj is nil", - args: args{ - path: pathStatus, - originalFieldValue: originalObj.Status, - newFieldValue: nil, - }, - want: func() ([]byte, error) { - return GenJSONPatch(JSONPatchOPRemove, "", pathStatus, nil) - }, - }, - { - name: "e2e return remove JSONPatch when field in new obj is nil", - args: args{ - path: pathStatus, - originalFieldValue: originalObj.Status, - newFieldValue: nil, - }, - want: func() ([]byte, error) { - return []byte(fmt.Sprintf(`[{"op":"remove","path":"%s"}]`, pathStatus)), nil - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := GenReplaceFieldJSONPatch(tt.args.path, tt.args.originalFieldValue, tt.args.newFieldValue) - want, wantErr := tt.want() - - if fmt.Sprint(wantErr) != fmt.Sprint(err) { - t.Errorf("wantErr: %s, but got err: %s", fmt.Sprint(wantErr), fmt.Sprint(err)) - } - if string(want) != string(got) { - t.Errorf("\nwant: %s\nbut got: %s\n", want, got) - } - }) - } -} diff --git a/pkg/util/helper/work.go b/pkg/util/helper/work.go index b2e24e6b4049..c5956270e585 100644 --- a/pkg/util/helper/work.go +++ b/pkg/util/helper/work.go @@ -29,6 +29,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/util/retry" "k8s.io/klog/v2" + "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -38,7 +39,7 @@ import ( ) // CreateOrUpdateWork creates a Work object if not exist, or updates if it already exists. -func CreateOrUpdateWork(client client.Client, workMeta metav1.ObjectMeta, resource *unstructured.Unstructured, suspendDispatching *bool) error { +func CreateOrUpdateWork(ctx context.Context, client client.Client, workMeta metav1.ObjectMeta, resource *unstructured.Unstructured, suspendDispatching *bool) error { if workMeta.Labels[util.PropagationInstruction] != util.PropagationInstructionSuppressed { resource = resource.DeepCopy() // set labels @@ -77,7 +78,7 @@ func CreateOrUpdateWork(client client.Client, workMeta metav1.ObjectMeta, resour runtimeObject := work.DeepCopy() var operationResult controllerutil.OperationResult err = retry.RetryOnConflict(retry.DefaultRetry, func() (err error) { - operationResult, err = controllerutil.CreateOrUpdate(context.TODO(), client, runtimeObject, func() error { + operationResult, err = controllerutil.CreateOrUpdate(ctx, client, runtimeObject, func() error { if !runtimeObject.DeletionTimestamp.IsZero() { return fmt.Errorf("work %s/%s is being deleted", runtimeObject.GetNamespace(), runtimeObject.GetName()) } @@ -107,15 +108,15 @@ func CreateOrUpdateWork(client client.Client, workMeta metav1.ObjectMeta, resour } // GetWorksByLabelsSet gets WorkList by matching labels.Set. -func GetWorksByLabelsSet(c client.Client, ls labels.Set) (*workv1alpha1.WorkList, error) { +func GetWorksByLabelsSet(ctx context.Context, c client.Client, ls labels.Set) (*workv1alpha1.WorkList, error) { workList := &workv1alpha1.WorkList{} listOpt := &client.ListOptions{LabelSelector: labels.SelectorFromSet(ls)} - return workList, c.List(context.TODO(), workList, listOpt) + return workList, c.List(ctx, workList, listOpt) } // GetWorksByBindingID gets WorkList by matching same binding's permanent id. -func GetWorksByBindingID(c client.Client, bindingID string, namespaced bool) (*workv1alpha1.WorkList, error) { +func GetWorksByBindingID(ctx context.Context, c client.Client, bindingID string, namespaced bool) (*workv1alpha1.WorkList, error) { var ls labels.Set if namespaced { ls = labels.Set{workv1alpha2.ResourceBindingPermanentIDLabel: bindingID} @@ -123,7 +124,7 @@ func GetWorksByBindingID(c client.Client, bindingID string, namespaced bool) (*w ls = labels.Set{workv1alpha2.ClusterResourceBindingPermanentIDLabel: bindingID} } - return GetWorksByLabelsSet(c, ls) + return GetWorksByLabelsSet(ctx, c, ls) } // GenEventRef returns the event reference. sets the UID(.spec.uid) that might be missing for fire events. @@ -173,3 +174,8 @@ func IsWorkContains(manifests []workv1alpha1.Manifest, targetResource schema.Gro } return false } + +// IsWorkSuspendDispatching checks if the work is suspended from dispatching. +func IsWorkSuspendDispatching(work *workv1alpha1.Work) bool { + return ptr.Deref(work.Spec.SuspendDispatching, false) +} diff --git a/pkg/util/helper/workstatus.go b/pkg/util/helper/workstatus.go index 8f3a275f5bf8..1184a11e266f 100644 --- a/pkg/util/helper/workstatus.go +++ b/pkg/util/helper/workstatus.go @@ -56,17 +56,17 @@ const ( // AggregateResourceBindingWorkStatus will collect all work statuses with current ResourceBinding objects, // then aggregate status info to current ResourceBinding status. func AggregateResourceBindingWorkStatus( + ctx context.Context, c client.Client, binding *workv1alpha2.ResourceBinding, - resourceTemplate *unstructured.Unstructured, eventRecorder record.EventRecorder, ) error { - workList, err := GetWorksByBindingID(c, binding.Labels[workv1alpha2.ResourceBindingPermanentIDLabel], true) + workList, err := GetWorksByBindingID(ctx, c, binding.Labels[workv1alpha2.ResourceBindingPermanentIDLabel], true) if err != nil { return err } - aggregatedStatuses, err := assembleWorkStatus(workList.Items, resourceTemplate) + aggregatedStatuses, err := assembleWorkStatus(workList.Items, binding.Spec.Resource) if err != nil { return err } @@ -75,7 +75,7 @@ func AggregateResourceBindingWorkStatus( var operationResult controllerutil.OperationResult if err = retry.RetryOnConflict(retry.DefaultRetry, func() error { - operationResult, err = UpdateStatus(context.Background(), c, binding, func() error { + operationResult, err = UpdateStatus(ctx, c, binding, func() error { binding.Status.AggregatedStatus = aggregatedStatuses // set binding status with the newest condition meta.SetStatusCondition(&binding.Status.Conditions, fullyAppliedCondition) @@ -84,14 +84,12 @@ func AggregateResourceBindingWorkStatus( return err }); err != nil { eventRecorder.Event(binding, corev1.EventTypeWarning, events.EventReasonAggregateStatusFailed, err.Error()) - eventRecorder.Event(resourceTemplate, corev1.EventTypeWarning, events.EventReasonAggregateStatusFailed, err.Error()) return err } if operationResult == controllerutil.OperationResultUpdatedStatusOnly { msg := fmt.Sprintf("Update ResourceBinding(%s/%s) with AggregatedStatus successfully.", binding.Namespace, binding.Name) eventRecorder.Event(binding, corev1.EventTypeNormal, events.EventReasonAggregateStatusSucceed, msg) - eventRecorder.Event(resourceTemplate, corev1.EventTypeNormal, events.EventReasonAggregateStatusSucceed, msg) } else { klog.Infof("New aggregatedStatuses are equal with old ResourceBinding(%s/%s) AggregatedStatus, no update required.", binding.Namespace, binding.Name) } @@ -101,17 +99,17 @@ func AggregateResourceBindingWorkStatus( // AggregateClusterResourceBindingWorkStatus will collect all work statuses with current ClusterResourceBinding objects, // then aggregate status info to current ClusterResourceBinding status. func AggregateClusterResourceBindingWorkStatus( + ctx context.Context, c client.Client, binding *workv1alpha2.ClusterResourceBinding, - resourceTemplate *unstructured.Unstructured, eventRecorder record.EventRecorder, ) error { - workList, err := GetWorksByBindingID(c, binding.Labels[workv1alpha2.ClusterResourceBindingPermanentIDLabel], false) + workList, err := GetWorksByBindingID(ctx, c, binding.Labels[workv1alpha2.ClusterResourceBindingPermanentIDLabel], false) if err != nil { return err } - aggregatedStatuses, err := assembleWorkStatus(workList.Items, resourceTemplate) + aggregatedStatuses, err := assembleWorkStatus(workList.Items, binding.Spec.Resource) if err != nil { return err } @@ -120,7 +118,7 @@ func AggregateClusterResourceBindingWorkStatus( var operationResult controllerutil.OperationResult if err = retry.RetryOnConflict(retry.DefaultRetry, func() error { - operationResult, err = UpdateStatus(context.Background(), c, binding, func() error { + operationResult, err = UpdateStatus(ctx, c, binding, func() error { binding.Status.AggregatedStatus = aggregatedStatuses // set binding status with the newest condition meta.SetStatusCondition(&binding.Status.Conditions, fullyAppliedCondition) @@ -129,14 +127,12 @@ func AggregateClusterResourceBindingWorkStatus( return err }); err != nil { eventRecorder.Event(binding, corev1.EventTypeWarning, events.EventReasonAggregateStatusFailed, err.Error()) - eventRecorder.Event(resourceTemplate, corev1.EventTypeWarning, events.EventReasonAggregateStatusFailed, err.Error()) return err } if operationResult == controllerutil.OperationResultUpdatedStatusOnly { msg := fmt.Sprintf("Update ClusterResourceBinding(%s) with AggregatedStatus successfully.", binding.Name) eventRecorder.Event(binding, corev1.EventTypeNormal, events.EventReasonAggregateStatusSucceed, msg) - eventRecorder.Event(resourceTemplate, corev1.EventTypeNormal, events.EventReasonAggregateStatusSucceed, msg) } else { klog.Infof("New aggregatedStatuses are equal with old ClusterResourceBinding(%s) AggregatedStatus, no update required.", binding.Name) } @@ -153,14 +149,15 @@ func generateFullyAppliedCondition(spec workv1alpha2.ResourceBindingSpec, aggreg } // assemble workStatuses from workList which list by selector and match with workload. -func assembleWorkStatus(works []workv1alpha1.Work, workload *unstructured.Unstructured) ([]workv1alpha2.AggregatedStatusItem, error) { +func assembleWorkStatus(works []workv1alpha1.Work, objRef workv1alpha2.ObjectReference) ([]workv1alpha2.AggregatedStatusItem, error) { statuses := make([]workv1alpha2.AggregatedStatusItem, 0) for _, work := range works { if !work.DeletionTimestamp.IsZero() { continue } - identifierIndex, err := GetManifestIndex(work.Spec.Workload.Manifests, workload) + manifestRef := ManifestReference{APIVersion: objRef.APIVersion, Kind: objRef.Kind, Namespace: objRef.Namespace, Name: objRef.Name} + identifierIndex, err := GetManifestIndex(work.Spec.Workload.Manifests, &manifestRef) if err != nil { klog.Errorf("Failed to get manifestIndex of workload in work.Spec.Workload.Manifests. Error: %v.", err) return nil, err @@ -206,7 +203,7 @@ func assembleWorkStatus(works []workv1alpha1.Work, workload *unstructured.Unstru } for i := range work.Status.ManifestStatuses { - equal, err := equalIdentifier(&work.Status.ManifestStatuses[i].Identifier, identifierIndex, workload) + equal, err := equalIdentifier(&work.Status.ManifestStatuses[i].Identifier, identifierIndex, &manifestRef) if err != nil { return nil, err } @@ -225,18 +222,25 @@ func assembleWorkStatus(works []workv1alpha1.Work, workload *unstructured.Unstru return statuses, nil } +// ManifestReference identifies an object in manifest list +type ManifestReference struct { + APIVersion string + Kind string + Namespace string + Name string +} + // GetManifestIndex gets the index of clusterObj in manifest list, if not exist return -1. -func GetManifestIndex(manifests []workv1alpha1.Manifest, clusterObj *unstructured.Unstructured) (int, error) { +func GetManifestIndex(manifests []workv1alpha1.Manifest, manifestRef *ManifestReference) (int, error) { for index, rawManifest := range manifests { manifest := &unstructured.Unstructured{} if err := manifest.UnmarshalJSON(rawManifest.Raw); err != nil { return -1, err } - - if manifest.GetAPIVersion() == clusterObj.GetAPIVersion() && - manifest.GetKind() == clusterObj.GetKind() && - manifest.GetNamespace() == clusterObj.GetNamespace() && - manifest.GetName() == clusterObj.GetName() { + if manifest.GetAPIVersion() == manifestRef.APIVersion && + manifest.GetKind() == manifestRef.Kind && + manifest.GetNamespace() == manifestRef.Namespace && + manifest.GetName() == manifestRef.Name { return index, nil } } @@ -244,8 +248,8 @@ func GetManifestIndex(manifests []workv1alpha1.Manifest, clusterObj *unstructure return -1, fmt.Errorf("no such manifest exist") } -func equalIdentifier(targetIdentifier *workv1alpha1.ResourceIdentifier, ordinal int, workload *unstructured.Unstructured) (bool, error) { - groupVersion, err := schema.ParseGroupVersion(workload.GetAPIVersion()) +func equalIdentifier(targetIdentifier *workv1alpha1.ResourceIdentifier, ordinal int, manifestRef *ManifestReference) (bool, error) { + groupVersion, err := schema.ParseGroupVersion(manifestRef.APIVersion) if err != nil { return false, err } @@ -253,9 +257,9 @@ func equalIdentifier(targetIdentifier *workv1alpha1.ResourceIdentifier, ordinal if targetIdentifier.Ordinal == ordinal && targetIdentifier.Group == groupVersion.Group && targetIdentifier.Version == groupVersion.Version && - targetIdentifier.Kind == workload.GetKind() && - targetIdentifier.Namespace == workload.GetNamespace() && - targetIdentifier.Name == workload.GetName() { + targetIdentifier.Kind == manifestRef.Kind && + targetIdentifier.Namespace == manifestRef.Namespace && + targetIdentifier.Name == manifestRef.Name { return true, nil } diff --git a/pkg/util/helper/workstatus_test.go b/pkg/util/helper/workstatus_test.go index 3ff329960759..bd5119524dc7 100644 --- a/pkg/util/helper/workstatus_test.go +++ b/pkg/util/helper/workstatus_test.go @@ -192,7 +192,9 @@ func TestGetManifestIndex(t *testing.T) { } t.Run("Service", func(t *testing.T) { - index, err := GetManifestIndex(manifests, service) + manifestRef := ManifestReference{APIVersion: service.GetAPIVersion(), Kind: service.GetKind(), + Namespace: service.GetNamespace(), Name: service.GetName()} + index, err := GetManifestIndex(manifests, &manifestRef) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -202,7 +204,9 @@ func TestGetManifestIndex(t *testing.T) { }) t.Run("Deployment", func(t *testing.T) { - index, err := GetManifestIndex(manifests, deployment) + manifestRef := ManifestReference{APIVersion: deployment.GetAPIVersion(), Kind: deployment.GetKind(), + Namespace: deployment.GetNamespace(), Name: deployment.GetName()} + index, err := GetManifestIndex(manifests, &manifestRef) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -212,7 +216,7 @@ func TestGetManifestIndex(t *testing.T) { }) t.Run("No match", func(t *testing.T) { - _, err := GetManifestIndex(manifests, &unstructured.Unstructured{}) + _, err := GetManifestIndex(manifests, &ManifestReference{}) if err == nil { t.Errorf("expected error, got nil") } @@ -224,7 +228,7 @@ func TestEqualIdentifier(t *testing.T) { name string target *workv1alpha1.ResourceIdentifier ordinal int - workload *unstructured.Unstructured + workload *ManifestReference expectedOutput bool }{ { @@ -238,15 +242,11 @@ func TestEqualIdentifier(t *testing.T) { Name: "test-deployment", }, ordinal: 0, - workload: &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": map[string]interface{}{ - "namespace": "default", - "name": "test-deployment", - }, - }, + workload: &ManifestReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "default", + Name: "test-deployment", }, expectedOutput: true, }, @@ -261,15 +261,11 @@ func TestEqualIdentifier(t *testing.T) { Name: "test-deployment", }, ordinal: 0, - workload: &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": map[string]interface{}{ - "namespace": "default", - "name": "test-deployment", - }, - }, + workload: &ManifestReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "default", + Name: "test-deployment", }, expectedOutput: false, }, diff --git a/pkg/util/interpreter/matcher_test.go b/pkg/util/interpreter/matcher_test.go index 005a2927183b..ce3009b86deb 100644 --- a/pkg/util/interpreter/matcher_test.go +++ b/pkg/util/interpreter/matcher_test.go @@ -313,3 +313,135 @@ func TestExactOrWildcard(t *testing.T) { }) } } + +func TestMatches(t *testing.T) { + tests := []struct { + name string + matcher *Matcher + expected bool + }{ + { + name: "not equal operations, equal group version and kind", + matcher: &Matcher{ + ObjGVK: schema.GroupVersionKind{ + Group: "apps", + Version: "v1", + Kind: "Deployment", + }, + Operation: configv1alpha1.InterpreterOperationPrune, + Rule: configv1alpha1.RuleWithOperations{ + Operations: []configv1alpha1.InterpreterOperation{ + configv1alpha1.InterpreterOperationRetain, + configv1alpha1.InterpreterOperationInterpretReplica, + }, + Rule: configv1alpha1.Rule{ + APIGroups: []string{"batch", "apps"}, + APIVersions: []string{"v1", "v1beta1"}, + Kinds: []string{"Pod", "Deployment"}, + }, + }, + }, + expected: false, + }, + { + name: "not equal group, equal operation version and kind", + matcher: &Matcher{ + ObjGVK: schema.GroupVersionKind{ + Group: "apps", + Version: "v1", + Kind: "Deployment", + }, + Operation: configv1alpha1.InterpreterOperationRetain, + Rule: configv1alpha1.RuleWithOperations{ + Operations: []configv1alpha1.InterpreterOperation{ + configv1alpha1.InterpreterOperationRetain, + configv1alpha1.InterpreterOperationInterpretReplica, + }, + Rule: configv1alpha1.Rule{ + APIGroups: []string{"batch"}, + APIVersions: []string{"v1", "v1beta1"}, + Kinds: []string{"Pod", "Deployment"}, + }, + }, + }, + expected: false, + }, + { + name: "not equal version, equal operation group and kind", + matcher: &Matcher{ + ObjGVK: schema.GroupVersionKind{ + Group: "apps", + Version: "v1", + Kind: "Deployment", + }, + Operation: configv1alpha1.InterpreterOperationRetain, + Rule: configv1alpha1.RuleWithOperations{ + Operations: []configv1alpha1.InterpreterOperation{ + configv1alpha1.InterpreterOperationRetain, + configv1alpha1.InterpreterOperationInterpretReplica, + }, + Rule: configv1alpha1.Rule{ + APIGroups: []string{"batch", "apps"}, + APIVersions: []string{"v1beta1"}, + Kinds: []string{"Pod", "Deployment"}, + }, + }, + }, + expected: false, + }, + { + name: "not equal kind, equal operation group and version", + matcher: &Matcher{ + ObjGVK: schema.GroupVersionKind{ + Group: "apps", + Version: "v1", + Kind: "Deployment", + }, + Operation: configv1alpha1.InterpreterOperationRetain, + Rule: configv1alpha1.RuleWithOperations{ + Operations: []configv1alpha1.InterpreterOperation{ + configv1alpha1.InterpreterOperationRetain, + configv1alpha1.InterpreterOperationInterpretReplica, + }, + Rule: configv1alpha1.Rule{ + APIGroups: []string{"batch", "apps"}, + APIVersions: []string{"v1", "v1beta1"}, + Kinds: []string{"Pod"}, + }, + }, + }, + expected: false, + }, + { + name: "operation, object matches the rule", + matcher: &Matcher{ + ObjGVK: schema.GroupVersionKind{ + Group: "apps", + Version: "v1", + Kind: "Deployment", + }, + Operation: configv1alpha1.InterpreterOperationRetain, + Rule: configv1alpha1.RuleWithOperations{ + Operations: []configv1alpha1.InterpreterOperation{ + configv1alpha1.InterpreterOperationRetain, + configv1alpha1.InterpreterOperationInterpretReplica, + }, + Rule: configv1alpha1.Rule{ + APIGroups: []string{"batch", "apps"}, + APIVersions: []string{"v1", "v1beta1"}, + Kinds: []string{"Pod", "Deployment"}, + }, + }, + }, + expected: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := tt.matcher.Matches() + if res != tt.expected { + t.Errorf("Matches() = %v, want %v", res, tt.expected) + } + }) + } +} diff --git a/pkg/util/label_test.go b/pkg/util/label_test.go index 6d15b89ecd5a..876718a79f7e 100644 --- a/pkg/util/label_test.go +++ b/pkg/util/label_test.go @@ -229,14 +229,46 @@ func TestDedupeAndMergeLabels(t *testing.T) { func TestRemoveLabel(t *testing.T) { type args struct { - obj *unstructured.Unstructured - labelKey string + obj *unstructured.Unstructured + labelKeys []string } tests := []struct { name string args args expected *unstructured.Unstructured }{ + { + name: "empty labelKeys", + args: args{ + obj: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "demo-deployment", + "labels": map[string]interface{}{"foo": "bar"}, + }, + "spec": map[string]interface{}{ + "replicas": 2, + }, + }, + }, + labelKeys: []string{}, + }, + expected: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "demo-deployment", + "labels": map[string]interface{}{"foo": "bar"}, + }, + "spec": map[string]interface{}{ + "replicas": 2, + }, + }, + }, + }, { name: "nil object labels", args: args{ @@ -249,8 +281,10 @@ func TestRemoveLabel(t *testing.T) { }, "spec": map[string]interface{}{ "replicas": 2, - }}}, - labelKey: "foo", + }, + }, + }, + labelKeys: []string{"foo"}, }, expected: &unstructured.Unstructured{ Object: map[string]interface{}{ @@ -261,10 +295,12 @@ func TestRemoveLabel(t *testing.T) { }, "spec": map[string]interface{}{ "replicas": 2, - }}}, + }, + }, + }, }, { - name: "same labelKey", + name: "same labelKeys", args: args{ obj: &unstructured.Unstructured{ Object: map[string]interface{}{ @@ -276,8 +312,10 @@ func TestRemoveLabel(t *testing.T) { }, "spec": map[string]interface{}{ "replicas": 2, - }}}, - labelKey: "foo", + }, + }, + }, + labelKeys: []string{"foo"}, }, expected: &unstructured.Unstructured{ Object: map[string]interface{}{ @@ -289,10 +327,12 @@ func TestRemoveLabel(t *testing.T) { }, "spec": map[string]interface{}{ "replicas": 2, - }}}, + }, + }, + }, }, { - name: "different labelKey", + name: "different labelKeys", args: args{ obj: &unstructured.Unstructured{ Object: map[string]interface{}{ @@ -304,8 +344,10 @@ func TestRemoveLabel(t *testing.T) { }, "spec": map[string]interface{}{ "replicas": 2, - }}}, - labelKey: "foo1", + }, + }, + }, + labelKeys: []string{"foo1"}, }, expected: &unstructured.Unstructured{ Object: map[string]interface{}{ @@ -317,12 +359,78 @@ func TestRemoveLabel(t *testing.T) { }, "spec": map[string]interface{}{ "replicas": 2, - }}}, + }, + }, + }, + }, + { + name: "same labelKeys of different length", + args: args{ + obj: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "demo-deployment", + "labels": map[string]interface{}{"foo": "bar", "foo1": "bar1"}, + }, + "spec": map[string]interface{}{ + "replicas": 2, + }, + }, + }, + labelKeys: []string{"foo", "foo1"}, + }, + expected: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "demo-deployment", + "labels": map[string]interface{}{}, + }, + "spec": map[string]interface{}{ + "replicas": 2, + }, + }, + }, + }, + { + name: "different labelKeys of different length", + args: args{ + obj: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "demo-deployment", + "labels": map[string]interface{}{"foo": "bar", "foo1": "bar1"}, + }, + "spec": map[string]interface{}{ + "replicas": 2, + }, + }, + }, + labelKeys: []string{"foo2", "foo3"}, + }, + expected: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "demo-deployment", + "labels": map[string]interface{}{"foo": "bar", "foo1": "bar1"}, + }, + "spec": map[string]interface{}{ + "replicas": 2, + }, + }, + }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - RemoveLabels(tt.args.obj, tt.args.labelKey) + RemoveLabels(tt.args.obj, tt.args.labelKeys...) if !reflect.DeepEqual(tt.args.obj, tt.expected) { t.Errorf("RemoveLabel() = %v, want %v", tt.args.obj, tt.expected) } @@ -560,7 +668,7 @@ func TestRecordManagedLabels(t *testing.T) { }, }, { - name: "object has has labels", + name: "object has labels", object: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", diff --git a/pkg/util/lifted/corev1printers.go b/pkg/util/lifted/corev1printers.go index ab493499c988..b85afd37346c 100644 --- a/pkg/util/lifted/corev1printers.go +++ b/pkg/util/lifted/corev1printers.go @@ -21,11 +21,10 @@ import ( "strings" "time" - "k8s.io/apimachinery/pkg/util/duration" - corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/duration" "k8s.io/apimachinery/pkg/util/sets" "github.com/karmada-io/karmada/pkg/printers" diff --git a/pkg/util/lifted/scheduler/cache/cache.go b/pkg/util/lifted/scheduler/cache/cache.go index 15fa87f3a736..f3d3793c74ed 100644 --- a/pkg/util/lifted/scheduler/cache/cache.go +++ b/pkg/util/lifted/scheduler/cache/cache.go @@ -489,7 +489,6 @@ func (cache *cacheImpl) removePod(pod *corev1.Pod) error { n, ok := cache.nodes[pod.Spec.NodeName] if !ok { klog.ErrorS(nil, "Node not found when trying to remove pod", "node", klog.KRef("", pod.Spec.NodeName), "podKey", key, "pod", klog.KObj(pod)) - } else { if err := n.info.RemovePod(pod); err != nil { return err diff --git a/pkg/util/lifted/validatingfhpa.go b/pkg/util/lifted/validatingfhpa.go old mode 100755 new mode 100644 index a3ebf9b2c94b..8aa9007ddedc --- a/pkg/util/lifted/validatingfhpa.go +++ b/pkg/util/lifted/validatingfhpa.go @@ -20,7 +20,6 @@ import ( "fmt" autoscalingv2 "k8s.io/api/autoscaling/v2" - apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation" apivalidation "k8s.io/apimachinery/pkg/api/validation" pathvalidation "k8s.io/apimachinery/pkg/api/validation/path" "k8s.io/apimachinery/pkg/util/sets" @@ -46,7 +45,7 @@ const ( func ValidateFederatedHPA(fhpa *autoscalingv1alpha1.FederatedHPA) field.ErrorList { errs := field.ErrorList{} - errs = append(errs, apimachineryvalidation.ValidateObjectMeta(&fhpa.ObjectMeta, true, apivalidation.NameIsDNSSubdomain, field.NewPath("metadata"))...) + errs = append(errs, apivalidation.ValidateObjectMeta(&fhpa.ObjectMeta, true, apivalidation.NameIsDNSSubdomain, field.NewPath("metadata"))...) // MinReplicasLowerBound represents a minimum value for minReplicas // 0 when HPA scale-to-zero feature is enabled @@ -267,7 +266,6 @@ func validateMetricSpec(spec autoscalingv2.MetricSpec, fldPath *field.Path) fiel var expectedField string switch spec.Type { - case autoscalingv2.ObjectMetricSourceType: if spec.Object == nil { allErrs = append(allErrs, field.Required(fldPath.Child("object"), "must populate information for the given metric source")) diff --git a/pkg/util/names/names_test.go b/pkg/util/names/names_test.go index a3e435bc97c9..341c43c53e35 100644 --- a/pkg/util/names/names_test.go +++ b/pkg/util/names/names_test.go @@ -37,7 +37,8 @@ func TestGenerateExecutionSpaceName(t *testing.T) { want string wantErr bool }{ - {name: "normal cluster name", + { + name: "normal cluster name", args: args{clusterName: "member-cluster-normal"}, want: "karmada-es-member-cluster-normal", }, @@ -62,17 +63,20 @@ func TestGetClusterName(t *testing.T) { want string wantErr bool }{ - {name: "normal execution space name", + { + name: "normal execution space name", args: args{executionSpaceName: "karmada-es-member-cluster-normal"}, want: "member-cluster-normal", wantErr: false, }, - {name: "invalid member cluster", + { + name: "invalid member cluster", args: args{executionSpaceName: "invalid"}, want: "", wantErr: true, }, - {name: "empty execution space name", + { + name: "empty execution space name", args: args{executionSpaceName: ""}, want: "", wantErr: true, @@ -210,6 +214,13 @@ func TestGenerateWorkName(t *testing.T) { namespace: "default", workname: "default-pod-pods", }, + { + testCase: "non nil namespace, colon in name", + kind: "Pods", + name: "work:pod", + namespace: "default", + workname: "default-work.pod-pods", + }, } for _, test := range tests { @@ -217,6 +228,9 @@ func TestGenerateWorkName(t *testing.T) { hash := fnv.New32a() hashutil.DeepHashObject(hash, test.workname) + if strings.Contains(test.name, ":") { + test.name = strings.ReplaceAll(test.name, ":", ".") + } if result := fmt.Sprintf("%s-%s", strings.ToLower(test.name), rand.SafeEncodeString(fmt.Sprint(hash.Sum32()))); result != got { t.Errorf("Test %s failed: expected %v, but got %v", test.testCase, result, got) } @@ -438,3 +452,30 @@ func TestGeneratePolicyName(t *testing.T) { } } } + +func TestNamespacedKey(t *testing.T) { + tests := []struct { + testCase string + name string + namespace string + expectedNamespacedKey string + }{ + { + testCase: "empty namespace", + name: "pod", + namespace: "", + expectedNamespacedKey: "pod", + }, { + testCase: "non nil namespace", + name: "pod", + namespace: "default", + expectedNamespacedKey: "default/pod", + }, + } + for _, test := range tests { + gotNamespacedKey := NamespacedKey(test.namespace, test.name) + if gotNamespacedKey != test.expectedNamespacedKey { + t.Errorf("Test %s failed: expected %v, but got %v", test.testCase, test.expectedNamespacedKey, gotNamespacedKey) + } + } +} diff --git a/pkg/util/objectwatcher/objectwatcher.go b/pkg/util/objectwatcher/objectwatcher.go index 888ab4b2e7e7..47a98560e7f8 100644 --- a/pkg/util/objectwatcher/objectwatcher.go +++ b/pkg/util/objectwatcher/objectwatcher.go @@ -41,9 +41,9 @@ import ( // ObjectWatcher manages operations for object dispatched to member clusters. type ObjectWatcher interface { - Create(clusterName string, desireObj *unstructured.Unstructured) error - Update(clusterName string, desireObj, clusterObj *unstructured.Unstructured) error - Delete(clusterName string, desireObj *unstructured.Unstructured) error + Create(ctx context.Context, clusterName string, desireObj *unstructured.Unstructured) error + Update(ctx context.Context, clusterName string, desireObj, clusterObj *unstructured.Unstructured) error + Delete(ctx context.Context, clusterName string, desireObj *unstructured.Unstructured) error NeedsUpdate(clusterName string, desiredObj, clusterObj *unstructured.Unstructured) (bool, error) } @@ -72,7 +72,7 @@ func NewObjectWatcher(kubeClientSet client.Client, restMapper meta.RESTMapper, c } } -func (o *objectWatcherImpl) Create(clusterName string, desireObj *unstructured.Unstructured) error { +func (o *objectWatcherImpl) Create(ctx context.Context, clusterName string, desireObj *unstructured.Unstructured) error { dynamicClusterClient, err := o.ClusterClientSetFunc(clusterName, o.KubeClientSet) if err != nil { klog.Errorf("Failed to build dynamic cluster client for cluster %s, err: %v.", clusterName, err) @@ -97,7 +97,7 @@ func (o *objectWatcherImpl) Create(clusterName string, desireObj *unstructured.U return err } - clusterObj, err := dynamicClusterClient.DynamicClientSet.Resource(gvr).Namespace(desireObj.GetNamespace()).Create(context.TODO(), desireObj, metav1.CreateOptions{}) + clusterObj, err := dynamicClusterClient.DynamicClientSet.Resource(gvr).Namespace(desireObj.GetNamespace()).Create(ctx, desireObj, metav1.CreateOptions{}) if err != nil { klog.Errorf("Failed to create resource(kind=%s, %s/%s) in cluster %s, err is %v.", desireObj.GetKind(), desireObj.GetNamespace(), desireObj.GetName(), clusterName, err) return err @@ -138,7 +138,7 @@ func (o *objectWatcherImpl) retainClusterFields(desired, observed *unstructured. return desired, nil } -func (o *objectWatcherImpl) Update(clusterName string, desireObj, clusterObj *unstructured.Unstructured) error { +func (o *objectWatcherImpl) Update(ctx context.Context, clusterName string, desireObj, clusterObj *unstructured.Unstructured) error { updateAllowed := o.allowUpdate(clusterName, desireObj, clusterObj) if !updateAllowed { // The existing resource is not managed by Karmada, and no conflict resolution found, avoid updating the existing resource by default. @@ -164,7 +164,7 @@ func (o *objectWatcherImpl) Update(clusterName string, desireObj, clusterObj *un return err } - resource, err := dynamicClusterClient.DynamicClientSet.Resource(gvr).Namespace(desireObj.GetNamespace()).Update(context.TODO(), desireObj, metav1.UpdateOptions{}) + resource, err := dynamicClusterClient.DynamicClientSet.Resource(gvr).Namespace(desireObj.GetNamespace()).Update(ctx, desireObj, metav1.UpdateOptions{}) if err != nil { klog.Errorf("Failed to update resource(kind=%s, %s/%s) in cluster %s, err: %v.", desireObj.GetKind(), desireObj.GetNamespace(), desireObj.GetName(), clusterName, err) return err @@ -177,7 +177,7 @@ func (o *objectWatcherImpl) Update(clusterName string, desireObj, clusterObj *un return nil } -func (o *objectWatcherImpl) Delete(clusterName string, desireObj *unstructured.Unstructured) error { +func (o *objectWatcherImpl) Delete(ctx context.Context, clusterName string, desireObj *unstructured.Unstructured) error { fedKey, err := keys.FederatedKeyFunc(clusterName, desireObj) if err != nil { klog.Errorf("Failed to get FederatedKey %s, error: %v", desireObj.GetName(), err) @@ -221,7 +221,7 @@ func (o *objectWatcherImpl) Delete(clusterName string, desireObj *unstructured.U PropagationPolicy: &deleteBackground, } - err = dynamicClusterClient.DynamicClientSet.Resource(gvr).Namespace(desireObj.GetNamespace()).Delete(context.TODO(), desireObj.GetName(), deleteOption) + err = dynamicClusterClient.DynamicClientSet.Resource(gvr).Namespace(desireObj.GetNamespace()).Delete(ctx, desireObj.GetName(), deleteOption) if err != nil && !apierrors.IsNotFound(err) { klog.Errorf("Failed to delete the resource(kind=%s, %s/%s) in the cluster %s, err: %v.", desireObj.GetKind(), desireObj.GetNamespace(), desireObj.GetName(), clusterName, err) return err diff --git a/pkg/util/overridemanager/shadow_test.go b/pkg/util/overridemanager/shadow_test.go index 08fb96c3a6ee..1991e1644803 100644 --- a/pkg/util/overridemanager/shadow_test.go +++ b/pkg/util/overridemanager/shadow_test.go @@ -22,6 +22,14 @@ import ( func TestAppliedOverrides_AscendOrder(t *testing.T) { applied := AppliedOverrides{} + appliedEmptyBytes, er := applied.MarshalJSON() + if er != nil { + t.Fatalf("not expect error, but got: %v", er) + } + if appliedEmptyBytes != nil { + t.Fatalf("expect nil, but got: %s", string(appliedEmptyBytes)) + } + item2 := OverridePolicyShadow{PolicyName: "bbb"} item1 := OverridePolicyShadow{PolicyName: "aaa"} item3 := OverridePolicyShadow{PolicyName: "ccc"} diff --git a/pkg/util/validation/validation.go b/pkg/util/validation/validation.go index 76bd3fc9671f..084cae0237c4 100644 --- a/pkg/util/validation/validation.go +++ b/pkg/util/validation/validation.go @@ -43,6 +43,7 @@ func ValidatePropagationSpec(spec policyv1alpha1.PropagationSpec) field.ErrorLis } allErrs = append(allErrs, ValidateFailover(spec.Failover, field.NewPath("spec").Child("failover"))...) allErrs = append(allErrs, validateResourceSelectorsIfPreemptionEnabled(spec, field.NewPath("spec").Child("resourceSelectors"))...) + allErrs = append(allErrs, validateSuspension(spec.Suspension, field.NewPath("spec").Child("suspension"))...) return allErrs } @@ -55,18 +56,33 @@ func validateResourceSelectorsIfPreemptionEnabled(spec policyv1alpha1.Propagatio var allErrs field.ErrorList for index, resourceSelector := range spec.ResourceSelectors { if len(resourceSelector.Name) == 0 { - allErrs = append(allErrs, field.Invalid(fldPath.Index(index).Child("name"), resourceSelector.Name, "name can not be empty if preemption is Always, the empty name may cause unexpected resources preemption")) + allErrs = append(allErrs, field.Invalid(fldPath.Index(index).Child("name"), resourceSelector.Name, "name cannot be empty if preemption is Always, the empty name may cause unexpected resources preemption")) } } return allErrs } +// validateSuspension validates no conflicts between dispatching and dispatchingOnClusters. +func validateSuspension(suspension *policyv1alpha1.Suspension, fldPath *field.Path) field.ErrorList { + if suspension == nil { + return nil + } + + if (suspension.Dispatching != nil && *suspension.Dispatching) && + (suspension.DispatchingOnClusters != nil && len(suspension.DispatchingOnClusters.ClusterNames) > 0) { + return field.ErrorList{ + field.Invalid(fldPath.Child("suspension"), suspension, "suspension dispatching cannot co-exist with dispatchingOnClusters.clusterNames"), + } + } + return nil +} + // ValidatePlacement validates a placement before creation or update. func ValidatePlacement(placement policyv1alpha1.Placement, fldPath *field.Path) field.ErrorList { var allErrs field.ErrorList if placement.ClusterAffinity != nil && placement.ClusterAffinities != nil { - allErrs = append(allErrs, field.Invalid(fldPath, placement, "clusterAffinities can not co-exist with clusterAffinity")) + allErrs = append(allErrs, field.Invalid(fldPath, placement, "clusterAffinities cannot co-exist with clusterAffinity")) } allErrs = append(allErrs, ValidateClusterAffinity(placement.ClusterAffinity, fldPath.Child("clusterAffinity"))...) diff --git a/pkg/util/validation/validation_test.go b/pkg/util/validation/validation_test.go index 2c6cf9f33854..f5aec8aec3f6 100644 --- a/pkg/util/validation/validation_test.go +++ b/pkg/util/validation/validation_test.go @@ -370,7 +370,7 @@ func TestValidatePropagationSpec(t *testing.T) { expectedErr: "unsupported operator \"Exists\", must be In or NotIn", }, { - name: "clusterAffinities can not co-exist with clusterAffinity", + name: "clusterAffinities cannot co-exist with clusterAffinity", spec: policyv1alpha1.PropagationSpec{ Placement: policyv1alpha1.Placement{ ClusterAffinity: &policyv1alpha1.ClusterAffinity{ @@ -382,7 +382,7 @@ func TestValidatePropagationSpec(t *testing.T) { ClusterAffinity: policyv1alpha1.ClusterAffinity{ ClusterNames: []string{"m1"}, }}}}}, - expectedErr: "clusterAffinities can not co-exist with clusterAffinity", + expectedErr: "clusterAffinities cannot co-exist with clusterAffinity", }, { name: "clusterAffinities different affinities have the same affinityName", @@ -564,7 +564,63 @@ func TestValidatePropagationSpec(t *testing.T) { }, Preemption: policyv1alpha1.PreemptAlways, }, - expectedErr: "name can not be empty if preemption is Always, the empty name may cause unexpected resources preemption", + expectedErr: "name cannot be empty if preemption is Always, the empty name may cause unexpected resources preemption", + }, + { + name: "suspension dispatching cannot co-exist with dispatchingOnClusters", + spec: policyv1alpha1.PropagationSpec{ + Suspension: &policyv1alpha1.Suspension{ + Dispatching: ptr.To(true), + DispatchingOnClusters: &policyv1alpha1.SuspendClusters{ + ClusterNames: []string{"cluster-name"}, + }, + }, + }, + expectedErr: "suspension dispatching cannot co-exist with dispatchingOnClusters.clusterNames", + }, + { + name: "suspension dispatching with nil dispatchingOnClusters is valid", + spec: policyv1alpha1.PropagationSpec{ + Suspension: &policyv1alpha1.Suspension{ + Dispatching: ptr.To(true), + }, + }, + expectedErr: "", + }, + { + name: "suspension dispatching with empty dispatching clusters is valid", + spec: policyv1alpha1.PropagationSpec{ + Suspension: &policyv1alpha1.Suspension{ + Dispatching: ptr.To(true), + DispatchingOnClusters: &policyv1alpha1.SuspendClusters{ + ClusterNames: []string{}, + }, + }, + }, + expectedErr: "", + }, + { + name: "dispatchingOnClusters.clusterNames without dispatching is valid", + spec: policyv1alpha1.PropagationSpec{ + Suspension: &policyv1alpha1.Suspension{ + DispatchingOnClusters: &policyv1alpha1.SuspendClusters{ + ClusterNames: []string{"cluster-name"}, + }, + }, + }, + expectedErr: "", + }, + { + name: "dispatchingOnClusters.clusterNames with dispatching false is valid", + spec: policyv1alpha1.PropagationSpec{ + Suspension: &policyv1alpha1.Suspension{ + Dispatching: ptr.To(false), + DispatchingOnClusters: &policyv1alpha1.SuspendClusters{ + ClusterNames: []string{"cluster-name"}, + }, + }, + }, + expectedErr: "", }, } for _, tt := range tests { diff --git a/test/e2e/clusterpropagationpolicy_test.go b/test/e2e/clusterpropagationpolicy_test.go index 8c39b81a1ab8..c019c9480d4d 100644 --- a/test/e2e/clusterpropagationpolicy_test.go +++ b/test/e2e/clusterpropagationpolicy_test.go @@ -26,6 +26,7 @@ import ( appsv1 "k8s.io/api/apps/v1" rbacv1 "k8s.io/api/rbac/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/types" @@ -34,7 +35,9 @@ import ( "k8s.io/utils/ptr" policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1" + workv1alpha1 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha1" workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" + "github.com/karmada-io/karmada/pkg/util/helper" "github.com/karmada-io/karmada/pkg/util/names" "github.com/karmada-io/karmada/test/e2e/framework" testhelper "github.com/karmada-io/karmada/test/helper" @@ -1049,23 +1052,22 @@ var _ = ginkgo.Describe("[Suspend] clusterPropagation testing", func() { }) ginkgo.BeforeEach(func() { + framework.CreateClusterPropagationPolicy(karmadaClient, policy) framework.CreateClusterRole(kubeClient, clusterRole) ginkgo.DeferCleanup(func() { + framework.RemoveClusterPropagationPolicy(karmadaClient, policy.Name) framework.RemoveClusterRole(kubeClient, clusterRole.Name) }) }) - ginkgo.Context("suspend the ClusterPropagationPolicy dispatching", func() { - ginkgo.BeforeEach(func() { - policy.Spec.Suspension = &policyv1alpha1.Suspension{ - Dispatching: ptr.To(true), - } - framework.CreateClusterPropagationPolicy(karmadaClient, policy) - ginkgo.DeferCleanup(func() { - framework.RemoveClusterPropagationPolicy(karmadaClient, policy.Name) - }) - }) + ginkgo.BeforeEach(func() { + policy.Spec.Suspension = &policyv1alpha1.Suspension{ + Dispatching: ptr.To(true), + } + framework.UpdateClusterPropagationPolicyWithSpec(karmadaClient, policy.Name, policy.Spec) + }) + ginkgo.Context("suspend the ClusterPropagationPolicy dispatching", func() { ginkgo.It("suspends ClusterResourceBinding", func() { framework.WaitClusterResourceBindingFitWith(karmadaClient, resourceBindingName, func(binding *workv1alpha2.ClusterResourceBinding) bool { return binding.Spec.Suspension != nil && ptr.Deref(binding.Spec.Suspension.Dispatching, false) @@ -1079,7 +1081,18 @@ var _ = ginkgo.Describe("[Suspend] clusterPropagation testing", func() { if err != nil { return false } - return work != nil && ptr.Deref(work.Spec.SuspendDispatching, false) + return work != nil && helper.IsWorkSuspendDispatching(work) + }, pollTimeout, pollInterval).Should(gomega.Equal(true)) + }) + + ginkgo.It("adds suspend dispatching condition to Work", func() { + esName := names.GenerateExecutionSpaceName(targetMember) + gomega.Eventually(func() bool { + work, err := karmadaClient.WorkV1alpha1().Works(esName).Get(context.TODO(), workName, metav1.GetOptions{}) + if err != nil { + return false + } + return work != nil && meta.IsStatusConditionPresentAndEqual(work.Status.Conditions, workv1alpha1.WorkDispatching, metav1.ConditionFalse) }, pollTimeout, pollInterval).Should(gomega.Equal(true)) }) }) diff --git a/test/e2e/clusterresourcebinding_test.go b/test/e2e/clusterresourcebinding_test.go index 25bc68e04e1d..13885ff2cbaa 100644 --- a/test/e2e/clusterresourcebinding_test.go +++ b/test/e2e/clusterresourcebinding_test.go @@ -17,6 +17,7 @@ limitations under the License. package e2e import ( + "context" "fmt" "github.com/onsi/ginkgo/v2" @@ -79,7 +80,7 @@ var _ = ginkgo.Describe("ClusterResourceBinding test", func() { ginkgo.It("creates work with permanent ID label", func() { framework.WaitClusterResourceBindingFitWith(karmadaClient, bindingName, func(clusterResourceBinding *workv1alpha2.ClusterResourceBinding) bool { - workList, err := helper.GetWorksByBindingID(controlPlaneClient, clusterResourceBinding.Labels[workv1alpha2.ClusterResourceBindingPermanentIDLabel], false) + workList, err := helper.GetWorksByBindingID(context.Background(), controlPlaneClient, clusterResourceBinding.Labels[workv1alpha2.ClusterResourceBindingPermanentIDLabel], false) if err != nil { return false } diff --git a/test/e2e/coverage_docs/failover_test.md b/test/e2e/coverage_docs/failover_test.md index cef83842dd8e..5698213c1ad3 100644 --- a/test/e2e/coverage_docs/failover_test.md +++ b/test/e2e/coverage_docs/failover_test.md @@ -1,11 +1,9 @@ ### failover e2e test coverage analysis -| Test Case | E2E Describe Text | Comments | -|------------------------------------------------------------------------------------|------------------------------------------------|----------------------------------------------------------------------------------------------| -| Test if the deployment of failed cluster is rescheduled to other available cluster | deployment failover testing | [Failover](https://karmada.io/docs/next/userguide/failover/failover-overview) | -| Test if the deployment of taint cluster is rescheduled to other available cluster | taint cluster | | -| Test if the deployment will rescheduled to other available cluster | application failover with purgeMode graciously | [Application failover](https://karmada.io/docs/next/userguide/failover/application-failover) | -| Test if the deployment will never rescheduled to other available cluster | application failover with purgeMode never | | - -#### TODO -1. There are 2 way to evict the deployment of the Graciously PurgeMode, the third case cover the first way only, we may add a test case [when the GracePeriodSeconds is reach out](https://karmada.io/docs/next/userguide/failover/application-failover/#:~:text=after%20a%20timeout%20is%20reached%20before%20evicting%20the%20application). +| Test Case | E2E Describe Text | Comments | +|------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Test if the deployment of failed cluster is rescheduled to other available cluster | deployment failover testing | [Failover](https://karmada.io/docs/next/userguide/failover/failover-overview) | +| Test if the deployment of taint cluster is rescheduled to other available cluster | taint cluster | | +| Test if the deployment will rescheduled to other available cluster | application failover with purgeMode graciously when the application come back to healthy on the new cluster | [Application failover](https://karmada.io/docs/next/userguide/failover/application-failover/#:~:text=the%20legacy%20application.-,Graciously%20represents%20that%20Karmada%20will%20wait%20for%20the%20application%20to%20come%20back%20to%20healthy%20on%20the%20new%20cluster,-or%20after%20a) | +| Test if the deployment will rescheduled to other available cluster (timeout) | application failover with purgeMode graciously when the GracePeriodSeconds is reach out | [Application failover](https://karmada.io/docs/next/userguide/failover/application-failover/#:~:text=after%20a%20timeout%20is%20reached%20before%20evicting%20the%20application) | +| Test if the deployment will never rescheduled to other available cluster | application failover with purgeMode never | | diff --git a/test/e2e/failover_test.go b/test/e2e/failover_test.go index 071fab09953a..2900a03d61fa 100644 --- a/test/e2e/failover_test.go +++ b/test/e2e/failover_test.go @@ -19,6 +19,7 @@ package e2e import ( "context" "fmt" + "time" "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" @@ -26,6 +27,7 @@ import ( corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/rand" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/klog/v2" @@ -274,6 +276,7 @@ var _ = framework.SerialDescribe("failover testing", func() { var policy *policyv1alpha1.PropagationPolicy var overridePolicy *policyv1alpha1.OverridePolicy var maxGroups, minGroups int + var gracePeriodSeconds, tolerationSeconds int32 ginkgo.BeforeEach(func() { policyNamespace = testNamespace policyName = deploymentNamePrefix + rand.String(RandomStrLength) @@ -282,6 +285,8 @@ var _ = framework.SerialDescribe("failover testing", func() { deployment = testhelper.NewDeployment(deploymentNamespace, deploymentName) maxGroups = 1 minGroups = 1 + gracePeriodSeconds = 30 + tolerationSeconds = 30 policy = &policyv1alpha1.PropagationPolicy{ ObjectMeta: metav1.ObjectMeta{ @@ -312,10 +317,10 @@ var _ = framework.SerialDescribe("failover testing", func() { Failover: &policyv1alpha1.FailoverBehavior{ Application: &policyv1alpha1.ApplicationFailoverBehavior{ DecisionConditions: policyv1alpha1.DecisionConditions{ - TolerationSeconds: ptr.To[int32](30), + TolerationSeconds: ptr.To[int32](tolerationSeconds), }, PurgeMode: policyv1alpha1.Graciously, - GracePeriodSeconds: ptr.To[int32](30), + GracePeriodSeconds: ptr.To[int32](gracePeriodSeconds), }, }, }, @@ -331,7 +336,7 @@ var _ = framework.SerialDescribe("failover testing", func() { }) }) - ginkgo.It("application failover with purgeMode graciously", func() { + ginkgo.It("application failover with purgeMode graciously when the application come back to healthy on the new cluster", func() { disabledClusters := framework.ExtractTargetClustersFrom(controlPlaneClient, deployment) ginkgo.By("create an error op", func() { overridePolicy = testhelper.NewOverridePolicyByOverrideRules(policyNamespace, policyName, []policyv1alpha1.ResourceSelector{ @@ -393,6 +398,70 @@ var _ = framework.SerialDescribe("failover testing", func() { framework.RemoveOverridePolicy(karmadaClient, policyNamespace, policyName) }) }) + + ginkgo.It("application failover with purgeMode graciously when the GracePeriodSeconds is reach out", func() { + gracePeriodSeconds = 10 + ginkgo.By("update pp", func() { + // modify gracePeriodSeconds to create a time difference with tolerationSecond to avoid cluster interference + patch := []map[string]interface{}{ + { + "op": "replace", + "path": "/spec/failover/application/gracePeriodSeconds", + "value": ptr.To[int32](gracePeriodSeconds), + }, + } + framework.PatchPropagationPolicy(karmadaClient, policy.Namespace, policy.Name, patch, types.JSONPatchType) + }) + + disabledClusters := framework.ExtractTargetClustersFrom(controlPlaneClient, deployment) + var beginTime time.Time + ginkgo.By("create an error op", func() { + overridePolicy = testhelper.NewOverridePolicyByOverrideRules(policyNamespace, policyName, []policyv1alpha1.ResourceSelector{ + { + APIVersion: deployment.APIVersion, + Kind: deployment.Kind, + Name: deployment.Name, + }, + }, []policyv1alpha1.RuleWithCluster{ + { + TargetCluster: &policyv1alpha1.ClusterAffinity{ + // guarantee that application cannot come back to healthy on the new cluster + ClusterNames: framework.ClusterNames(), + }, + Overriders: policyv1alpha1.Overriders{ + ImageOverrider: []policyv1alpha1.ImageOverrider{ + { + Component: "Registry", + Operator: "replace", + Value: "fake", + }, + }, + }, + }, + }) + framework.CreateOverridePolicy(karmadaClient, overridePolicy) + beginTime = time.Now() + }) + defer framework.RemoveOverridePolicy(karmadaClient, policyNamespace, policyName) + + ginkgo.By("check if deployment present on member clusters has correct image value", func() { + framework.WaitDeploymentPresentOnClustersFitWith(disabledClusters, deployment.Namespace, deployment.Name, + func(deployment *appsv1.Deployment) bool { + for _, container := range deployment.Spec.Template.Spec.Containers { + if container.Image != "fake/nginx:1.19.0" { + return false + } + } + return true + }) + }) + + ginkgo.By("check whether application failover with purgeMode graciously when the GracePeriodSeconds is reach out", func() { + framework.WaitDeploymentDisappearOnClusters(disabledClusters, deploymentNamespace, deploymentName) + evictionTime := time.Now() + gomega.Expect(evictionTime.Sub(beginTime) > time.Duration(gracePeriodSeconds+tolerationSeconds)*time.Second).Should(gomega.BeTrue()) + }) + }) }) ginkgo.Context("Application failover testing with purgeMode never", func() { diff --git a/test/e2e/federatedresourcequota_test.go b/test/e2e/federatedresourcequota_test.go index 3878dac75cc5..7199f063716c 100644 --- a/test/e2e/federatedresourcequota_test.go +++ b/test/e2e/federatedresourcequota_test.go @@ -84,7 +84,7 @@ var _ = framework.SerialDescribe("FederatedResourceQuota auto-provision testing" var clusterContext string ginkgo.BeforeEach(func() { - clusterName = "member-e2e-" + rand.String(3) + clusterName = "member-e2e-" + rand.String(RandomStrLength) homeDir = os.Getenv("HOME") kubeConfigPath = fmt.Sprintf("%s/.kube/%s.config", homeDir, clusterName) controlPlane = fmt.Sprintf("%s-control-plane", clusterName) diff --git a/test/e2e/framework/events.go b/test/e2e/framework/events.go new file mode 100644 index 000000000000..a4795faa0711 --- /dev/null +++ b/test/e2e/framework/events.go @@ -0,0 +1,39 @@ +/* +Copyright 2024 The Karmada 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 framework + +import ( + "context" + "slices" + + "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/client-go/kubernetes" +) + +// WaitEventFitWith wait PropagationPolicy sync with fit func. +func WaitEventFitWith(kubeClient kubernetes.Interface, namespace string, involvedObj string, fit func(policy corev1.Event) bool) { + gomega.Eventually(func() bool { + eventList, err := kubeClient.CoreV1().Events(namespace).List(context.TODO(), metav1.ListOptions{ + FieldSelector: fields.OneTermEqualSelector("involvedObject.name", involvedObj).String(), + }) + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + return slices.ContainsFunc(eventList.Items, fit) + }, pollTimeout, pollInterval).Should(gomega.Equal(true)) +} diff --git a/test/e2e/framework/resourcebinding.go b/test/e2e/framework/resourcebinding.go index a48d5f2522e9..eb12b70ccd6f 100644 --- a/test/e2e/framework/resourcebinding.go +++ b/test/e2e/framework/resourcebinding.go @@ -50,17 +50,17 @@ func AssertBindingScheduledClusters(client karmada.Interface, namespace, name st if err != nil { return err } - scheduledClutsers := make([]string, 0, len(binding.Spec.Clusters)) + scheduledClusters := make([]string, 0, len(binding.Spec.Clusters)) for _, scheduledCluster := range binding.Spec.Clusters { - scheduledClutsers = append(scheduledClutsers, scheduledCluster.Name) + scheduledClusters = append(scheduledClusters, scheduledCluster.Name) } - sort.Strings(scheduledClutsers) - for _, expectedClutsers := range expectedResults { - if reflect.DeepEqual(scheduledClutsers, expectedClutsers) { + sort.Strings(scheduledClusters) + for _, expectedClusters := range expectedResults { + if reflect.DeepEqual(scheduledClusters, expectedClusters) { return nil } } - return fmt.Errorf("scheduled clusters: %+v, expected possible results: %+v", scheduledClutsers, expectedResults) + return fmt.Errorf("scheduled clusters: %+v, expected possible results: %+v", scheduledClusters, expectedResults) }, pollTimeout, pollInterval).ShouldNot(gomega.HaveOccurred()) }) } diff --git a/test/e2e/framework/workloadrebalancer.go b/test/e2e/framework/workloadrebalancer.go index d5f95c75b652..074d7caa1ef9 100644 --- a/test/e2e/framework/workloadrebalancer.go +++ b/test/e2e/framework/workloadrebalancer.go @@ -47,7 +47,7 @@ func RemoveWorkloadRebalancer(client karmada.Interface, name string) { }) } -// UpdateWorkloadRebalancer udpate WorkloadRebalancer with karmada client. +// UpdateWorkloadRebalancer updates WorkloadRebalancer with karmada client. // if workloads/ttl is a nil pointer, keep previous value unchanged. func UpdateWorkloadRebalancer(client karmada.Interface, name string, workloads *[]appsv1alpha1.ObjectReference, ttl *int32) { ginkgo.By(fmt.Sprintf("Updating WorkloadRebalancer(%s)'s workloads", name), func() { diff --git a/test/e2e/karmadactl_test.go b/test/e2e/karmadactl_test.go index dde15bbfb340..66556b095965 100644 --- a/test/e2e/karmadactl_test.go +++ b/test/e2e/karmadactl_test.go @@ -29,6 +29,7 @@ import ( appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" @@ -39,6 +40,7 @@ import ( bootstrapapi "k8s.io/cluster-bootstrap/token/api" "k8s.io/klog/v2" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/yaml" clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1" policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1" @@ -50,11 +52,11 @@ import ( "github.com/karmada-io/karmada/pkg/util/names" "github.com/karmada-io/karmada/test/e2e/framework" "github.com/karmada-io/karmada/test/helper" - testhelper "github.com/karmada-io/karmada/test/helper" ) const ( - karmadactlTimeout = time.Second * 10 + karmadactlTimeout = time.Second * 10 + PropagationPolicyPattern = `propagationpolicy\.policy\.karmada\.io\/([a-zA-Z0-9\-]+)` ) var _ = ginkgo.Describe("Karmadactl promote testing", func() { @@ -282,7 +284,7 @@ var _ = framework.SerialDescribe("Karmadactl join/unjoin testing", ginkgo.Labels var policy *policyv1alpha1.PropagationPolicy ginkgo.BeforeEach(func() { - clusterName = "member-e2e-" + rand.String(3) + clusterName = "member-e2e-" + rand.String(RandomStrLength) homeDir = os.Getenv("HOME") kubeConfigPath = fmt.Sprintf("%s/.kube/%s.config", homeDir, clusterName) clusterContext = fmt.Sprintf("kind-%s", clusterName) @@ -403,7 +405,7 @@ var _ = framework.SerialDescribe("Karmadactl cordon/uncordon testing", ginkgo.La var f cmdutil.Factory ginkgo.BeforeEach(func() { - clusterName = "member-e2e-" + rand.String(3) + clusterName = "member-e2e-" + rand.String(RandomStrLength) homeDir = os.Getenv("HOME") kubeConfigPath = fmt.Sprintf("%s/.kube/%s.config", homeDir, clusterName) controlPlane = fmt.Sprintf("%s-control-plane", clusterName) @@ -501,7 +503,7 @@ var _ = ginkgo.Describe("Karmadactl exec testing", func() { ginkgo.BeforeEach(func() { policyName = podNamePrefix + rand.String(RandomStrLength) pod = helper.NewPod(testNamespace, podNamePrefix+rand.String(RandomStrLength)) - policy = testhelper.NewPropagationPolicy(testNamespace, policyName, []policyv1alpha1.ResourceSelector{ + policy = helper.NewPropagationPolicy(testNamespace, policyName, []policyv1alpha1.ResourceSelector{ { APIVersion: pod.APIVersion, Kind: pod.Kind, @@ -530,7 +532,7 @@ var _ = ginkgo.Describe("Karmadactl exec testing", func() { }) for _, clusterName := range framework.ClusterNames() { - cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, pod.Namespace, karmadactlTimeout, "exec", pod.Name, "-C", clusterName, "--", "echo", "hello") + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, pod.Namespace, karmadactlTimeout, "exec", pod.Name, "--operation-scope", "members", "--cluster", clusterName, "--", "echo", "hello") _, err := cmd.ExecOrDie() gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) } @@ -544,7 +546,8 @@ var _ = ginkgo.Describe("Karmadactl top testing", func() { for _, clusterName := range framework.ClusterNames() { cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, "", karmadactlTimeout, "top", "pod", podName, "-n", testNamespace, "-C", clusterName) _, err := cmd.ExecOrDie() - gomega.Expect(strings.Contains(err.Error(), fmt.Sprintf("pods \"%s\" not found", podName))).To(gomega.BeTrue(), "should not found") + gomega.Expect(err).Should(gomega.HaveOccurred()) + gomega.Expect(strings.Contains(err.Error(), fmt.Sprintf("pods \"%s\" not found", podName))).To(gomega.BeTrue(), "should not found", fmt.Sprintf("errMsg: %s", err.Error())) } }) }) @@ -557,7 +560,7 @@ var _ = ginkgo.Describe("Karmadactl top testing", func() { // create a pod and a propagationPolicy policyName = podNamePrefix + rand.String(RandomStrLength) pod = helper.NewPod(testNamespace, podNamePrefix+rand.String(RandomStrLength)) - policy = testhelper.NewPropagationPolicy(testNamespace, policyName, []policyv1alpha1.ResourceSelector{ + policy = helper.NewPropagationPolicy(testNamespace, policyName, []policyv1alpha1.ResourceSelector{ { APIVersion: pod.APIVersion, Kind: pod.Kind, @@ -587,28 +590,30 @@ var _ = ginkgo.Describe("Karmadactl top testing", func() { }) ginkgo.It("Karmadactl top existing pod", func() { - for _, clusterName := range framework.ClusterNames() { - cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, pod.Namespace, karmadactlTimeout, "top", "pod", pod.Name, "-n", pod.Namespace, "-C", clusterName) + ginkgo.By("Karmadactl top existing pod", func() { + for _, clusterName := range framework.ClusterNames() { + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, pod.Namespace, karmadactlTimeout, "top", "pod", pod.Name, "-n", pod.Namespace, "-C", clusterName) + _, err := cmd.ExecOrDie() + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + } + }) + + ginkgo.By("Karmadactl top existing pod without setting cluster flag", func() { + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, pod.Namespace, karmadactlTimeout, "top", "pod", pod.Name, "-n", pod.Namespace) _, err := cmd.ExecOrDie() gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) - } - }) - - ginkgo.It("Karmadactl top existing pod without setting cluster flag", func() { - cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, pod.Namespace, karmadactlTimeout, "top", "pod", pod.Name, "-n", pod.Namespace) - _, err := cmd.ExecOrDie() - gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) - }) + }) - ginkgo.It("Karmadactl top pod without specific podName", func() { - cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, pod.Namespace, karmadactlTimeout, "top", "pod", "-A") - _, err := cmd.ExecOrDie() - gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) - for _, clusterName := range framework.ClusterNames() { - cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, pod.Namespace, karmadactlTimeout, "top", "pod", "-A", "-C", clusterName) + ginkgo.By("Karmadactl top pod without specific podName", func() { + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, pod.Namespace, karmadactlTimeout, "top", "pod", "-A") _, err := cmd.ExecOrDie() gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) - } + for _, clusterName := range framework.ClusterNames() { + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, pod.Namespace, karmadactlTimeout, "top", "pod", "-A", "-C", clusterName) + _, err := cmd.ExecOrDie() + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + } + }) }) }) }) @@ -800,6 +805,74 @@ var _ = ginkgo.Describe("Karmadactl get testing", func() { member1Client = framework.GetClusterClient(member1) }) + ginkgo.Context("Test operation scope switching", func() { + var deployment *appsv1.Deployment + var propagationPolicy *policyv1alpha1.PropagationPolicy + + ginkgo.BeforeEach(func() { + deployment = helper.NewDeployment(testNamespace, deploymentNamePrefix+rand.String(RandomStrLength)) + propagationPolicy = helper.NewPropagationPolicy(deployment.Namespace, ppNamePrefix+rand.String(RandomStrLength), []policyv1alpha1.ResourceSelector{ + { + APIVersion: deployment.APIVersion, + Kind: deployment.Kind, + Name: deployment.Name, + }, + }, policyv1alpha1.Placement{ + ClusterAffinity: &policyv1alpha1.ClusterAffinity{ClusterNames: framework.ClusterNames()}, + }) + }) + + ginkgo.BeforeEach(func() { + framework.CreateDeployment(kubeClient, deployment) + framework.CreatePropagationPolicy(karmadaClient, propagationPolicy) + + ginkgo.DeferCleanup(func() { + framework.RemoveDeployment(kubeClient, deployment.Namespace, deployment.Name) + framework.RemovePropagationPolicy(karmadaClient, propagationPolicy.Namespace, propagationPolicy.Name) + }) + }) + + ginkgo.It("should switch operation scope successfully", func() { + framework.WaitDeploymentPresentOnClustersFitWith(framework.ClusterNames(), deployment.Namespace, deployment.Name, + func(*appsv1.Deployment) bool { + return true + }) + + ginkgo.By("should display the deployment in Karmada control plane", func() { + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, deployment.Namespace, karmadactlTimeout, "get", "deployment", deployment.Name) + output, err := cmd.ExecOrDie() + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + gomega.Expect(strings.Contains(output, "Karmada")).Should(gomega.BeTrue()) + gomega.Expect(strings.Contains(output, member1)).ShouldNot(gomega.BeTrue()) + }) + + ginkgo.By("should display the deployment in Karmada control plane and member1", func() { + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, deployment.Namespace, karmadactlTimeout, "get", "deployment", deployment.Name, "--operation-scope", "all", "-C", member1) + output, err := cmd.ExecOrDie() + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + gomega.Expect(strings.Contains(output, "Karmada")).Should(gomega.BeTrue()) + gomega.Expect(strings.Contains(output, member1)).Should(gomega.BeTrue()) + gomega.Expect(strings.Contains(output, framework.ClusterNames()[1])).ShouldNot(gomega.BeTrue()) + }) + + ginkgo.By("should display the deployment in Karmada control plane and all member clusters", func() { + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, deployment.Namespace, karmadactlTimeout, "get", "deployment", deployment.Name, "--operation-scope", "all") + output, err := cmd.ExecOrDie() + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + gomega.Expect(strings.Contains(output, "Karmada")).Should(gomega.BeTrue()) + gomega.Expect(strings.Contains(output, member1)).Should(gomega.BeTrue()) + gomega.Expect(strings.Contains(output, framework.ClusterNames()[1])).Should(gomega.BeTrue()) + }) + + ginkgo.By("should ignore resources in Karmada control plane", func() { + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, deployment.Namespace, karmadactlTimeout, "get", "deployment", deployment.Name, "--operation-scope", "members") + output, err := cmd.ExecOrDie() + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + gomega.Expect(strings.Contains(output, "Karmada")).ShouldNot(gomega.BeTrue()) + }) + }) + }) + ginkgo.Context("Test karmadactl get for existing resource", func() { var ( namespace, podName string @@ -827,7 +900,7 @@ var _ = ginkgo.Describe("Karmadactl get testing", func() { }) ginkgo.It("should get the existing pod successfully", func() { - cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, namespace, karmadactlTimeout, "get", "pods", podName, "-C", member1) + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, namespace, karmadactlTimeout, "get", "pods", podName, "--operation-scope", "members", "-C", member1) output, err := cmd.ExecOrDie() gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) gomega.Expect(strings.Contains(output, podName)).Should(gomega.BeTrue()) @@ -856,7 +929,7 @@ var _ = ginkgo.Describe("Karmadactl get testing", func() { }) ginkgo.It("should return not found error for non-existing pod", func() { - cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, namespace, karmadactlTimeout, "get", "pods", podName, "-C", member1) + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, namespace, karmadactlTimeout, "get", "pods", podName, "--operation-scope", "members", "-C", member1) _, err := cmd.ExecOrDie() gomega.Expect(err).Should(gomega.HaveOccurred()) gomega.Expect(strings.Contains(err.Error(), fmt.Sprintf("pods \"%s\" not found", podName))).Should(gomega.BeTrue()) @@ -872,7 +945,7 @@ var _ = ginkgo.Describe("Karmadactl get testing", func() { }) ginkgo.It("should return not found error for non-existing namespace", func() { - cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, namespace, karmadactlTimeout, "get", "pods", podName, "-C", member1) + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, namespace, karmadactlTimeout, "get", "pods", podName, "--operation-scope", "members", "-C", member1) _, err := cmd.ExecOrDie() gomega.Expect(err).Should(gomega.HaveOccurred()) gomega.Expect(strings.Contains(err.Error(), fmt.Sprintf("namespaces \"%s\" not found", namespace))).Should(gomega.BeTrue()) @@ -887,7 +960,7 @@ var _ = ginkgo.Describe("Karmadactl get testing", func() { }) ginkgo.It("should return error for invalid resource type", func() { - cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, namespace, karmadactlTimeout, "get", "invalidresource", "invalidname", "-C", member1) + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, namespace, karmadactlTimeout, "get", "invalidresource", "invalidname") _, err := cmd.ExecOrDie() gomega.Expect(err).Should(gomega.HaveOccurred()) gomega.Expect(strings.Contains(err.Error(), "the server doesn't have a resource type \"invalidresource\"")).Should(gomega.BeTrue()) @@ -896,67 +969,62 @@ var _ = ginkgo.Describe("Karmadactl get testing", func() { }) var _ = ginkgo.Describe("Karmadactl describe testing", func() { - var member1 string - var member1Client kubernetes.Interface - - ginkgo.BeforeEach(func() { - member1 = framework.ClusterNames()[0] - member1Client = framework.GetClusterClient(member1) - }) - ginkgo.Context("Test karmadactl describe for existing resource", func() { - var namespace, podName string - var ( - ns *corev1.Namespace - pod *corev1.Pod - ) + var deployment *appsv1.Deployment + var propagationPolicy *policyv1alpha1.PropagationPolicy ginkgo.BeforeEach(func() { - namespace = fmt.Sprintf("karmadatest-%s", rand.String(RandomStrLength)) - podName = podNamePrefix + rand.String(RandomStrLength) - pod = helper.NewPod(namespace, podName) - ns = helper.NewNamespace(namespace) - // Create the namespace and pod in the member cluster. - _, err := member1Client.CoreV1().Namespaces().Create(context.TODO(), ns, metav1.CreateOptions{}) - gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) - - _, err = member1Client.CoreV1().Pods(namespace).Create(context.TODO(), pod, metav1.CreateOptions{}) - gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + deployment = helper.NewDeployment(testNamespace, deploymentNamePrefix+rand.String(RandomStrLength)) + propagationPolicy = helper.NewPropagationPolicy(deployment.Namespace, ppNamePrefix+rand.String(RandomStrLength), []policyv1alpha1.ResourceSelector{ + { + APIVersion: deployment.APIVersion, + Kind: deployment.Kind, + Name: deployment.Name, + }, + }, policyv1alpha1.Placement{ + ClusterAffinity: &policyv1alpha1.ClusterAffinity{ClusterNames: framework.ClusterNames()}, + }) }) - ginkgo.AfterEach(func() { - err := member1Client.CoreV1().Namespaces().Delete(context.TODO(), namespace, metav1.DeleteOptions{}) - gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + ginkgo.BeforeEach(func() { + framework.CreateDeployment(kubeClient, deployment) + framework.CreatePropagationPolicy(karmadaClient, propagationPolicy) + + ginkgo.DeferCleanup(func() { + framework.RemoveDeployment(kubeClient, deployment.Namespace, deployment.Name) + framework.RemovePropagationPolicy(karmadaClient, propagationPolicy.Namespace, propagationPolicy.Name) + }) }) ginkgo.It("should describe the existing pod successfully", func() { - cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, namespace, karmadactlTimeout, "describe", "pods", podName, "-C", member1) - output, err := cmd.ExecOrDie() - gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) - gomega.Expect(strings.Contains(output, podName)).Should(gomega.BeTrue()) + framework.WaitDeploymentPresentOnClustersFitWith(framework.ClusterNames(), deployment.Namespace, deployment.Name, + func(*appsv1.Deployment) bool { + return true + }) + ginkgo.By("should describe resources in Karmada control plane", func() { + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, testNamespace, karmadactlTimeout, "describe", "deployments", deployment.Name) + output, err := cmd.ExecOrDie() + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + gomega.Expect(strings.Contains(output, deployment.Name)).Should(gomega.BeTrue()) + }) + ginkgo.By("should describe resources in member1", func() { + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, testNamespace, karmadactlTimeout, "describe", "deployments", deployment.Name, "--operation-scope", "members", "--cluster", framework.ClusterNames()[0]) + output, err := cmd.ExecOrDie() + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + gomega.Expect(strings.Contains(output, deployment.Name)).Should(gomega.BeTrue()) + }) }) }) ginkgo.Context("Test karmadactl describe for non-existing resource", func() { - var namespace, podName string - var ns *corev1.Namespace + var podName string ginkgo.BeforeEach(func() { - namespace = fmt.Sprintf("karmadatest-%s", rand.String(RandomStrLength)) podName = podNamePrefix + rand.String(RandomStrLength) - ns = helper.NewNamespace(namespace) - // Create the namespace in the member cluster. - _, err := member1Client.CoreV1().Namespaces().Create(context.TODO(), ns, metav1.CreateOptions{}) - gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) - }) - - ginkgo.AfterEach(func() { - err := member1Client.CoreV1().Namespaces().Delete(context.TODO(), namespace, metav1.DeleteOptions{}) - gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) }) ginkgo.It("should return not found error for non-existing pod", func() { - cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, namespace, karmadactlTimeout, "describe", "pods", podName, "-C", member1) + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, testNamespace, karmadactlTimeout, "describe", "pods", podName) _, err := cmd.ExecOrDie() gomega.Expect(err).Should(gomega.HaveOccurred()) gomega.Expect(strings.Contains(err.Error(), fmt.Sprintf("pods \"%s\" not found", podName))).Should(gomega.BeTrue()) @@ -972,7 +1040,7 @@ var _ = ginkgo.Describe("Karmadactl describe testing", func() { }) ginkgo.It("should return not found error for non-existing namespace", func() { - cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, namespace, karmadactlTimeout, "describe", "pods", podName, "-C", member1) + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, namespace, karmadactlTimeout, "describe", "pods", podName) _, err := cmd.ExecOrDie() gomega.Expect(err).Should(gomega.HaveOccurred()) gomega.Expect(strings.Contains(err.Error(), fmt.Sprintf("namespaces \"%s\" not found", namespace))).Should(gomega.BeTrue()) @@ -987,7 +1055,7 @@ var _ = ginkgo.Describe("Karmadactl describe testing", func() { }) ginkgo.It("should return error for invalid resource type", func() { - cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, namespace, karmadactlTimeout, "describe", "invalidresource", "invalidname", "-C", member1) + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, namespace, karmadactlTimeout, "describe", "invalidresource", "invalidname") _, err := cmd.ExecOrDie() gomega.Expect(err).Should(gomega.HaveOccurred()) gomega.Expect(strings.Contains(err.Error(), "the server doesn't have a resource type \"invalidresource\"")).Should(gomega.BeTrue()) @@ -1246,7 +1314,7 @@ var _ = framework.SerialDescribe("Karmadactl taint testing", ginkgo.Labels{NeedC ) ginkgo.BeforeEach(func() { - newClusterName = "member-e2e-" + rand.String(3) + newClusterName = "member-e2e-" + rand.String(RandomStrLength) homeDir = os.Getenv("HOME") kubeConfigPath = fmt.Sprintf("%s/.kube/%s.config", homeDir, newClusterName) controlPlane = fmt.Sprintf("%s-control-plane", newClusterName) @@ -1392,6 +1460,184 @@ var _ = framework.SerialDescribe("Karmadactl taint testing", ginkgo.Labels{NeedC }) }) +var _ = ginkgo.Describe("Karmadactl apply testing", func() { + var ( + member1Name string + member1Client kubernetes.Interface + deploymentManifest string + deployment *appsv1.Deployment + ) + + ginkgo.BeforeEach(func() { + member1Name = framework.ClusterNames()[0] + member1Client = framework.GetClusterClient(member1Name) + }) + + ginkgo.BeforeEach(func() { + deployment = helper.NewDeployment(testNamespace, deploymentNamePrefix+rand.String(RandomStrLength)) + deploymentManifest = fmt.Sprintf("/tmp/%s.yaml", deployment.Name) + err := WriteYamlToFile(deployment, deploymentManifest) + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + ginkgo.DeferCleanup(func() { + os.Remove(deploymentManifest) + }) + }) + + ginkgo.It("should apply configuration without propagating into member clusters", func() { + // Apply configuration without propagation to member clusters. + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, "", karmadactlTimeout, "apply", "-f", deploymentManifest) + output, err := cmd.ExecOrDie() + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + gomega.Expect(output).Should(gomega.ContainSubstring(fmt.Sprintf("deployment.apps/%s created", deployment.Name))) + defer framework.RemoveDeployment(kubeClient, deployment.Namespace, deployment.Name) + + // Check that the deployment is created on karmada control plane. + framework.WaitDeploymentFitWith(kubeClient, deployment.Namespace, deployment.Name, func(_ *appsv1.Deployment) bool { + return true + }) + }) + + ginkgo.It("should apply configuration with propagation into specific member clusters", func() { + // Apply configuration with propagation to member1 cluster. + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, "", karmadactlTimeout, "apply", "-f", deploymentManifest, "--cluster", member1Name) + output, err := cmd.ExecOrDie() + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + gomega.Expect(output).Should(gomega.ContainSubstring(fmt.Sprintf("deployment.apps/%s created", deployment.Name))) + gomega.Expect(output).Should(gomega.MatchRegexp(PropagationPolicyPattern + ` created`)) + defer framework.RemoveDeployment(kubeClient, deployment.Namespace, deployment.Name) + + // Extract propagation policy name. + propagationPolicyName, err := extractPropagationPolicyName(output) + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + defer framework.RemovePropagationPolicy(karmadaClient, testNamespace, propagationPolicyName) + + // Check that the propagation policy is created on the karmada control plane in the given namespace. + framework.WaitPropagationPolicyFitWith(karmadaClient, testNamespace, propagationPolicyName, func(_ *policyv1alpha1.PropagationPolicy) bool { + return true + }) + + // Check that the deployment is created on the karmada control plane. + framework.WaitDeploymentFitWith(kubeClient, deployment.Namespace, deployment.Name, func(_ *appsv1.Deployment) bool { + return true + }) + + // Check that the deployment is propagated to the specified member1 cluster. + framework.WaitClusterFitWith(controlPlaneClient, member1Name, func(_ *clusterv1alpha1.Cluster) bool { + _, err := member1Client.AppsV1().Deployments(deployment.Namespace).Get(context.TODO(), deployment.Name, metav1.GetOptions{}) + return err == nil + }) + }) + + ginkgo.It("should apply the configuration and propagate to all member clusters", func() { + // Apply configuration and propagate to all member clusters. + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, "", karmadactlTimeout, "apply", "-f", deploymentManifest, "--all-clusters") + output, err := cmd.ExecOrDie() + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + gomega.Expect(output).Should(gomega.ContainSubstring(fmt.Sprintf("deployment.apps/%s created", deployment.Name))) + gomega.Expect(output).Should(gomega.MatchRegexp(PropagationPolicyPattern + ` created`)) + defer framework.RemoveDeployment(kubeClient, deployment.Namespace, deployment.Name) + + // Extract propagation policy name. + propagationPolicyName, err := extractPropagationPolicyName(output) + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + defer framework.RemovePropagationPolicy(karmadaClient, testNamespace, propagationPolicyName) + + // Check that the propagation policy is created on the karmada control plane in the given namespace. + framework.WaitPropagationPolicyFitWith(karmadaClient, testNamespace, propagationPolicyName, func(_ *policyv1alpha1.PropagationPolicy) bool { + return true + }) + + // Check that the deployment is created on the karmada control plane. + framework.WaitDeploymentFitWith(kubeClient, deployment.Namespace, deployment.Name, func(_ *appsv1.Deployment) bool { + return true + }) + + // Check that the deployment is propagated to all member clusters. + framework.WaitDeploymentPresentOnClustersFitWith(framework.ClusterNames(), deployment.Namespace, deployment.Name, func(_ *appsv1.Deployment) bool { + return true + }) + }) + + ginkgo.It("should run in dry-run mode without making any server requests", func() { + // Apply configuration in dry-run mode. + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, "", karmadactlTimeout, "apply", "-f", deploymentManifest, "--dry-run=client") + output, err := cmd.ExecOrDie() + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + gomega.Expect(output).Should(gomega.ContainSubstring(fmt.Sprintf("deployment.apps/%s", deployment.Name))) + + // Check that the deployment is not created on karmada control plane. + gomega.Eventually(func() bool { + _, err = kubeClient.AppsV1().Deployments(deployment.Namespace).Get(context.TODO(), deployment.Name, metav1.GetOptions{}) + return apierrors.IsNotFound(err) + }, pollTimeout, pollInterval).Should(gomega.Equal(true)) + }) + + ginkgo.It("should return error for invalid flag", func() { + // Apply configuration with invalid flag. + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, "", karmadactlTimeout, "apply", "-f", deploymentManifest, "--invalidflag") + _, err := cmd.ExecOrDie() + gomega.Expect(err).Should(gomega.HaveOccurred()) + gomega.Expect(strings.Contains(err.Error(), "unknown flag: --invalidflag")).Should(gomega.BeTrue()) + }) + + ginkgo.It("should return error if file does not exist", func() { + // Apply configuration from non-existent file. + nonExistentFile := "/tmp/non-existent.yaml" + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, "", karmadactlTimeout, "apply", "-f", nonExistentFile) + _, err := cmd.ExecOrDie() + gomega.Expect(err).Should(gomega.HaveOccurred()) + gomega.Expect(strings.Contains(err.Error(), fmt.Sprintf("error: the path \"%s\" does not exist", nonExistentFile))).Should(gomega.BeTrue()) + }) +}) + +// WriteYamlToFile writes the provided object as a YAML file to the specified path. +// +// Parameters: +// - obj: The object to be marshaled to YAML. +// - filePath: The path where the YAML file will be written. +// +// Returns: +// - error: An error if there was an issue during the process, otherwise nil. +func WriteYamlToFile(obj interface{}, filePath string) error { + // Marshal the object to YAML. + yamlData, err := yaml.Marshal(obj) + if err != nil { + return err + } + + // Create the file. + file, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) + if err != nil { + return err + } + defer file.Close() + + // Write the YAML data to the file. + _, err = file.Write(yamlData) + if err != nil { + return err + } + + return nil +} + +// extractPropagationPolicyName extracts the propagation policy name from the input string. +// +// Parameters: +// - input: The string containing the propagation policy information. +// +// Returns: +// - string: The extracted propagation policy name. +// - error: An error if the propagation policy name could not be found. +func extractPropagationPolicyName(input string) (string, error) { + re := regexp.MustCompile(PropagationPolicyPattern) + matches := re.FindStringSubmatch(input) + if len(matches) > 1 { + return matches[1], nil + } + return "", fmt.Errorf("no match found") +} + // extractTokenIDAndSecret extracts the token ID and Secret from the output string. // It assumes the output format is "tokenID.tokenSecret". // diff --git a/test/e2e/mcs_test.go b/test/e2e/mcs_test.go index 219dc9dbb0de..7372446f4825 100644 --- a/test/e2e/mcs_test.go +++ b/test/e2e/mcs_test.go @@ -42,7 +42,6 @@ import ( "github.com/karmada-io/karmada/pkg/util/names" "github.com/karmada-io/karmada/test/e2e/framework" "github.com/karmada-io/karmada/test/helper" - testhelper "github.com/karmada-io/karmada/test/helper" ) var ( @@ -155,7 +154,7 @@ func getPrepareInfo() (serviceExport mcsv1alpha1.ServiceExport, serviceImport mc exportPolicyNamespace := serviceExport.Namespace exportPolicyName := fmt.Sprintf("export-%s-policy", serviceExport.Name) - exportPolicy = testhelper.NewPropagationPolicy(exportPolicyNamespace, exportPolicyName, []policyv1alpha1.ResourceSelector{ + exportPolicy = helper.NewPropagationPolicy(exportPolicyNamespace, exportPolicyName, []policyv1alpha1.ResourceSelector{ { APIVersion: serviceExport.APIVersion, Kind: serviceExport.Kind, @@ -170,7 +169,7 @@ func getPrepareInfo() (serviceExport mcsv1alpha1.ServiceExport, serviceImport mc importPolicyNamespace := serviceImport.Namespace importPolicyName := fmt.Sprintf("import-%s-policy", serviceImport.Name) - importPolicy = testhelper.NewPropagationPolicy(importPolicyNamespace, importPolicyName, []policyv1alpha1.ResourceSelector{ + importPolicy = helper.NewPropagationPolicy(importPolicyNamespace, importPolicyName, []policyv1alpha1.ResourceSelector{ { APIVersion: serviceImport.APIVersion, Kind: serviceImport.Kind, @@ -209,7 +208,7 @@ var _ = ginkgo.Describe("Multi-Cluster Service testing", func() { serviceExportPolicyName = fmt.Sprintf("%s-%s-policy", serviceExportResource, rand.String(RandomStrLength)) serviceImportPolicyName = fmt.Sprintf("%s-%s-policy", serviceImportResource, rand.String(RandomStrLength)) - serviceExportPolicy = testhelper.NewClusterPropagationPolicy(serviceExportPolicyName, []policyv1alpha1.ResourceSelector{ + serviceExportPolicy = helper.NewClusterPropagationPolicy(serviceExportPolicyName, []policyv1alpha1.ResourceSelector{ { APIVersion: apiextensionsv1.SchemeGroupVersion.String(), Kind: util.CRDKind, @@ -220,7 +219,7 @@ var _ = ginkgo.Describe("Multi-Cluster Service testing", func() { ClusterNames: framework.ClusterNames(), }, }) - serviceImportPolicy = testhelper.NewClusterPropagationPolicy(serviceImportPolicyName, []policyv1alpha1.ResourceSelector{ + serviceImportPolicy = helper.NewClusterPropagationPolicy(serviceImportPolicyName, []policyv1alpha1.ResourceSelector{ { APIVersion: apiextensionsv1.SchemeGroupVersion.String(), Kind: util.CRDKind, diff --git a/test/e2e/namespace_test.go b/test/e2e/namespace_test.go index f019c4f1d3c7..dc8a2b06c410 100644 --- a/test/e2e/namespace_test.go +++ b/test/e2e/namespace_test.go @@ -45,7 +45,7 @@ var _ = ginkgo.Describe("[namespace auto-provision] namespace auto-provision tes var f cmdutil.Factory ginkgo.BeforeEach(func() { - namespaceName = "karmada-e2e-ns-" + rand.String(3) + namespaceName = "karmada-e2e-ns-" + rand.String(RandomStrLength) namespace = helper.NewNamespace(namespaceName) defaultConfigFlags := genericclioptions.NewConfigFlags(true).WithDeprecatedPasswordFlag().WithDiscoveryBurst(300).WithDiscoveryQPS(50.0) @@ -86,7 +86,7 @@ var _ = ginkgo.Describe("[namespace auto-provision] namespace auto-provision tes var clusterContext string ginkgo.BeforeEach(func() { - clusterName = "member-e2e-" + rand.String(3) + clusterName = "member-e2e-" + rand.String(RandomStrLength) homeDir = os.Getenv("HOME") kubeConfigPath = fmt.Sprintf("%s/.kube/%s.config", homeDir, clusterName) controlPlane = fmt.Sprintf("%s-control-plane", clusterName) diff --git a/test/e2e/propagationpolicy_test.go b/test/e2e/propagationpolicy_test.go index e23f2b606326..4dfc479ce594 100644 --- a/test/e2e/propagationpolicy_test.go +++ b/test/e2e/propagationpolicy_test.go @@ -30,6 +30,7 @@ import ( rbacv1 "k8s.io/api/rbac/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/labels" @@ -41,7 +42,11 @@ import ( "k8s.io/utils/ptr" policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1" + workv1alpha1 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha1" workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" + "github.com/karmada-io/karmada/pkg/controllers/execution" + "github.com/karmada-io/karmada/pkg/events" + "github.com/karmada-io/karmada/pkg/util/helper" "github.com/karmada-io/karmada/pkg/util/names" "github.com/karmada-io/karmada/test/e2e/framework" testhelper "github.com/karmada-io/karmada/test/helper" @@ -97,6 +102,15 @@ var _ = ginkgo.Describe("[BasicPropagation] propagation testing", func() { return *deployment.Spec.Replicas == updateDeploymentReplicas }) }) + + ginkgo.It("adds dispatching event with a dispatching message", func() { + workName := names.GenerateWorkName(deployment.Kind, deployment.Name, deployment.Namespace) + esName := names.GenerateExecutionSpaceName(framework.ClusterNames()[0]) + framework.WaitEventFitWith(kubeClient, esName, workName, func(event corev1.Event) bool { + return event.Reason == events.EventReasonWorkDispatching && + event.Message == execution.WorkDispatchingConditionMessage + }) + }) }) ginkgo.Context("Service propagation testing", func() { @@ -1134,25 +1148,34 @@ var _ = ginkgo.Describe("[Suspend] PropagationPolicy testing", func() { }) ginkgo.BeforeEach(func() { - framework.CreateDeployment(kubeClient, deployment) + framework.CreatePropagationPolicy(karmadaClient, policy) ginkgo.DeferCleanup(func() { - framework.RemoveDeployment(kubeClient, deployment.Namespace, deployment.Name) + framework.RemovePropagationPolicy(karmadaClient, policy.Namespace, policy.Name) }) + framework.CreateDeployment(kubeClient, deployment) + framework.WaitDeploymentPresentOnClusterFitWith(targetMember, deployment.Namespace, deployment.Name, + func(*appsv1.Deployment) bool { + return true + }) }) - ginkgo.Context("suspend the PropagationPolicy dispatching", func() { - ginkgo.BeforeEach(func() { - policy.Spec.Suspension = &policyv1alpha1.Suspension{ - Dispatching: ptr.To(true), - } + ginkgo.BeforeEach(func() { + policy.Spec.Suspension = &policyv1alpha1.Suspension{ + Dispatching: ptr.To(true), + } + framework.UpdatePropagationPolicyWithSpec(karmadaClient, policy.Namespace, policy.Name, policy.Spec) + }) - framework.CreatePropagationPolicy(karmadaClient, policy) + ginkgo.Context("suspend the PropagationPolicy dispatching", func() { + ginkgo.AfterEach(func() { + framework.RemoveDeployment(kubeClient, deployment.Namespace, deployment.Name) }) ginkgo.It("suspends ResourceBinding", func() { - framework.WaitResourceBindingFitWith(karmadaClient, deployment.Namespace, names.GenerateBindingName(deployment.Kind, deployment.Name), func(binding *workv1alpha2.ResourceBinding) bool { - return binding.Spec.Suspension != nil && ptr.Deref(binding.Spec.Suspension.Dispatching, false) - }) + framework.WaitResourceBindingFitWith(karmadaClient, deployment.Namespace, names.GenerateBindingName(deployment.Kind, deployment.Name), + func(binding *workv1alpha2.ResourceBinding) bool { + return binding.Spec.Suspension != nil && ptr.Deref(binding.Spec.Suspension.Dispatching, false) + }) }) ginkgo.It("suspends Work", func() { @@ -1163,8 +1186,61 @@ var _ = ginkgo.Describe("[Suspend] PropagationPolicy testing", func() { if err != nil { return false } - return work != nil && ptr.Deref(work.Spec.SuspendDispatching, false) + return work != nil && helper.IsWorkSuspendDispatching(work) }, pollTimeout, pollInterval).Should(gomega.Equal(true)) }) + + ginkgo.It("adds suspend dispatching condition to Work", func() { + workName := names.GenerateWorkName(deployment.Kind, deployment.Name, deployment.Namespace) + esName := names.GenerateExecutionSpaceName(targetMember) + gomega.Eventually(func() bool { + work, err := karmadaClient.WorkV1alpha1().Works(esName).Get(context.TODO(), workName, metav1.GetOptions{}) + if err != nil { + return false + } + return work != nil && meta.IsStatusConditionPresentAndEqual(work.Status.Conditions, workv1alpha1.WorkDispatching, metav1.ConditionFalse) + }, pollTimeout, pollInterval).Should(gomega.Equal(true)) + }) + + ginkgo.It("adds dispatching event with suspend message", func() { + workName := names.GenerateWorkName(deployment.Kind, deployment.Name, deployment.Namespace) + esName := names.GenerateExecutionSpaceName(targetMember) + framework.WaitEventFitWith(kubeClient, esName, workName, + func(event corev1.Event) bool { + return event.Reason == events.EventReasonWorkDispatching && + event.Message == execution.WorkSuspendDispatchingConditionMessage + }) + }) + }) + + ginkgo.Context("update resource in the control plane", func() { + ginkgo.JustBeforeEach(func() { + framework.UpdateDeploymentReplicas(kubeClient, deployment, updateDeploymentReplicas) + }) + + ginkgo.AfterEach(func() { + framework.RemoveDeployment(kubeClient, deployment.Namespace, deployment.Name) + }) + + ginkgo.It("suspends updating deployment replicas in member cluster", func() { + framework.WaitDeploymentPresentOnClusterFitWith(targetMember, deployment.Namespace, deployment.Name, + func(d *appsv1.Deployment) bool { + return *d.Spec.Replicas != updateDeploymentReplicas + }) + }) + + ginkgo.When("propagation is resumed", func() { + ginkgo.JustBeforeEach(func() { + policy.Spec.Suspension = &policyv1alpha1.Suspension{} + framework.UpdatePropagationPolicyWithSpec(karmadaClient, policy.Namespace, policy.Name, policy.Spec) + }) + + ginkgo.It("updates deployment replicas in member cluster", func() { + framework.WaitDeploymentPresentOnClusterFitWith(targetMember, deployment.Namespace, deployment.Name, + func(d *appsv1.Deployment) bool { + return *d.Spec.Replicas == updateDeploymentReplicas + }) + }) + }) }) }) diff --git a/test/e2e/rescheduling_test.go b/test/e2e/rescheduling_test.go index 3002b9e098f0..82b9e46564b3 100644 --- a/test/e2e/rescheduling_test.go +++ b/test/e2e/rescheduling_test.go @@ -52,7 +52,7 @@ var _ = ginkgo.Describe("[cluster unjoined] reschedule testing", func() { var f cmdutil.Factory ginkgo.BeforeEach(func() { - newClusterName = "member-e2e-" + rand.String(3) + newClusterName = "member-e2e-" + rand.String(RandomStrLength) homeDir = os.Getenv("HOME") kubeConfigPath = fmt.Sprintf("%s/.kube/%s.config", homeDir, newClusterName) controlPlane = fmt.Sprintf("%s-control-plane", newClusterName) @@ -173,7 +173,7 @@ var _ = ginkgo.Describe("[cluster joined] reschedule testing", func() { var f cmdutil.Factory ginkgo.BeforeEach(func() { - newClusterName = "member-e2e-" + rand.String(3) + newClusterName = "member-e2e-" + rand.String(RandomStrLength) homeDir = os.Getenv("HOME") kubeConfigPath = fmt.Sprintf("%s/.kube/%s.config", homeDir, newClusterName) controlPlane = fmt.Sprintf("%s-control-plane", newClusterName) diff --git a/test/e2e/resource_test.go b/test/e2e/resource_test.go index 21c960d19abe..971d24341dbf 100644 --- a/test/e2e/resource_test.go +++ b/test/e2e/resource_test.go @@ -172,12 +172,12 @@ var _ = ginkgo.Describe("[resource-status collection] resource status collection for index, clusterName := range framework.ClusterNames() { clusterClient := framework.GetClusterClient(clusterName) gomega.Expect(clusterClient).ShouldNot(gomega.BeNil()) - ingresses := []corev1.LoadBalancerIngress{{IP: fmt.Sprintf("172.19.1.%d", index+6)}} for _, ingress := range ingresses { svcLoadBalancer.Ingress = append(svcLoadBalancer.Ingress, corev1.LoadBalancerIngress{ IP: ingress.IP, Hostname: clusterName, + IPMode: ingress.IPMode, }) } @@ -198,8 +198,14 @@ var _ = ginkgo.Describe("[resource-status collection] resource status collection latestSvc, err := kubeClient.CoreV1().Services(serviceNamespace).Get(context.TODO(), serviceName, metav1.GetOptions{}) g.Expect(err).NotTo(gomega.HaveOccurred()) + // TODO: Once karmada-apiserver v1.30 deploy by default,delete the following five lines, see https://github.com/karmada-io/karmada/pull/5141 + for i := range latestSvc.Status.LoadBalancer.Ingress { + if latestSvc.Status.LoadBalancer.Ingress[i].IPMode != nil { + latestSvc.Status.LoadBalancer.Ingress[i].IPMode = nil + } + } klog.Infof("the latest serviceStatus loadBalancer: %v", latestSvc.Status.LoadBalancer) - return reflect.DeepEqual(latestSvc.Status.LoadBalancer, svcLoadBalancer), nil + return reflect.DeepEqual(latestSvc.Status.LoadBalancer.Ingress, svcLoadBalancer.Ingress), nil }, pollTimeout, pollInterval).Should(gomega.Equal(true)) }) }) @@ -447,12 +453,10 @@ var _ = ginkgo.Describe("[resource-status collection] resource status collection currentDaemonSet, err := kubeClient.AppsV1().DaemonSets(daemonSetNamespace).Get(context.TODO(), daemonSetName, metav1.GetOptions{}) g.Expect(err).ShouldNot(gomega.HaveOccurred()) - klog.Infof("daemonSet(%s/%s) replicas: %d, wanted replicas: %d", daemonSetNamespace, daemonSetName, currentDaemonSet.Status.NumberReady, wantedReplicas) - if currentDaemonSet.Status.NumberReady == wantedReplicas && - currentDaemonSet.Status.CurrentNumberScheduled == wantedReplicas && + klog.Infof("daemonSet(%s/%s) current scheduled replicas: %d, wanted replicas: %d", daemonSetNamespace, daemonSetName, currentDaemonSet.Status.CurrentNumberScheduled, wantedReplicas) + if currentDaemonSet.Status.CurrentNumberScheduled == wantedReplicas && currentDaemonSet.Status.DesiredNumberScheduled == wantedReplicas && - currentDaemonSet.Status.UpdatedNumberScheduled == wantedReplicas && - currentDaemonSet.Status.NumberAvailable == wantedReplicas { + currentDaemonSet.Status.UpdatedNumberScheduled == wantedReplicas { return true, nil } @@ -470,11 +474,9 @@ var _ = ginkgo.Describe("[resource-status collection] resource status collection currentDaemonSet, err := kubeClient.AppsV1().DaemonSets(daemonSetNamespace).Get(context.TODO(), daemonSetName, metav1.GetOptions{}) g.Expect(err).ShouldNot(gomega.HaveOccurred()) - if currentDaemonSet.Status.NumberReady == wantedReplicas && - currentDaemonSet.Status.CurrentNumberScheduled == wantedReplicas && + if currentDaemonSet.Status.CurrentNumberScheduled == wantedReplicas && currentDaemonSet.Status.DesiredNumberScheduled == wantedReplicas && - currentDaemonSet.Status.UpdatedNumberScheduled == wantedReplicas && - currentDaemonSet.Status.NumberAvailable == wantedReplicas { + currentDaemonSet.Status.UpdatedNumberScheduled == wantedReplicas { return true, nil } @@ -569,9 +571,13 @@ var _ = ginkgo.Describe("[resource-status collection] resource status collection pdbNamespace = testNamespace pdbName = policyName deploymentName := policyName + // use a special label value to prevent PDB from selecting pods of other parallel e2e cases. + matchLabels := map[string]string{"app": "nginx-" + rand.String(RandomStrLength)} deployment = testhelper.NewDeployment(pdbNamespace, deploymentName) - pdb = testhelper.NewPodDisruptionBudget(pdbNamespace, pdbName, intstr.FromString("50%")) + deployment.Spec.Selector.MatchLabels = matchLabels + deployment.Spec.Template.Labels = matchLabels + pdb = testhelper.NewPodDisruptionBudget(pdbNamespace, pdbName, intstr.FromString("50%"), matchLabels) policy = testhelper.NewPropagationPolicy(policyNamespace, policyName, []policyv1alpha1.ResourceSelector{ { APIVersion: pdb.APIVersion, diff --git a/test/helper/resource.go b/test/helper/resource.go index 3456beadb649..5f001efa7118 100644 --- a/test/helper/resource.go +++ b/test/helper/resource.go @@ -936,9 +936,7 @@ func NewIngress(namespace, name string) *networkingv1.Ingress { } // NewPodDisruptionBudget will build a new PodDisruptionBudget object. -func NewPodDisruptionBudget(namespace, name string, maxUnAvailable intstr.IntOrString) *policyv1.PodDisruptionBudget { - podLabels := map[string]string{"app": "nginx"} - +func NewPodDisruptionBudget(namespace, name string, maxUnAvailable intstr.IntOrString, matchLabels map[string]string) *policyv1.PodDisruptionBudget { return &policyv1.PodDisruptionBudget{ TypeMeta: metav1.TypeMeta{ APIVersion: "policy/v1", @@ -951,7 +949,7 @@ func NewPodDisruptionBudget(namespace, name string, maxUnAvailable intstr.IntOrS Spec: policyv1.PodDisruptionBudgetSpec{ MaxUnavailable: &maxUnAvailable, Selector: &metav1.LabelSelector{ - MatchLabels: podLabels, + MatchLabels: matchLabels, }, }, } @@ -960,6 +958,10 @@ func NewPodDisruptionBudget(namespace, name string, maxUnAvailable intstr.IntOrS // NewWork will build a new Work object. func NewWork(workName, workNs, workUID string, raw []byte) *workv1alpha1.Work { work := &workv1alpha1.Work{ + TypeMeta: metav1.TypeMeta{ + Kind: workv1alpha1.ResourceKindWork, + APIVersion: workv1alpha1.GroupVersion.Version, + }, ObjectMeta: metav1.ObjectMeta{ Name: workName, Namespace: workNs, diff --git a/vendor/github.com/BurntSushi/toml/.gitignore b/vendor/github.com/BurntSushi/toml/.gitignore index cd11be965309..fe79e3adda29 100644 --- a/vendor/github.com/BurntSushi/toml/.gitignore +++ b/vendor/github.com/BurntSushi/toml/.gitignore @@ -1,2 +1,2 @@ -toml.test +/toml.test /toml-test diff --git a/vendor/github.com/BurntSushi/toml/COMPATIBLE b/vendor/github.com/BurntSushi/toml/COMPATIBLE deleted file mode 100644 index f621b01196cb..000000000000 --- a/vendor/github.com/BurntSushi/toml/COMPATIBLE +++ /dev/null @@ -1 +0,0 @@ -Compatible with TOML version [v1.0.0](https://toml.io/en/v1.0.0). diff --git a/vendor/github.com/BurntSushi/toml/README.md b/vendor/github.com/BurntSushi/toml/README.md index cc13f8667fbd..639e6c39983d 100644 --- a/vendor/github.com/BurntSushi/toml/README.md +++ b/vendor/github.com/BurntSushi/toml/README.md @@ -1,6 +1,5 @@ TOML stands for Tom's Obvious, Minimal Language. This Go package provides a -reflection interface similar to Go's standard library `json` and `xml` -packages. +reflection interface similar to Go's standard library `json` and `xml` packages. Compatible with TOML version [v1.0.0](https://toml.io/en/v1.0.0). @@ -10,7 +9,7 @@ See the [releases page](https://github.com/BurntSushi/toml/releases) for a changelog; this information is also in the git tag annotations (e.g. `git show v0.4.0`). -This library requires Go 1.13 or newer; install it with: +This library requires Go 1.18 or newer; add it to your go.mod with: % go get github.com/BurntSushi/toml@latest @@ -19,16 +18,7 @@ It also comes with a TOML validator CLI tool: % go install github.com/BurntSushi/toml/cmd/tomlv@latest % tomlv some-toml-file.toml -### Testing -This package passes all tests in [toml-test] for both the decoder and the -encoder. - -[toml-test]: https://github.com/BurntSushi/toml-test - ### Examples -This package works similar to how the Go standard library handles XML and JSON. -Namely, data is loaded into Go values via reflection. - For the simplest example, consider some TOML file as just a list of keys and values: @@ -40,7 +30,7 @@ Perfection = [ 6, 28, 496, 8128 ] DOB = 1987-07-05T05:45:00Z ``` -Which could be defined in Go as: +Which can be decoded with: ```go type Config struct { @@ -48,20 +38,15 @@ type Config struct { Cats []string Pi float64 Perfection []int - DOB time.Time // requires `import time` + DOB time.Time } -``` - -And then decoded with: -```go var conf Config -err := toml.Decode(tomlData, &conf) -// handle error +_, err := toml.Decode(tomlData, &conf) ``` -You can also use struct tags if your struct field name doesn't map to a TOML -key value directly: +You can also use struct tags if your struct field name doesn't map to a TOML key +value directly: ```toml some_key_NAME = "wat" @@ -73,139 +58,63 @@ type TOML struct { } ``` -Beware that like other most other decoders **only exported fields** are -considered when encoding and decoding; private fields are silently ignored. +Beware that like other decoders **only exported fields** are considered when +encoding and decoding; private fields are silently ignored. ### Using the `Marshaler` and `encoding.TextUnmarshaler` interfaces -Here's an example that automatically parses duration strings into -`time.Duration` values: +Here's an example that automatically parses values in a `mail.Address`: ```toml -[[song]] -name = "Thunder Road" -duration = "4m49s" - -[[song]] -name = "Stairway to Heaven" -duration = "8m03s" -``` - -Which can be decoded with: - -```go -type song struct { - Name string - Duration duration -} -type songs struct { - Song []song -} -var favorites songs -if _, err := toml.Decode(blob, &favorites); err != nil { - log.Fatal(err) -} - -for _, s := range favorites.Song { - fmt.Printf("%s (%s)\n", s.Name, s.Duration) -} +contacts = [ + "Donald Duck ", + "Scrooge McDuck ", +] ``` -And you'll also need a `duration` type that satisfies the -`encoding.TextUnmarshaler` interface: +Can be decoded with: ```go -type duration struct { - time.Duration +// Create address type which satisfies the encoding.TextUnmarshaler interface. +type address struct { + *mail.Address } -func (d *duration) UnmarshalText(text []byte) error { +func (a *address) UnmarshalText(text []byte) error { var err error - d.Duration, err = time.ParseDuration(string(text)) + a.Address, err = mail.ParseAddress(string(text)) return err } + +// Decode it. +func decode() { + blob := ` + contacts = [ + "Donald Duck ", + "Scrooge McDuck ", + ] + ` + + var contacts struct { + Contacts []address + } + + _, err := toml.Decode(blob, &contacts) + if err != nil { + log.Fatal(err) + } + + for _, c := range contacts.Contacts { + fmt.Printf("%#v\n", c.Address) + } + + // Output: + // &mail.Address{Name:"Donald Duck", Address:"donald@duckburg.com"} + // &mail.Address{Name:"Scrooge McDuck", Address:"scrooge@duckburg.com"} +} ``` To target TOML specifically you can implement `UnmarshalTOML` TOML interface in a similar way. ### More complex usage -Here's an example of how to load the example from the official spec page: - -```toml -# This is a TOML document. Boom. - -title = "TOML Example" - -[owner] -name = "Tom Preston-Werner" -organization = "GitHub" -bio = "GitHub Cofounder & CEO\nLikes tater tots and beer." -dob = 1979-05-27T07:32:00Z # First class dates? Why not? - -[database] -server = "192.168.1.1" -ports = [ 8001, 8001, 8002 ] -connection_max = 5000 -enabled = true - -[servers] - - # You can indent as you please. Tabs or spaces. TOML don't care. - [servers.alpha] - ip = "10.0.0.1" - dc = "eqdc10" - - [servers.beta] - ip = "10.0.0.2" - dc = "eqdc10" - -[clients] -data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it - -# Line breaks are OK when inside arrays -hosts = [ - "alpha", - "omega" -] -``` - -And the corresponding Go types are: - -```go -type tomlConfig struct { - Title string - Owner ownerInfo - DB database `toml:"database"` - Servers map[string]server - Clients clients -} - -type ownerInfo struct { - Name string - Org string `toml:"organization"` - Bio string - DOB time.Time -} - -type database struct { - Server string - Ports []int - ConnMax int `toml:"connection_max"` - Enabled bool -} - -type server struct { - IP string - DC string -} - -type clients struct { - Data [][]interface{} - Hosts []string -} -``` - -Note that a case insensitive match will be tried if an exact match can't be -found. - -A working example of the above can be found in `_example/example.{go,toml}`. +See the [`_example/`](/_example) directory for a more complex example. diff --git a/vendor/github.com/BurntSushi/toml/decode.go b/vendor/github.com/BurntSushi/toml/decode.go index e24f0c5d5c04..7aaf462c94a4 100644 --- a/vendor/github.com/BurntSushi/toml/decode.go +++ b/vendor/github.com/BurntSushi/toml/decode.go @@ -1,32 +1,66 @@ package toml import ( + "bytes" "encoding" + "encoding/json" "fmt" "io" - "io/ioutil" + "io/fs" "math" "os" "reflect" + "strconv" "strings" + "time" ) // Unmarshaler is the interface implemented by objects that can unmarshal a // TOML description of themselves. type Unmarshaler interface { - UnmarshalTOML(interface{}) error + UnmarshalTOML(any) error } -// Unmarshal decodes the contents of `p` in TOML format into a pointer `v`. -func Unmarshal(p []byte, v interface{}) error { - _, err := Decode(string(p), v) +// Unmarshal decodes the contents of data in TOML format into a pointer v. +// +// See [Decoder] for a description of the decoding process. +func Unmarshal(data []byte, v any) error { + _, err := NewDecoder(bytes.NewReader(data)).Decode(v) return err } +// Decode the TOML data in to the pointer v. +// +// See [Decoder] for a description of the decoding process. +func Decode(data string, v any) (MetaData, error) { + return NewDecoder(strings.NewReader(data)).Decode(v) +} + +// DecodeFile reads the contents of a file and decodes it with [Decode]. +func DecodeFile(path string, v any) (MetaData, error) { + fp, err := os.Open(path) + if err != nil { + return MetaData{}, err + } + defer fp.Close() + return NewDecoder(fp).Decode(v) +} + +// DecodeFS reads the contents of a file from [fs.FS] and decodes it with +// [Decode]. +func DecodeFS(fsys fs.FS, path string, v any) (MetaData, error) { + fp, err := fsys.Open(path) + if err != nil { + return MetaData{}, err + } + defer fp.Close() + return NewDecoder(fp).Decode(v) +} + // Primitive is a TOML value that hasn't been decoded into a Go value. // // This type can be used for any value, which will cause decoding to be delayed. -// You can use the PrimitiveDecode() function to "manually" decode these values. +// You can use [PrimitiveDecode] to "manually" decode these values. // // NOTE: The underlying representation of a `Primitive` value is subject to // change. Do not rely on it. @@ -35,43 +69,29 @@ func Unmarshal(p []byte, v interface{}) error { // overhead of reflection. They can be useful when you don't know the exact type // of TOML data until runtime. type Primitive struct { - undecoded interface{} + undecoded any context Key } // The significand precision for float32 and float64 is 24 and 53 bits; this is // the range a natural number can be stored in a float without loss of data. const ( - maxSafeFloat32Int = 16777215 // 2^24-1 - maxSafeFloat64Int = 9007199254740991 // 2^53-1 + maxSafeFloat32Int = 16777215 // 2^24-1 + maxSafeFloat64Int = int64(9007199254740991) // 2^53-1 ) -// PrimitiveDecode is just like the other `Decode*` functions, except it -// decodes a TOML value that has already been parsed. Valid primitive values -// can *only* be obtained from values filled by the decoder functions, -// including this method. (i.e., `v` may contain more `Primitive` -// values.) -// -// Meta data for primitive values is included in the meta data returned by -// the `Decode*` functions with one exception: keys returned by the Undecoded -// method will only reflect keys that were decoded. Namely, any keys hidden -// behind a Primitive will be considered undecoded. Executing this method will -// update the undecoded keys in the meta data. (See the example.) -func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error { - md.context = primValue.context - defer func() { md.context = nil }() - return md.unify(primValue.undecoded, rvalue(v)) -} - // Decoder decodes TOML data. // -// TOML tables correspond to Go structs or maps (dealer's choice – they can be -// used interchangeably). +// TOML tables correspond to Go structs or maps; they can be used +// interchangeably, but structs offer better type safety. // // TOML table arrays correspond to either a slice of structs or a slice of maps. // -// TOML datetimes correspond to Go time.Time values. Local datetimes are parsed -// in the local timezone. +// TOML datetimes correspond to [time.Time]. Local datetimes are parsed in the +// local timezone. +// +// [time.Duration] types are treated as nanoseconds if the TOML value is an +// integer, or they're parsed with time.ParseDuration() if they're strings. // // All other TOML types (float, string, int, bool and array) correspond to the // obvious Go types. @@ -80,9 +100,9 @@ func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error { // interface, in which case any primitive TOML value (floats, strings, integers, // booleans, datetimes) will be converted to a []byte and given to the value's // UnmarshalText method. See the Unmarshaler example for a demonstration with -// time duration strings. +// email addresses. // -// Key mapping +// # Key mapping // // TOML keys can map to either keys in a Go map or field names in a Go struct. // The special `toml` struct tag can be used to map TOML keys to struct fields @@ -109,10 +129,11 @@ func NewDecoder(r io.Reader) *Decoder { var ( unmarshalToml = reflect.TypeOf((*Unmarshaler)(nil)).Elem() unmarshalText = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() + primitiveType = reflect.TypeOf((*Primitive)(nil)).Elem() ) // Decode TOML data in to the pointer `v`. -func (dec *Decoder) Decode(v interface{}) (MetaData, error) { +func (dec *Decoder) Decode(v any) (MetaData, error) { rv := reflect.ValueOf(v) if rv.Kind() != reflect.Ptr { s := "%q" @@ -120,25 +141,25 @@ func (dec *Decoder) Decode(v interface{}) (MetaData, error) { s = "%v" } - return MetaData{}, e("cannot decode to non-pointer "+s, reflect.TypeOf(v)) + return MetaData{}, fmt.Errorf("toml: cannot decode to non-pointer "+s, reflect.TypeOf(v)) } if rv.IsNil() { - return MetaData{}, e("cannot decode to nil value of %q", reflect.TypeOf(v)) + return MetaData{}, fmt.Errorf("toml: cannot decode to nil value of %q", reflect.TypeOf(v)) } - // Check if this is a supported type: struct, map, interface{}, or something - // that implements UnmarshalTOML or UnmarshalText. + // Check if this is a supported type: struct, map, any, or something that + // implements UnmarshalTOML or UnmarshalText. rv = indirect(rv) rt := rv.Type() if rv.Kind() != reflect.Struct && rv.Kind() != reflect.Map && !(rv.Kind() == reflect.Interface && rv.NumMethod() == 0) && !rt.Implements(unmarshalToml) && !rt.Implements(unmarshalText) { - return MetaData{}, e("cannot decode to type %s", rt) + return MetaData{}, fmt.Errorf("toml: cannot decode to type %s", rt) } // TODO: parser should read from io.Reader? Or at the very least, make it // read from []byte rather than string - data, err := ioutil.ReadAll(dec.r) + data, err := io.ReadAll(dec.r) if err != nil { return MetaData{}, err } @@ -150,30 +171,29 @@ func (dec *Decoder) Decode(v interface{}) (MetaData, error) { md := MetaData{ mapping: p.mapping, - types: p.types, + keyInfo: p.keyInfo, keys: p.ordered, decoded: make(map[string]struct{}, len(p.ordered)), context: nil, + data: data, } return md, md.unify(p.mapping, rv) } -// Decode the TOML data in to the pointer v. +// PrimitiveDecode is just like the other Decode* functions, except it decodes a +// TOML value that has already been parsed. Valid primitive values can *only* be +// obtained from values filled by the decoder functions, including this method. +// (i.e., v may contain more [Primitive] values.) // -// See the documentation on Decoder for a description of the decoding process. -func Decode(data string, v interface{}) (MetaData, error) { - return NewDecoder(strings.NewReader(data)).Decode(v) -} - -// DecodeFile is just like Decode, except it will automatically read the -// contents of the file at path and decode it for you. -func DecodeFile(path string, v interface{}) (MetaData, error) { - fp, err := os.Open(path) - if err != nil { - return MetaData{}, err - } - defer fp.Close() - return NewDecoder(fp).Decode(v) +// Meta data for primitive values is included in the meta data returned by the +// Decode* functions with one exception: keys returned by the Undecoded method +// will only reflect keys that were decoded. Namely, any keys hidden behind a +// Primitive will be considered undecoded. Executing this method will update the +// undecoded keys in the meta data. (See the example.) +func (md *MetaData) PrimitiveDecode(primValue Primitive, v any) error { + md.context = primValue.context + defer func() { md.context = nil }() + return md.unify(primValue.undecoded, rvalue(v)) } // unify performs a sort of type unification based on the structure of `rv`, @@ -181,10 +201,10 @@ func DecodeFile(path string, v interface{}) (MetaData, error) { // // Any type mismatch produces an error. Finding a type that we don't know // how to handle produces an unsupported type error. -func (md *MetaData) unify(data interface{}, rv reflect.Value) error { +func (md *MetaData) unify(data any, rv reflect.Value) error { // Special case. Look for a `Primitive` value. // TODO: #76 would make this superfluous after implemented. - if rv.Type() == reflect.TypeOf((*Primitive)(nil)).Elem() { + if rv.Type() == primitiveType { // Save the undecoded data and the key context into the primitive // value. context := make(Key, len(md.context)) @@ -196,17 +216,18 @@ func (md *MetaData) unify(data interface{}, rv reflect.Value) error { return nil } - // Special case. Unmarshaler Interface support. - if rv.CanAddr() { - if v, ok := rv.Addr().Interface().(Unmarshaler); ok { - return v.UnmarshalTOML(data) + rvi := rv.Interface() + if v, ok := rvi.(Unmarshaler); ok { + err := v.UnmarshalTOML(data) + if err != nil { + return md.parseErr(err) } + return nil } - - // Special case. Look for a value satisfying the TextUnmarshaler interface. - if v, ok := rv.Interface().(encoding.TextUnmarshaler); ok { + if v, ok := rvi.(encoding.TextUnmarshaler); ok { return md.unifyText(data, v) } + // TODO: // The behavior here is incorrect whenever a Go type satisfies the // encoding.TextUnmarshaler interface but also corresponds to a TOML hash or @@ -217,19 +238,10 @@ func (md *MetaData) unify(data interface{}, rv reflect.Value) error { k := rv.Kind() - // laziness if k >= reflect.Int && k <= reflect.Uint64 { return md.unifyInt(data, rv) } switch k { - case reflect.Ptr: - elem := reflect.New(rv.Type().Elem()) - err := md.unify(data, reflect.Indirect(elem)) - if err != nil { - return err - } - rv.Set(elem) - return nil case reflect.Struct: return md.unifyStruct(data, rv) case reflect.Map: @@ -243,25 +255,23 @@ func (md *MetaData) unify(data interface{}, rv reflect.Value) error { case reflect.Bool: return md.unifyBool(data, rv) case reflect.Interface: - // we only support empty interfaces. - if rv.NumMethod() > 0 { - return e("unsupported type %s", rv.Type()) + if rv.NumMethod() > 0 { /// Only empty interfaces are supported. + return md.e("unsupported type %s", rv.Type()) } return md.unifyAnything(data, rv) case reflect.Float32, reflect.Float64: return md.unifyFloat64(data, rv) } - return e("unsupported type %s", rv.Kind()) + return md.e("unsupported type %s", rv.Kind()) } -func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error { - tmap, ok := mapping.(map[string]interface{}) +func (md *MetaData) unifyStruct(mapping any, rv reflect.Value) error { + tmap, ok := mapping.(map[string]any) if !ok { if mapping == nil { return nil } - return e("type mismatch for %s: expected table but found %T", - rv.Type().String(), mapping) + return md.e("type mismatch for %s: expected table but found %s", rv.Type().String(), fmtType(mapping)) } for key, datum := range tmap { @@ -286,27 +296,28 @@ func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error { if isUnifiable(subv) { md.decoded[md.context.add(key).String()] = struct{}{} md.context = append(md.context, key) + err := md.unify(datum, subv) if err != nil { return err } md.context = md.context[0 : len(md.context)-1] } else if f.name != "" { - return e("cannot write unexported field %s.%s", rv.Type().String(), f.name) + return md.e("cannot write unexported field %s.%s", rv.Type().String(), f.name) } } } return nil } -func (md *MetaData) unifyMap(mapping interface{}, rv reflect.Value) error { - if k := rv.Type().Key().Kind(); k != reflect.String { - return fmt.Errorf( - "toml: cannot decode to a map with non-string key type (%s in %q)", - k, rv.Type()) +func (md *MetaData) unifyMap(mapping any, rv reflect.Value) error { + keyType := rv.Type().Key().Kind() + if keyType != reflect.String && keyType != reflect.Interface { + return fmt.Errorf("toml: cannot decode to a map with non-string key type (%s in %q)", + keyType, rv.Type()) } - tmap, ok := mapping.(map[string]interface{}) + tmap, ok := mapping.(map[string]any) if !ok { if tmap == nil { return nil @@ -321,19 +332,28 @@ func (md *MetaData) unifyMap(mapping interface{}, rv reflect.Value) error { md.context = append(md.context, k) rvval := reflect.Indirect(reflect.New(rv.Type().Elem())) - if err := md.unify(v, rvval); err != nil { + + err := md.unify(v, indirect(rvval)) + if err != nil { return err } md.context = md.context[0 : len(md.context)-1] rvkey := indirect(reflect.New(rv.Type().Key())) - rvkey.SetString(k) + + switch keyType { + case reflect.Interface: + rvkey.Set(reflect.ValueOf(k)) + case reflect.String: + rvkey.SetString(k) + } + rv.SetMapIndex(rvkey, rvval) } return nil } -func (md *MetaData) unifyArray(data interface{}, rv reflect.Value) error { +func (md *MetaData) unifyArray(data any, rv reflect.Value) error { datav := reflect.ValueOf(data) if datav.Kind() != reflect.Slice { if !datav.IsValid() { @@ -342,12 +362,12 @@ func (md *MetaData) unifyArray(data interface{}, rv reflect.Value) error { return md.badtype("slice", data) } if l := datav.Len(); l != rv.Len() { - return e("expected array length %d; got TOML array of length %d", rv.Len(), l) + return md.e("expected array length %d; got TOML array of length %d", rv.Len(), l) } return md.unifySliceArray(datav, rv) } -func (md *MetaData) unifySlice(data interface{}, rv reflect.Value) error { +func (md *MetaData) unifySlice(data any, rv reflect.Value) error { datav := reflect.ValueOf(data) if datav.Kind() != reflect.Slice { if !datav.IsValid() { @@ -374,7 +394,19 @@ func (md *MetaData) unifySliceArray(data, rv reflect.Value) error { return nil } -func (md *MetaData) unifyString(data interface{}, rv reflect.Value) error { +func (md *MetaData) unifyString(data any, rv reflect.Value) error { + _, ok := rv.Interface().(json.Number) + if ok { + if i, ok := data.(int64); ok { + rv.SetString(strconv.FormatInt(i, 10)) + } else if f, ok := data.(float64); ok { + rv.SetString(strconv.FormatFloat(f, 'f', -1, 64)) + } else { + return md.badtype("string", data) + } + return nil + } + if s, ok := data.(string); ok { rv.SetString(s) return nil @@ -382,12 +414,14 @@ func (md *MetaData) unifyString(data interface{}, rv reflect.Value) error { return md.badtype("string", data) } -func (md *MetaData) unifyFloat64(data interface{}, rv reflect.Value) error { +func (md *MetaData) unifyFloat64(data any, rv reflect.Value) error { + rvk := rv.Kind() + if num, ok := data.(float64); ok { - switch rv.Kind() { + switch rvk { case reflect.Float32: if num < -math.MaxFloat32 || num > math.MaxFloat32 { - return e("value %f is out of range for float32", num) + return md.parseErr(errParseRange{i: num, size: rvk.String()}) } fallthrough case reflect.Float64: @@ -399,74 +433,61 @@ func (md *MetaData) unifyFloat64(data interface{}, rv reflect.Value) error { } if num, ok := data.(int64); ok { - switch rv.Kind() { - case reflect.Float32: - if num < -maxSafeFloat32Int || num > maxSafeFloat32Int { - return e("value %d is out of range for float32", num) - } - fallthrough - case reflect.Float64: - if num < -maxSafeFloat64Int || num > maxSafeFloat64Int { - return e("value %d is out of range for float64", num) - } - rv.SetFloat(float64(num)) - default: - panic("bug") + if (rvk == reflect.Float32 && (num < -maxSafeFloat32Int || num > maxSafeFloat32Int)) || + (rvk == reflect.Float64 && (num < -maxSafeFloat64Int || num > maxSafeFloat64Int)) { + return md.parseErr(errUnsafeFloat{i: num, size: rvk.String()}) } + rv.SetFloat(float64(num)) return nil } return md.badtype("float", data) } -func (md *MetaData) unifyInt(data interface{}, rv reflect.Value) error { - if num, ok := data.(int64); ok { - if rv.Kind() >= reflect.Int && rv.Kind() <= reflect.Int64 { - switch rv.Kind() { - case reflect.Int, reflect.Int64: - // No bounds checking necessary. - case reflect.Int8: - if num < math.MinInt8 || num > math.MaxInt8 { - return e("value %d is out of range for int8", num) - } - case reflect.Int16: - if num < math.MinInt16 || num > math.MaxInt16 { - return e("value %d is out of range for int16", num) - } - case reflect.Int32: - if num < math.MinInt32 || num > math.MaxInt32 { - return e("value %d is out of range for int32", num) - } +func (md *MetaData) unifyInt(data any, rv reflect.Value) error { + _, ok := rv.Interface().(time.Duration) + if ok { + // Parse as string duration, and fall back to regular integer parsing + // (as nanosecond) if this is not a string. + if s, ok := data.(string); ok { + dur, err := time.ParseDuration(s) + if err != nil { + return md.parseErr(errParseDuration{s}) } - rv.SetInt(num) - } else if rv.Kind() >= reflect.Uint && rv.Kind() <= reflect.Uint64 { - unum := uint64(num) - switch rv.Kind() { - case reflect.Uint, reflect.Uint64: - // No bounds checking necessary. - case reflect.Uint8: - if num < 0 || unum > math.MaxUint8 { - return e("value %d is out of range for uint8", num) - } - case reflect.Uint16: - if num < 0 || unum > math.MaxUint16 { - return e("value %d is out of range for uint16", num) - } - case reflect.Uint32: - if num < 0 || unum > math.MaxUint32 { - return e("value %d is out of range for uint32", num) - } - } - rv.SetUint(unum) - } else { - panic("unreachable") + rv.SetInt(int64(dur)) + return nil } - return nil } - return md.badtype("integer", data) + + num, ok := data.(int64) + if !ok { + return md.badtype("integer", data) + } + + rvk := rv.Kind() + switch { + case rvk >= reflect.Int && rvk <= reflect.Int64: + if (rvk == reflect.Int8 && (num < math.MinInt8 || num > math.MaxInt8)) || + (rvk == reflect.Int16 && (num < math.MinInt16 || num > math.MaxInt16)) || + (rvk == reflect.Int32 && (num < math.MinInt32 || num > math.MaxInt32)) { + return md.parseErr(errParseRange{i: num, size: rvk.String()}) + } + rv.SetInt(num) + case rvk >= reflect.Uint && rvk <= reflect.Uint64: + unum := uint64(num) + if rvk == reflect.Uint8 && (num < 0 || unum > math.MaxUint8) || + rvk == reflect.Uint16 && (num < 0 || unum > math.MaxUint16) || + rvk == reflect.Uint32 && (num < 0 || unum > math.MaxUint32) { + return md.parseErr(errParseRange{i: num, size: rvk.String()}) + } + rv.SetUint(unum) + default: + panic("unreachable") + } + return nil } -func (md *MetaData) unifyBool(data interface{}, rv reflect.Value) error { +func (md *MetaData) unifyBool(data any, rv reflect.Value) error { if b, ok := data.(bool); ok { rv.SetBool(b) return nil @@ -474,12 +495,12 @@ func (md *MetaData) unifyBool(data interface{}, rv reflect.Value) error { return md.badtype("boolean", data) } -func (md *MetaData) unifyAnything(data interface{}, rv reflect.Value) error { +func (md *MetaData) unifyAnything(data any, rv reflect.Value) error { rv.Set(reflect.ValueOf(data)) return nil } -func (md *MetaData) unifyText(data interface{}, v encoding.TextUnmarshaler) error { +func (md *MetaData) unifyText(data any, v encoding.TextUnmarshaler) error { var s string switch sdata := data.(type) { case Marshaler: @@ -488,7 +509,7 @@ func (md *MetaData) unifyText(data interface{}, v encoding.TextUnmarshaler) erro return err } s = string(text) - case TextMarshaler: + case encoding.TextMarshaler: text, err := sdata.MarshalText() if err != nil { return err @@ -508,17 +529,40 @@ func (md *MetaData) unifyText(data interface{}, v encoding.TextUnmarshaler) erro return md.badtype("primitive (string-like)", data) } if err := v.UnmarshalText([]byte(s)); err != nil { - return err + return md.parseErr(err) } return nil } -func (md *MetaData) badtype(dst string, data interface{}) error { - return e("incompatible types: TOML key %q has type %T; destination has type %s", md.context, data, dst) +func (md *MetaData) badtype(dst string, data any) error { + return md.e("incompatible types: TOML value has type %s; destination has type %s", fmtType(data), dst) +} + +func (md *MetaData) parseErr(err error) error { + k := md.context.String() + return ParseError{ + LastKey: k, + Position: md.keyInfo[k].pos, + Line: md.keyInfo[k].pos.Line, + err: err, + input: string(md.data), + } +} + +func (md *MetaData) e(format string, args ...any) error { + f := "toml: " + if len(md.context) > 0 { + f = fmt.Sprintf("toml: (last key %q): ", md.context) + p := md.keyInfo[md.context.String()].pos + if p.Line > 0 { + f = fmt.Sprintf("toml: line %d (last key %q): ", p.Line, md.context) + } + } + return fmt.Errorf(f+format, args...) } // rvalue returns a reflect.Value of `v`. All pointers are resolved. -func rvalue(v interface{}) reflect.Value { +func rvalue(v any) reflect.Value { return indirect(reflect.ValueOf(v)) } @@ -533,7 +577,11 @@ func indirect(v reflect.Value) reflect.Value { if v.Kind() != reflect.Ptr { if v.CanSet() { pv := v.Addr() - if _, ok := pv.Interface().(encoding.TextUnmarshaler); ok { + pvi := pv.Interface() + if _, ok := pvi.(encoding.TextUnmarshaler); ok { + return pv + } + if _, ok := pvi.(Unmarshaler); ok { return pv } } @@ -549,12 +597,17 @@ func isUnifiable(rv reflect.Value) bool { if rv.CanSet() { return true } - if _, ok := rv.Interface().(encoding.TextUnmarshaler); ok { + rvi := rv.Interface() + if _, ok := rvi.(encoding.TextUnmarshaler); ok { + return true + } + if _, ok := rvi.(Unmarshaler); ok { return true } return false } -func e(format string, args ...interface{}) error { - return fmt.Errorf("toml: "+format, args...) +// fmt %T with "interface {}" replaced with "any", which is far more readable. +func fmtType(t any) string { + return strings.ReplaceAll(fmt.Sprintf("%T", t), "interface {}", "any") } diff --git a/vendor/github.com/BurntSushi/toml/decode_go116.go b/vendor/github.com/BurntSushi/toml/decode_go116.go deleted file mode 100644 index eddfb641b862..000000000000 --- a/vendor/github.com/BurntSushi/toml/decode_go116.go +++ /dev/null @@ -1,19 +0,0 @@ -//go:build go1.16 -// +build go1.16 - -package toml - -import ( - "io/fs" -) - -// DecodeFS is just like Decode, except it will automatically read the contents -// of the file at `path` from a fs.FS instance. -func DecodeFS(fsys fs.FS, path string, v interface{}) (MetaData, error) { - fp, err := fsys.Open(path) - if err != nil { - return MetaData{}, err - } - defer fp.Close() - return NewDecoder(fp).Decode(v) -} diff --git a/vendor/github.com/BurntSushi/toml/deprecated.go b/vendor/github.com/BurntSushi/toml/deprecated.go index c6af3f239ddf..155709a80b88 100644 --- a/vendor/github.com/BurntSushi/toml/deprecated.go +++ b/vendor/github.com/BurntSushi/toml/deprecated.go @@ -5,17 +5,25 @@ import ( "io" ) +// TextMarshaler is an alias for encoding.TextMarshaler. +// // Deprecated: use encoding.TextMarshaler type TextMarshaler encoding.TextMarshaler +// TextUnmarshaler is an alias for encoding.TextUnmarshaler. +// // Deprecated: use encoding.TextUnmarshaler type TextUnmarshaler encoding.TextUnmarshaler +// DecodeReader is an alias for NewDecoder(r).Decode(v). +// +// Deprecated: use NewDecoder(reader).Decode(&value). +func DecodeReader(r io.Reader, v any) (MetaData, error) { return NewDecoder(r).Decode(v) } + +// PrimitiveDecode is an alias for MetaData.PrimitiveDecode(). +// // Deprecated: use MetaData.PrimitiveDecode. -func PrimitiveDecode(primValue Primitive, v interface{}) error { +func PrimitiveDecode(primValue Primitive, v any) error { md := MetaData{decoded: make(map[string]struct{})} return md.unify(primValue.undecoded, rvalue(v)) } - -// Deprecated: use NewDecoder(reader).Decode(&value). -func DecodeReader(r io.Reader, v interface{}) (MetaData, error) { return NewDecoder(r).Decode(v) } diff --git a/vendor/github.com/BurntSushi/toml/doc.go b/vendor/github.com/BurntSushi/toml/doc.go index 099c4a77d2d3..82c90a905701 100644 --- a/vendor/github.com/BurntSushi/toml/doc.go +++ b/vendor/github.com/BurntSushi/toml/doc.go @@ -1,13 +1,8 @@ -/* -Package toml implements decoding and encoding of TOML files. - -This package supports TOML v1.0.0, as listed on https://toml.io - -There is also support for delaying decoding with the Primitive type, and -querying the set of keys in a TOML document with the MetaData type. - -The github.com/BurntSushi/toml/cmd/tomlv package implements a TOML validator, -and can be used to verify if TOML document is valid. It can also be used to -print the type of each key. -*/ +// Package toml implements decoding and encoding of TOML files. +// +// This package supports TOML v1.0.0, as specified at https://toml.io +// +// The github.com/BurntSushi/toml/cmd/tomlv package implements a TOML validator, +// and can be used to verify if TOML document is valid. It can also be used to +// print the type of each key. package toml diff --git a/vendor/github.com/BurntSushi/toml/encode.go b/vendor/github.com/BurntSushi/toml/encode.go index dee4e6d31961..73366c0d9a98 100644 --- a/vendor/github.com/BurntSushi/toml/encode.go +++ b/vendor/github.com/BurntSushi/toml/encode.go @@ -2,7 +2,9 @@ package toml import ( "bufio" + "bytes" "encoding" + "encoding/json" "errors" "fmt" "io" @@ -63,18 +65,38 @@ var dblQuotedReplacer = strings.NewReplacer( "\x7f", `\u007f`, ) +var ( + marshalToml = reflect.TypeOf((*Marshaler)(nil)).Elem() + marshalText = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() + timeType = reflect.TypeOf((*time.Time)(nil)).Elem() +) + // Marshaler is the interface implemented by types that can marshal themselves // into valid TOML. type Marshaler interface { MarshalTOML() ([]byte, error) } +// Marshal returns a TOML representation of the Go value. +// +// See [Encoder] for a description of the encoding process. +func Marshal(v any) ([]byte, error) { + buff := new(bytes.Buffer) + if err := NewEncoder(buff).Encode(v); err != nil { + return nil, err + } + return buff.Bytes(), nil +} + // Encoder encodes a Go to a TOML document. // // The mapping between Go values and TOML values should be precisely the same as -// for the Decode* functions. +// for [Decode]. +// +// time.Time is encoded as a RFC 3339 string, and time.Duration as its string +// representation. // -// The toml.Marshaler and encoder.TextMarshaler interfaces are supported to +// The [Marshaler] and [encoding.TextMarshaler] interfaces are supported to // encoding the value as custom TOML. // // If you want to write arbitrary binary data then you will need to use @@ -85,6 +107,17 @@ type Marshaler interface { // // Go maps will be sorted alphabetically by key for deterministic output. // +// The toml struct tag can be used to provide the key name; if omitted the +// struct field name will be used. If the "omitempty" option is present the +// following value will be skipped: +// +// - arrays, slices, maps, and string with len of 0 +// - struct with all zero values +// - bool false +// +// If omitzero is given all int and float types with a value of 0 will be +// skipped. +// // Encoding Go values without a corresponding TOML representation will return an // error. Examples of this includes maps with non-string keys, slices with nil // elements, embedded non-struct types, and nested slices containing maps or @@ -94,28 +127,24 @@ type Marshaler interface { // NOTE: only exported keys are encoded due to the use of reflection. Unexported // keys are silently discarded. type Encoder struct { - // String to use for a single indentation level; default is two spaces. - Indent string - + Indent string // string for a single indentation level; default is two spaces. + hasWritten bool // written any output to w yet? w *bufio.Writer - hasWritten bool // written any output to w yet? } // NewEncoder create a new Encoder. func NewEncoder(w io.Writer) *Encoder { - return &Encoder{ - w: bufio.NewWriter(w), - Indent: " ", - } + return &Encoder{w: bufio.NewWriter(w), Indent: " "} } -// Encode writes a TOML representation of the Go value to the Encoder's writer. +// Encode writes a TOML representation of the Go value to the [Encoder]'s writer. // // An error is returned if the value given cannot be encoded to a valid TOML // document. -func (enc *Encoder) Encode(v interface{}) error { +func (enc *Encoder) Encode(v any) error { rv := eindirect(reflect.ValueOf(v)) - if err := enc.safeEncode(Key([]string{}), rv); err != nil { + err := enc.safeEncode(Key([]string{}), rv) + if err != nil { return err } return enc.w.Flush() @@ -136,18 +165,15 @@ func (enc *Encoder) safeEncode(key Key, rv reflect.Value) (err error) { } func (enc *Encoder) encode(key Key, rv reflect.Value) { - // Special case: time needs to be in ISO8601 format. - // - // Special case: if we can marshal the type to text, then we used that. This - // prevents the encoder for handling these types as generic structs (or - // whatever the underlying type of a TextMarshaler is). - switch t := rv.Interface().(type) { - case time.Time, encoding.TextMarshaler, Marshaler: + // If we can marshal the type to text, then we use that. This prevents the + // encoder for handling these types as generic structs (or whatever the + // underlying type of a TextMarshaler is). + switch { + case isMarshaler(rv): enc.writeKeyValue(key, rv, false) return - // TODO: #76 would make this superfluous after implemented. - case Primitive: - enc.encode(key, reflect.ValueOf(t.undecoded)) + case rv.Type() == primitiveType: // TODO: #76 would make this superfluous after implemented. + enc.encode(key, reflect.ValueOf(rv.Interface().(Primitive).undecoded)) return } @@ -212,18 +238,44 @@ func (enc *Encoder) eElement(rv reflect.Value) { if err != nil { encPanic(err) } - enc.writeQuoted(string(s)) + if s == nil { + encPanic(errors.New("MarshalTOML returned nil and no error")) + } + enc.w.Write(s) return case encoding.TextMarshaler: s, err := v.MarshalText() if err != nil { encPanic(err) } + if s == nil { + encPanic(errors.New("MarshalText returned nil and no error")) + } enc.writeQuoted(string(s)) return + case time.Duration: + enc.writeQuoted(v.String()) + return + case json.Number: + n, _ := rv.Interface().(json.Number) + + if n == "" { /// Useful zero value. + enc.w.WriteByte('0') + return + } else if v, err := n.Int64(); err == nil { + enc.eElement(reflect.ValueOf(v)) + return + } else if v, err := n.Float64(); err == nil { + enc.eElement(reflect.ValueOf(v)) + return + } + encPanic(fmt.Errorf("unable to convert %q to int64 or float64", n)) } switch rv.Kind() { + case reflect.Ptr: + enc.eElement(rv.Elem()) + return case reflect.String: enc.writeQuoted(rv.String()) case reflect.Bool: @@ -235,18 +287,30 @@ func (enc *Encoder) eElement(rv reflect.Value) { case reflect.Float32: f := rv.Float() if math.IsNaN(f) { + if math.Signbit(f) { + enc.wf("-") + } enc.wf("nan") } else if math.IsInf(f, 0) { - enc.wf("%cinf", map[bool]byte{true: '-', false: '+'}[math.Signbit(f)]) + if math.Signbit(f) { + enc.wf("-") + } + enc.wf("inf") } else { enc.wf(floatAddDecimal(strconv.FormatFloat(f, 'f', -1, 32))) } case reflect.Float64: f := rv.Float() if math.IsNaN(f) { + if math.Signbit(f) { + enc.wf("-") + } enc.wf("nan") } else if math.IsInf(f, 0) { - enc.wf("%cinf", map[bool]byte{true: '-', false: '+'}[math.Signbit(f)]) + if math.Signbit(f) { + enc.wf("-") + } + enc.wf("inf") } else { enc.wf(floatAddDecimal(strconv.FormatFloat(f, 'f', -1, 64))) } @@ -259,7 +323,7 @@ func (enc *Encoder) eElement(rv reflect.Value) { case reflect.Interface: enc.eElement(rv.Elem()) default: - encPanic(fmt.Errorf("unexpected primitive type: %T", rv.Interface())) + encPanic(fmt.Errorf("unexpected type: %s", fmtType(rv.Interface()))) } } @@ -280,7 +344,7 @@ func (enc *Encoder) eArrayOrSliceElement(rv reflect.Value) { length := rv.Len() enc.wf("[") for i := 0; i < length; i++ { - elem := rv.Index(i) + elem := eindirect(rv.Index(i)) enc.eElement(elem) if i != length-1 { enc.wf(", ") @@ -294,7 +358,7 @@ func (enc *Encoder) eArrayOfTables(key Key, rv reflect.Value) { encPanic(errNoKey) } for i := 0; i < rv.Len(); i++ { - trv := rv.Index(i) + trv := eindirect(rv.Index(i)) if isNil(trv) { continue } @@ -319,7 +383,7 @@ func (enc *Encoder) eTable(key Key, rv reflect.Value) { } func (enc *Encoder) eMapOrStruct(key Key, rv reflect.Value, inline bool) { - switch rv := eindirect(rv); rv.Kind() { + switch rv.Kind() { case reflect.Map: enc.eMap(key, rv, inline) case reflect.Struct: @@ -341,7 +405,7 @@ func (enc *Encoder) eMap(key Key, rv reflect.Value, inline bool) { var mapKeysDirect, mapKeysSub []string for _, mapKey := range rv.MapKeys() { k := mapKey.String() - if typeIsTable(tomlTypeOfGo(rv.MapIndex(mapKey))) { + if typeIsTable(tomlTypeOfGo(eindirect(rv.MapIndex(mapKey)))) { mapKeysSub = append(mapKeysSub, k) } else { mapKeysDirect = append(mapKeysDirect, k) @@ -351,7 +415,7 @@ func (enc *Encoder) eMap(key Key, rv reflect.Value, inline bool) { var writeMapKeys = func(mapKeys []string, trailC bool) { sort.Strings(mapKeys) for i, mapKey := range mapKeys { - val := rv.MapIndex(reflect.ValueOf(mapKey)) + val := eindirect(rv.MapIndex(reflect.ValueOf(mapKey))) if isNil(val) { continue } @@ -379,6 +443,13 @@ func (enc *Encoder) eMap(key Key, rv reflect.Value, inline bool) { const is32Bit = (32 << (^uint(0) >> 63)) == 32 +func pointerTo(t reflect.Type) reflect.Type { + if t.Kind() == reflect.Ptr { + return pointerTo(t.Elem()) + } + return t +} + func (enc *Encoder) eStruct(key Key, rv reflect.Value, inline bool) { // Write keys for fields directly under this key first, because if we write // a field that creates a new table then all keys under it will be in that @@ -395,48 +466,42 @@ func (enc *Encoder) eStruct(key Key, rv reflect.Value, inline bool) { addFields = func(rt reflect.Type, rv reflect.Value, start []int) { for i := 0; i < rt.NumField(); i++ { f := rt.Field(i) - if f.PkgPath != "" && !f.Anonymous { /// Skip unexported fields. + isEmbed := f.Anonymous && pointerTo(f.Type).Kind() == reflect.Struct + if f.PkgPath != "" && !isEmbed { /// Skip unexported fields. + continue + } + opts := getOptions(f.Tag) + if opts.skip { continue } - frv := rv.Field(i) + frv := eindirect(rv.Field(i)) + + if is32Bit { + // Copy so it works correct on 32bit archs; not clear why this + // is needed. See #314, and https://www.reddit.com/r/golang/comments/pnx8v4 + // This also works fine on 64bit, but 32bit archs are somewhat + // rare and this is a wee bit faster. + copyStart := make([]int, len(start)) + copy(copyStart, start) + start = copyStart + } // Treat anonymous struct fields with tag names as though they are // not anonymous, like encoding/json does. // // Non-struct anonymous fields use the normal encoding logic. - if f.Anonymous { - t := f.Type - switch t.Kind() { - case reflect.Struct: - if getOptions(f.Tag).name == "" { - addFields(t, frv, append(start, f.Index...)) - continue - } - case reflect.Ptr: - if t.Elem().Kind() == reflect.Struct && getOptions(f.Tag).name == "" { - if !frv.IsNil() { - addFields(t.Elem(), frv.Elem(), append(start, f.Index...)) - } - continue - } + if isEmbed { + if getOptions(f.Tag).name == "" && frv.Kind() == reflect.Struct { + addFields(frv.Type(), frv, append(start, f.Index...)) + continue } } if typeIsTable(tomlTypeOfGo(frv)) { fieldsSub = append(fieldsSub, append(start, f.Index...)) } else { - // Copy so it works correct on 32bit archs; not clear why this - // is needed. See #314, and https://www.reddit.com/r/golang/comments/pnx8v4 - // This also works fine on 64bit, but 32bit archs are somewhat - // rare and this is a wee bit faster. - if is32Bit { - copyStart := make([]int, len(start)) - copy(copyStart, start) - fieldsDirect = append(fieldsDirect, append(copyStart, f.Index...)) - } else { - fieldsDirect = append(fieldsDirect, append(start, f.Index...)) - } + fieldsDirect = append(fieldsDirect, append(start, f.Index...)) } } } @@ -447,21 +512,25 @@ func (enc *Encoder) eStruct(key Key, rv reflect.Value, inline bool) { fieldType := rt.FieldByIndex(fieldIndex) fieldVal := rv.FieldByIndex(fieldIndex) - if isNil(fieldVal) { /// Don't write anything for nil fields. + opts := getOptions(fieldType.Tag) + if opts.skip { + continue + } + if opts.omitempty && isEmpty(fieldVal) { continue } - opts := getOptions(fieldType.Tag) - if opts.skip { + fieldVal = eindirect(fieldVal) + + if isNil(fieldVal) { /// Don't write anything for nil fields. continue } + keyName := fieldType.Name if opts.name != "" { keyName = opts.name } - if opts.omitempty && isEmpty(fieldVal) { - continue - } + if opts.omitzero && isZero(fieldVal) { continue } @@ -498,6 +567,21 @@ func tomlTypeOfGo(rv reflect.Value) tomlType { if isNil(rv) || !rv.IsValid() { return nil } + + if rv.Kind() == reflect.Struct { + if rv.Type() == timeType { + return tomlDatetime + } + if isMarshaler(rv) { + return tomlString + } + return tomlHash + } + + if isMarshaler(rv) { + return tomlString + } + switch rv.Kind() { case reflect.Bool: return tomlBool @@ -509,7 +593,7 @@ func tomlTypeOfGo(rv reflect.Value) tomlType { case reflect.Float32, reflect.Float64: return tomlFloat case reflect.Array, reflect.Slice: - if typeEqual(tomlHash, tomlArrayType(rv)) { + if isTableArray(rv) { return tomlArrayHash } return tomlArray @@ -519,67 +603,35 @@ func tomlTypeOfGo(rv reflect.Value) tomlType { return tomlString case reflect.Map: return tomlHash - case reflect.Struct: - if _, ok := rv.Interface().(time.Time); ok { - return tomlDatetime - } - if isMarshaler(rv) { - return tomlString - } - return tomlHash default: - if isMarshaler(rv) { - return tomlString - } - encPanic(errors.New("unsupported type: " + rv.Kind().String())) panic("unreachable") } } func isMarshaler(rv reflect.Value) bool { - switch rv.Interface().(type) { - case encoding.TextMarshaler: - return true - case Marshaler: - return true - } - - // Someone used a pointer receiver: we can make it work for pointer values. - if rv.CanAddr() { - if _, ok := rv.Addr().Interface().(encoding.TextMarshaler); ok { - return true - } - if _, ok := rv.Addr().Interface().(Marshaler); ok { - return true - } - } - return false + return rv.Type().Implements(marshalText) || rv.Type().Implements(marshalToml) } -// tomlArrayType returns the element type of a TOML array. The type returned -// may be nil if it cannot be determined (e.g., a nil slice or a zero length -// slize). This function may also panic if it finds a type that cannot be -// expressed in TOML (such as nil elements, heterogeneous arrays or directly -// nested arrays of tables). -func tomlArrayType(rv reflect.Value) tomlType { - if isNil(rv) || !rv.IsValid() || rv.Len() == 0 { - return nil +// isTableArray reports if all entries in the array or slice are a table. +func isTableArray(arr reflect.Value) bool { + if isNil(arr) || !arr.IsValid() || arr.Len() == 0 { + return false } - /// Don't allow nil. - rvlen := rv.Len() - for i := 1; i < rvlen; i++ { - if tomlTypeOfGo(rv.Index(i)) == nil { + ret := true + for i := 0; i < arr.Len(); i++ { + tt := tomlTypeOfGo(eindirect(arr.Index(i))) + // Don't allow nil. + if tt == nil { encPanic(errArrayNilElement) } - } - firstType := tomlTypeOfGo(rv.Index(0)) - if firstType == nil { - encPanic(errArrayNilElement) + if ret && !typeEqual(tomlHash, tt) { + ret = false + } } - return firstType + return ret } type tagOptions struct { @@ -624,8 +676,26 @@ func isEmpty(rv reflect.Value) bool { switch rv.Kind() { case reflect.Array, reflect.Slice, reflect.Map, reflect.String: return rv.Len() == 0 + case reflect.Struct: + if rv.Type().Comparable() { + return reflect.Zero(rv.Type()).Interface() == rv.Interface() + } + // Need to also check if all the fields are empty, otherwise something + // like this with uncomparable types will always return true: + // + // type a struct{ field b } + // type b struct{ s []string } + // s := a{field: b{s: []string{"AAA"}}} + for i := 0; i < rv.NumField(); i++ { + if !isEmpty(rv.Field(i)) { + return false + } + } + return true case reflect.Bool: return !rv.Bool() + case reflect.Ptr: + return rv.IsNil() } return false } @@ -638,19 +708,21 @@ func (enc *Encoder) newline() { // Write a key/value pair: // -// key = +// key = // // This is also used for "k = v" in inline tables; so something like this will // be written in three calls: // -// ┌────────────────────┐ -// │ ┌───┐ ┌─────┐│ -// v v v v vv -// key = {k = v, k2 = v2} -// +// ┌───────────────────┐ +// │ ┌───┐ ┌────┐│ +// v v v v vv +// key = {k = 1, k2 = 2} func (enc *Encoder) writeKeyValue(key Key, val reflect.Value, inline bool) { + /// Marshaler used on top-level document; call eElement() to just call + /// Marshal{TOML,Text}. if len(key) == 0 { - encPanic(errNoKey) + enc.eElement(val) + return } enc.wf("%s%s = ", enc.indentStr(key), key.maybeQuoted(len(key)-1)) enc.eElement(val) @@ -659,7 +731,7 @@ func (enc *Encoder) writeKeyValue(key Key, val reflect.Value, inline bool) { } } -func (enc *Encoder) wf(format string, v ...interface{}) { +func (enc *Encoder) wf(format string, v ...any) { _, err := fmt.Fprintf(enc.w, format, v...) if err != nil { encPanic(err) @@ -675,13 +747,25 @@ func encPanic(err error) { panic(tomlEncodeError{err}) } +// Resolve any level of pointers to the actual value (e.g. **string → string). func eindirect(v reflect.Value) reflect.Value { - switch v.Kind() { - case reflect.Ptr, reflect.Interface: - return eindirect(v.Elem()) - default: + if v.Kind() != reflect.Ptr && v.Kind() != reflect.Interface { + if isMarshaler(v) { + return v + } + if v.CanAddr() { /// Special case for marshalers; see #358. + if pv := v.Addr(); isMarshaler(pv) { + return pv + } + } return v } + + if v.IsNil() { + return v + } + + return eindirect(v.Elem()) } func isNil(rv reflect.Value) bool { diff --git a/vendor/github.com/BurntSushi/toml/error.go b/vendor/github.com/BurntSushi/toml/error.go index 36edc46554ed..b45a3f45f68a 100644 --- a/vendor/github.com/BurntSushi/toml/error.go +++ b/vendor/github.com/BurntSushi/toml/error.go @@ -5,57 +5,60 @@ import ( "strings" ) -// ParseError is returned when there is an error parsing the TOML syntax. -// -// For example invalid syntax, duplicate keys, etc. +// ParseError is returned when there is an error parsing the TOML syntax such as +// invalid syntax, duplicate keys, etc. // // In addition to the error message itself, you can also print detailed location -// information with context by using ErrorWithLocation(): +// information with context by using [ErrorWithPosition]: // -// toml: error: Key 'fruit' was already created and cannot be used as an array. +// toml: error: Key 'fruit' was already created and cannot be used as an array. // -// At line 4, column 2-7: +// At line 4, column 2-7: // -// 2 | fruit = [] -// 3 | -// 4 | [[fruit]] # Not allowed -// ^^^^^ +// 2 | fruit = [] +// 3 | +// 4 | [[fruit]] # Not allowed +// ^^^^^ // -// Furthermore, the ErrorWithUsage() can be used to print the above with some -// more detailed usage guidance: +// [ErrorWithUsage] can be used to print the above with some more detailed usage +// guidance: // -// toml: error: newlines not allowed within inline tables +// toml: error: newlines not allowed within inline tables // -// At line 1, column 18: +// At line 1, column 18: // -// 1 | x = [{ key = 42 # -// ^ +// 1 | x = [{ key = 42 # +// ^ // -// Error help: +// Error help: // -// Inline tables must always be on a single line: +// Inline tables must always be on a single line: // -// table = {key = 42, second = 43} +// table = {key = 42, second = 43} // -// It is invalid to split them over multiple lines like so: +// It is invalid to split them over multiple lines like so: // -// # INVALID -// table = { -// key = 42, -// second = 43 -// } +// # INVALID +// table = { +// key = 42, +// second = 43 +// } // -// Use regular for this: +// Use regular for this: // -// [table] -// key = 42 -// second = 43 +// [table] +// key = 42 +// second = 43 type ParseError struct { Message string // Short technical message. Usage string // Longer message with usage guidance; may be blank. Position Position // Position of the error LastKey string // Last parsed key, may be blank. - Line int // Line the error occurred. Deprecated: use Position. + + // Line the error occurred. + // + // Deprecated: use [Position]. + Line int err error input string @@ -81,9 +84,9 @@ func (pe ParseError) Error() string { pe.Position.Line, pe.LastKey, msg) } -// ErrorWithUsage() returns the error with detailed location context. +// ErrorWithPosition returns the error with detailed location context. // -// See the documentation on ParseError. +// See the documentation on [ParseError]. func (pe ParseError) ErrorWithPosition() string { if pe.input == "" { // Should never happen, but just in case. return pe.Error() @@ -111,26 +114,39 @@ func (pe ParseError) ErrorWithPosition() string { msg, pe.Position.Line, col, col+pe.Position.Len) } if pe.Position.Line > 2 { - fmt.Fprintf(b, "% 7d | %s\n", pe.Position.Line-2, lines[pe.Position.Line-3]) + fmt.Fprintf(b, "% 7d | %s\n", pe.Position.Line-2, expandTab(lines[pe.Position.Line-3])) } if pe.Position.Line > 1 { - fmt.Fprintf(b, "% 7d | %s\n", pe.Position.Line-1, lines[pe.Position.Line-2]) + fmt.Fprintf(b, "% 7d | %s\n", pe.Position.Line-1, expandTab(lines[pe.Position.Line-2])) } - fmt.Fprintf(b, "% 7d | %s\n", pe.Position.Line, lines[pe.Position.Line-1]) - fmt.Fprintf(b, "% 10s%s%s\n", "", strings.Repeat(" ", col), strings.Repeat("^", pe.Position.Len)) + + /// Expand tabs, so that the ^^^s are at the correct position, but leave + /// "column 10-13" intact. Adjusting this to the visual column would be + /// better, but we don't know the tabsize of the user in their editor, which + /// can be 8, 4, 2, or something else. We can't know. So leaving it as the + /// character index is probably the "most correct". + expanded := expandTab(lines[pe.Position.Line-1]) + diff := len(expanded) - len(lines[pe.Position.Line-1]) + + fmt.Fprintf(b, "% 7d | %s\n", pe.Position.Line, expanded) + fmt.Fprintf(b, "% 10s%s%s\n", "", strings.Repeat(" ", col+diff), strings.Repeat("^", pe.Position.Len)) return b.String() } -// ErrorWithUsage() returns the error with detailed location context and usage +// ErrorWithUsage returns the error with detailed location context and usage // guidance. // -// See the documentation on ParseError. +// See the documentation on [ParseError]. func (pe ParseError) ErrorWithUsage() string { m := pe.ErrorWithPosition() if u, ok := pe.err.(interface{ Usage() string }); ok && u.Usage() != "" { - return m + "Error help:\n\n " + - strings.ReplaceAll(strings.TrimSpace(u.Usage()), "\n", "\n ") + - "\n" + lines := strings.Split(strings.TrimSpace(u.Usage()), "\n") + for i := range lines { + if lines[i] != "" { + lines[i] = " " + lines[i] + } + } + return m + "Error help:\n\n" + strings.Join(lines, "\n") + "\n" } return m } @@ -152,14 +168,49 @@ func (pe ParseError) column(lines []string) int { return col } +func expandTab(s string) string { + var ( + b strings.Builder + l int + fill = func(n int) string { + b := make([]byte, n) + for i := range b { + b[i] = ' ' + } + return string(b) + } + ) + b.Grow(len(s)) + for _, r := range s { + switch r { + case '\t': + tw := 8 - l%8 + b.WriteString(fill(tw)) + l += tw + default: + b.WriteRune(r) + l += 1 + } + } + return b.String() +} + type ( errLexControl struct{ r rune } errLexEscape struct{ r rune } errLexUTF8 struct{ b byte } - errLexInvalidNum struct{ v string } - errLexInvalidDate struct{ v string } + errParseDate struct{ v string } errLexInlineTableNL struct{} errLexStringNL struct{} + errParseRange struct { + i any // int or float + size string // "int64", "uint16", etc. + } + errUnsafeFloat struct { + i interface{} // float32 or float64 + size string // "float32" or "float64" + } + errParseDuration struct{ d string } ) func (e errLexControl) Error() string { @@ -171,14 +222,20 @@ func (e errLexEscape) Error() string { return fmt.Sprintf(`invalid escape func (e errLexEscape) Usage() string { return usageEscape } func (e errLexUTF8) Error() string { return fmt.Sprintf("invalid UTF-8 byte: 0x%02x", e.b) } func (e errLexUTF8) Usage() string { return "" } -func (e errLexInvalidNum) Error() string { return fmt.Sprintf("invalid number: %q", e.v) } -func (e errLexInvalidNum) Usage() string { return "" } -func (e errLexInvalidDate) Error() string { return fmt.Sprintf("invalid date: %q", e.v) } -func (e errLexInvalidDate) Usage() string { return "" } +func (e errParseDate) Error() string { return fmt.Sprintf("invalid datetime: %q", e.v) } +func (e errParseDate) Usage() string { return usageDate } func (e errLexInlineTableNL) Error() string { return "newlines not allowed within inline tables" } func (e errLexInlineTableNL) Usage() string { return usageInlineNewline } func (e errLexStringNL) Error() string { return "strings cannot contain newlines" } func (e errLexStringNL) Usage() string { return usageStringNewline } +func (e errParseRange) Error() string { return fmt.Sprintf("%v is out of range for %s", e.i, e.size) } +func (e errParseRange) Usage() string { return usageIntOverflow } +func (e errUnsafeFloat) Error() string { + return fmt.Sprintf("%v is out of the safe %s range", e.i, e.size) +} +func (e errUnsafeFloat) Usage() string { return usageUnsafeFloat } +func (e errParseDuration) Error() string { return fmt.Sprintf("invalid duration: %q", e.d) } +func (e errParseDuration) Usage() string { return usageDuration } const usageEscape = ` A '\' inside a "-delimited string is interpreted as an escape character. @@ -227,3 +284,73 @@ Instead use """ or ''' to split strings over multiple lines: string = """Hello, world!""" ` + +const usageIntOverflow = ` +This number is too large; this may be an error in the TOML, but it can also be a +bug in the program that uses too small of an integer. + +The maximum and minimum values are: + + size │ lowest │ highest + ───────┼────────────────┼────────────── + int8 │ -128 │ 127 + int16 │ -32,768 │ 32,767 + int32 │ -2,147,483,648 │ 2,147,483,647 + int64 │ -9.2 × 10¹⁷ │ 9.2 × 10¹⁷ + uint8 │ 0 │ 255 + uint16 │ 0 │ 65,535 + uint32 │ 0 │ 4,294,967,295 + uint64 │ 0 │ 1.8 × 10¹⁸ + +int refers to int32 on 32-bit systems and int64 on 64-bit systems. +` + +const usageUnsafeFloat = ` +This number is outside of the "safe" range for floating point numbers; whole +(non-fractional) numbers outside the below range can not always be represented +accurately in a float, leading to some loss of accuracy. + +Explicitly mark a number as a fractional unit by adding ".0", which will incur +some loss of accuracy; for example: + + f = 2_000_000_000.0 + +Accuracy ranges: + + float32 = 16,777,215 + float64 = 9,007,199,254,740,991 +` + +const usageDuration = ` +A duration must be as "number", without any spaces. Valid units are: + + ns nanoseconds (billionth of a second) + us, µs microseconds (millionth of a second) + ms milliseconds (thousands of a second) + s seconds + m minutes + h hours + +You can combine multiple units; for example "5m10s" for 5 minutes and 10 +seconds. +` + +const usageDate = ` +A TOML datetime must be in one of the following formats: + + 2006-01-02T15:04:05Z07:00 Date and time, with timezone. + 2006-01-02T15:04:05 Date and time, but without timezone. + 2006-01-02 Date without a time or timezone. + 15:04:05 Just a time, without any timezone. + +Seconds may optionally have a fraction, up to nanosecond precision: + + 15:04:05.123 + 15:04:05.856018510 +` + +// TOML 1.1: +// The seconds part in times is optional, and may be omitted: +// 2006-01-02T15:04Z07:00 +// 2006-01-02T15:04 +// 15:04 diff --git a/vendor/github.com/BurntSushi/toml/lex.go b/vendor/github.com/BurntSushi/toml/lex.go index 63ef20f47453..a1016d98a8ec 100644 --- a/vendor/github.com/BurntSushi/toml/lex.go +++ b/vendor/github.com/BurntSushi/toml/lex.go @@ -17,6 +17,7 @@ const ( itemEOF itemText itemString + itemStringEsc itemRawString itemMultilineString itemRawMultilineString @@ -46,12 +47,14 @@ func (p Position) String() string { } type lexer struct { - input string - start int - pos int - line int - state stateFn - items chan item + input string + start int + pos int + line int + state stateFn + items chan item + tomlNext bool + esc bool // Allow for backing up up to 4 runes. This is necessary because TOML // contains 3-rune tokens (""" and '''). @@ -82,18 +85,19 @@ func (lx *lexer) nextItem() item { return item default: lx.state = lx.state(lx) - //fmt.Printf(" STATE %-24s current: %-10q stack: %s\n", lx.state, lx.current(), lx.stack) + //fmt.Printf(" STATE %-24s current: %-10s stack: %s\n", lx.state, lx.current(), lx.stack) } } } -func lex(input string) *lexer { +func lex(input string, tomlNext bool) *lexer { lx := &lexer{ - input: input, - state: lexTop, - items: make(chan item, 10), - stack: make([]stateFn, 0, 10), - line: 1, + input: input, + state: lexTop, + items: make(chan item, 10), + stack: make([]stateFn, 0, 10), + line: 1, + tomlNext: tomlNext, } return lx } @@ -128,6 +132,11 @@ func (lx lexer) getPos() Position { } func (lx *lexer) emit(typ itemType) { + // Needed for multiline strings ending with an incomplete UTF-8 sequence. + if lx.start > lx.pos { + lx.error(errLexUTF8{lx.input[lx.pos]}) + return + } lx.items <- item{typ: typ, pos: lx.getPos(), val: lx.current()} lx.start = lx.pos } @@ -157,7 +166,7 @@ func (lx *lexer) next() (r rune) { } r, w := utf8.DecodeRuneInString(lx.input[lx.pos:]) - if r == utf8.RuneError { + if r == utf8.RuneError && w == 1 { lx.error(errLexUTF8{lx.input[lx.pos]}) return utf8.RuneError } @@ -263,7 +272,7 @@ func (lx *lexer) errorPos(start, length int, err error) stateFn { } // errorf is like error, and creates a new error. -func (lx *lexer) errorf(format string, values ...interface{}) stateFn { +func (lx *lexer) errorf(format string, values ...any) stateFn { if lx.atEOF { pos := lx.getPos() pos.Line-- @@ -326,9 +335,7 @@ func lexTopEnd(lx *lexer) stateFn { lx.emit(itemEOF) return nil } - return lx.errorf( - "expected a top-level item to end with a newline, comment, or EOF, but got %q instead", - r) + return lx.errorf("expected a top-level item to end with a newline, comment, or EOF, but got %q instead", r) } // lexTable lexes the beginning of a table. Namely, it makes sure that @@ -403,7 +410,7 @@ func lexTableNameEnd(lx *lexer) stateFn { // Lexes only one part, e.g. only 'a' inside 'a.b'. func lexBareName(lx *lexer) stateFn { r := lx.next() - if isBareKeyChar(r) { + if isBareKeyChar(r, lx.tomlNext) { return lexBareName } lx.backup() @@ -613,6 +620,9 @@ func lexInlineTableValue(lx *lexer) stateFn { case isWhitespace(r): return lexSkip(lx, lexInlineTableValue) case isNL(r): + if lx.tomlNext { + return lexSkip(lx, lexInlineTableValue) + } return lx.errorPrevLine(errLexInlineTableNL{}) case r == '#': lx.push(lexInlineTableValue) @@ -635,6 +645,9 @@ func lexInlineTableValueEnd(lx *lexer) stateFn { case isWhitespace(r): return lexSkip(lx, lexInlineTableValueEnd) case isNL(r): + if lx.tomlNext { + return lexSkip(lx, lexInlineTableValueEnd) + } return lx.errorPrevLine(errLexInlineTableNL{}) case r == '#': lx.push(lexInlineTableValueEnd) @@ -643,6 +656,9 @@ func lexInlineTableValueEnd(lx *lexer) stateFn { lx.ignore() lx.skip(isWhitespace) if lx.peek() == '}' { + if lx.tomlNext { + return lexInlineTableValueEnd + } return lx.errorf("trailing comma not allowed in inline tables") } return lexInlineTableValue @@ -682,7 +698,12 @@ func lexString(lx *lexer) stateFn { return lexStringEscape case r == '"': lx.backup() - lx.emit(itemString) + if lx.esc { + lx.esc = false + lx.emit(itemStringEsc) + } else { + lx.emit(itemString) + } lx.next() lx.ignore() return lx.pop() @@ -711,7 +732,17 @@ func lexMultilineString(lx *lexer) stateFn { if lx.peek() == '"' { /// Check if we already lexed 5 's; if so we have 6 now, and /// that's just too many man! - if strings.HasSuffix(lx.current(), `"""""`) { + /// + /// Second check is for the edge case: + /// + /// two quotes allowed. + /// vv + /// """lol \"""""" + /// ^^ ^^^---- closing three + /// escaped + /// + /// But ugly, but it works + if strings.HasSuffix(lx.current(), `"""""`) && !strings.HasSuffix(lx.current(), `\"""""`) { return lx.errorf(`unexpected '""""""'`) } lx.backup() @@ -722,6 +753,7 @@ func lexMultilineString(lx *lexer) stateFn { lx.backup() /// backup: don't include the """ in the item. lx.backup() lx.backup() + lx.esc = false lx.emit(itemMultilineString) lx.next() /// Read over ''' again and discard it. lx.next() @@ -755,8 +787,8 @@ func lexRawString(lx *lexer) stateFn { } } -// lexMultilineRawString consumes a raw string. Nothing can be escaped in such -// a string. It assumes that the beginning "'''" has already been consumed and +// lexMultilineRawString consumes a raw string. Nothing can be escaped in such a +// string. It assumes that the beginning triple-' has already been consumed and // ignored. func lexMultilineRawString(lx *lexer) stateFn { r := lx.next() @@ -802,8 +834,7 @@ func lexMultilineRawString(lx *lexer) stateFn { // lexMultilineStringEscape consumes an escaped character. It assumes that the // preceding '\\' has already been consumed. func lexMultilineStringEscape(lx *lexer) stateFn { - // Handle the special case first: - if isNL(lx.next()) { + if isNL(lx.next()) { /// \ escaping newline. return lexMultilineString } lx.backup() @@ -812,8 +843,14 @@ func lexMultilineStringEscape(lx *lexer) stateFn { } func lexStringEscape(lx *lexer) stateFn { + lx.esc = true r := lx.next() switch r { + case 'e': + if !lx.tomlNext { + return lx.error(errLexEscape{r}) + } + fallthrough case 'b': fallthrough case 't': @@ -832,6 +869,11 @@ func lexStringEscape(lx *lexer) stateFn { fallthrough case '\\': return lx.pop() + case 'x': + if !lx.tomlNext { + return lx.error(errLexEscape{r}) + } + return lexHexEscape case 'u': return lexShortUnicodeEscape case 'U': @@ -840,14 +882,23 @@ func lexStringEscape(lx *lexer) stateFn { return lx.error(errLexEscape{r}) } +func lexHexEscape(lx *lexer) stateFn { + var r rune + for i := 0; i < 2; i++ { + r = lx.next() + if !isHex(r) { + return lx.errorf(`expected two hexadecimal digits after '\x', but got %q instead`, lx.current()) + } + } + return lx.pop() +} + func lexShortUnicodeEscape(lx *lexer) stateFn { var r rune for i := 0; i < 4; i++ { r = lx.next() - if !isHexadecimal(r) { - return lx.errorf( - `expected four hexadecimal digits after '\u', but got %q instead`, - lx.current()) + if !isHex(r) { + return lx.errorf(`expected four hexadecimal digits after '\u', but got %q instead`, lx.current()) } } return lx.pop() @@ -857,10 +908,8 @@ func lexLongUnicodeEscape(lx *lexer) stateFn { var r rune for i := 0; i < 8; i++ { r = lx.next() - if !isHexadecimal(r) { - return lx.errorf( - `expected eight hexadecimal digits after '\U', but got %q instead`, - lx.current()) + if !isHex(r) { + return lx.errorf(`expected eight hexadecimal digits after '\U', but got %q instead`, lx.current()) } } return lx.pop() @@ -927,7 +976,7 @@ func lexDatetime(lx *lexer) stateFn { // lexHexInteger consumes a hexadecimal integer after seeing the '0x' prefix. func lexHexInteger(lx *lexer) stateFn { r := lx.next() - if isHexadecimal(r) { + if isHex(r) { return lexHexInteger } switch r { @@ -1061,7 +1110,7 @@ func lexBaseNumberOrDate(lx *lexer) stateFn { return lexOctalInteger case 'x': r = lx.peek() - if !isHexadecimal(r) { + if !isHex(r) { lx.errorf("not a hexidecimal number: '%s%c'", lx.current(), r) } return lexHexInteger @@ -1159,7 +1208,7 @@ func (itype itemType) String() string { return "EOF" case itemText: return "Text" - case itemString, itemRawString, itemMultilineString, itemRawMultilineString: + case itemString, itemStringEsc, itemRawString, itemMultilineString, itemRawMultilineString: return "String" case itemBool: return "Bool" @@ -1192,7 +1241,7 @@ func (itype itemType) String() string { } func (item item) String() string { - return fmt.Sprintf("(%s, %s)", item.typ.String(), item.val) + return fmt.Sprintf("(%s, %s)", item.typ, item.val) } func isWhitespace(r rune) bool { return r == '\t' || r == ' ' } @@ -1208,10 +1257,23 @@ func isControl(r rune) bool { // Control characters except \t, \r, \n func isDigit(r rune) bool { return r >= '0' && r <= '9' } func isBinary(r rune) bool { return r == '0' || r == '1' } func isOctal(r rune) bool { return r >= '0' && r <= '7' } -func isHexadecimal(r rune) bool { - return (r >= '0' && r <= '9') || (r >= 'a' && r <= 'f') || (r >= 'A' && r <= 'F') -} -func isBareKeyChar(r rune) bool { +func isHex(r rune) bool { return (r >= '0' && r <= '9') || (r|0x20 >= 'a' && r|0x20 <= 'f') } +func isBareKeyChar(r rune, tomlNext bool) bool { + if tomlNext { + return (r >= 'A' && r <= 'Z') || + (r >= 'a' && r <= 'z') || + (r >= '0' && r <= '9') || + r == '_' || r == '-' || + r == 0xb2 || r == 0xb3 || r == 0xb9 || (r >= 0xbc && r <= 0xbe) || + (r >= 0xc0 && r <= 0xd6) || (r >= 0xd8 && r <= 0xf6) || (r >= 0xf8 && r <= 0x037d) || + (r >= 0x037f && r <= 0x1fff) || + (r >= 0x200c && r <= 0x200d) || (r >= 0x203f && r <= 0x2040) || + (r >= 0x2070 && r <= 0x218f) || (r >= 0x2460 && r <= 0x24ff) || + (r >= 0x2c00 && r <= 0x2fef) || (r >= 0x3001 && r <= 0xd7ff) || + (r >= 0xf900 && r <= 0xfdcf) || (r >= 0xfdf0 && r <= 0xfffd) || + (r >= 0x10000 && r <= 0xeffff) + } + return (r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') || diff --git a/vendor/github.com/BurntSushi/toml/meta.go b/vendor/github.com/BurntSushi/toml/meta.go index 868619fb9750..e61453730040 100644 --- a/vendor/github.com/BurntSushi/toml/meta.go +++ b/vendor/github.com/BurntSushi/toml/meta.go @@ -12,10 +12,11 @@ import ( type MetaData struct { context Key // Used only during decoding. - mapping map[string]interface{} - types map[string]tomlType + keyInfo map[string]keyInfo + mapping map[string]any keys []Key decoded map[string]struct{} + data []byte // Input file; for errors. } // IsDefined reports if the key exists in the TOML data. @@ -30,12 +31,12 @@ func (md *MetaData) IsDefined(key ...string) bool { } var ( - hash map[string]interface{} + hash map[string]any ok bool - hashOrVal interface{} = md.mapping + hashOrVal any = md.mapping ) for _, k := range key { - if hash, ok = hashOrVal.(map[string]interface{}); !ok { + if hash, ok = hashOrVal.(map[string]any); !ok { return false } if hashOrVal, ok = hash[k]; !ok { @@ -50,8 +51,8 @@ func (md *MetaData) IsDefined(key ...string) bool { // Type will return the empty string if given an empty key or a key that does // not exist. Keys are case sensitive. func (md *MetaData) Type(key ...string) string { - if typ, ok := md.types[Key(key).String()]; ok { - return typ.typeString() + if ki, ok := md.keyInfo[Key(key).String()]; ok { + return ki.tomlType.typeString() } return "" } @@ -70,7 +71,7 @@ func (md *MetaData) Keys() []Key { // Undecoded returns all keys that have not been decoded in the order in which // they appear in the original TOML document. // -// This includes keys that haven't been decoded because of a Primitive value. +// This includes keys that haven't been decoded because of a [Primitive] value. // Once the Primitive value is decoded, the keys will be considered decoded. // // Also note that decoding into an empty interface will result in no decoding, @@ -88,33 +89,60 @@ func (md *MetaData) Undecoded() []Key { return undecoded } -// Key represents any TOML key, including key groups. Use (MetaData).Keys to get +// Key represents any TOML key, including key groups. Use [MetaData.Keys] to get // values of this type. type Key []string func (k Key) String() string { - ss := make([]string, len(k)) - for i := range k { - ss[i] = k.maybeQuoted(i) + // This is called quite often, so it's a bit funky to make it faster. + var b strings.Builder + b.Grow(len(k) * 25) +outer: + for i, kk := range k { + if i > 0 { + b.WriteByte('.') + } + if kk == "" { + b.WriteString(`""`) + } else { + for _, r := range kk { + // "Inline" isBareKeyChar + if !((r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') || r == '_' || r == '-') { + b.WriteByte('"') + b.WriteString(dblQuotedReplacer.Replace(kk)) + b.WriteByte('"') + continue outer + } + } + b.WriteString(kk) + } } - return strings.Join(ss, ".") + return b.String() } func (k Key) maybeQuoted(i int) string { if k[i] == "" { return `""` } - for _, c := range k[i] { - if !isBareKeyChar(c) { - return `"` + dblQuotedReplacer.Replace(k[i]) + `"` + for _, r := range k[i] { + if (r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') || r == '_' || r == '-' { + continue } + return `"` + dblQuotedReplacer.Replace(k[i]) + `"` } return k[i] } +// Like append(), but only increase the cap by 1. func (k Key) add(piece string) Key { + if cap(k) > len(k) { + return append(k, piece) + } newKey := make(Key, len(k)+1) copy(newKey, k) newKey[len(k)] = piece return newKey } + +func (k Key) parent() Key { return k[:len(k)-1] } // all except the last piece. +func (k Key) last() string { return k[len(k)-1] } // last piece of this key. diff --git a/vendor/github.com/BurntSushi/toml/parse.go b/vendor/github.com/BurntSushi/toml/parse.go index 8269cca17016..11ac3108be3f 100644 --- a/vendor/github.com/BurntSushi/toml/parse.go +++ b/vendor/github.com/BurntSushi/toml/parse.go @@ -2,6 +2,8 @@ package toml import ( "fmt" + "math" + "os" "strconv" "strings" "time" @@ -15,14 +17,23 @@ type parser struct { context Key // Full key for the current hash in scope. currentKey string // Base key name for everything except hashes. pos Position // Current position in the TOML file. + tomlNext bool - ordered []Key // List of keys in the order that they appear in the TOML data. - mapping map[string]interface{} // Map keyname → key value. - types map[string]tomlType // Map keyname → TOML type. - implicits map[string]struct{} // Record implicit keys (e.g. "key.group.names"). + ordered []Key // List of keys in the order that they appear in the TOML data. + + keyInfo map[string]keyInfo // Map keyname → info about the TOML key. + mapping map[string]any // Map keyname → key value. + implicits map[string]struct{} // Record implicit keys (e.g. "key.group.names"). +} + +type keyInfo struct { + pos Position + tomlType tomlType } func parse(data string) (p *parser, err error) { + _, tomlNext := os.LookupEnv("BURNTSUSHI_TOML_110") + defer func() { if r := recover(); r != nil { if pErr, ok := r.(ParseError); ok { @@ -35,9 +46,13 @@ func parse(data string) (p *parser, err error) { }() // Read over BOM; do this here as the lexer calls utf8.DecodeRuneInString() - // which mangles stuff. - if strings.HasPrefix(data, "\xff\xfe") || strings.HasPrefix(data, "\xfe\xff") { + // which mangles stuff. UTF-16 BOM isn't strictly valid, but some tools add + // it anyway. + if strings.HasPrefix(data, "\xff\xfe") || strings.HasPrefix(data, "\xfe\xff") { // UTF-16 data = data[2:] + //lint:ignore S1017 https://github.com/dominikh/go-tools/issues/1447 + } else if strings.HasPrefix(data, "\xef\xbb\xbf") { // UTF-8 + data = data[3:] } // Examine first few bytes for NULL bytes; this probably means it's a UTF-16 @@ -57,11 +72,12 @@ func parse(data string) (p *parser, err error) { } p = &parser{ - mapping: make(map[string]interface{}), - types: make(map[string]tomlType), - lx: lex(data), + keyInfo: make(map[string]keyInfo), + mapping: make(map[string]any), + lx: lex(data, tomlNext), ordered: make([]Key, 0), implicits: make(map[string]struct{}), + tomlNext: tomlNext, } for { item := p.next() @@ -74,7 +90,16 @@ func parse(data string) (p *parser, err error) { return p, nil } -func (p *parser) panicItemf(it item, format string, v ...interface{}) { +func (p *parser) panicErr(it item, err error) { + panic(ParseError{ + err: err, + Position: it.pos, + Line: it.pos.Len, + LastKey: p.current(), + }) +} + +func (p *parser) panicItemf(it item, format string, v ...any) { panic(ParseError{ Message: fmt.Sprintf(format, v...), Position: it.pos, @@ -83,7 +108,7 @@ func (p *parser) panicItemf(it item, format string, v ...interface{}) { }) } -func (p *parser) panicf(format string, v ...interface{}) { +func (p *parser) panicf(format string, v ...any) { panic(ParseError{ Message: fmt.Sprintf(format, v...), Position: p.pos, @@ -94,7 +119,7 @@ func (p *parser) panicf(format string, v ...interface{}) { func (p *parser) next() item { it := p.lx.nextItem() - //fmt.Printf("ITEM %-18s line %-3d │ %q\n", it.typ, it.line, it.val) + //fmt.Printf("ITEM %-18s line %-3d │ %q\n", it.typ, it.pos.Line, it.val) if it.typ == itemError { if it.err != nil { panic(ParseError{ @@ -116,7 +141,7 @@ func (p *parser) nextPos() item { return it } -func (p *parser) bug(format string, v ...interface{}) { +func (p *parser) bug(format string, v ...any) { panic(fmt.Sprintf("BUG: "+format+"\n\n", v...)) } @@ -146,7 +171,7 @@ func (p *parser) topLevel(item item) { p.assertEqual(itemTableEnd, name.typ) p.addContext(key, false) - p.setType("", tomlHash) + p.setType("", tomlHash, item.pos) p.ordered = append(p.ordered, key) case itemArrayTableStart: // [[ .. ]] name := p.nextPos() @@ -158,7 +183,7 @@ func (p *parser) topLevel(item item) { p.assertEqual(itemArrayTableEnd, name.typ) p.addContext(key, true) - p.setType("", tomlArrayHash) + p.setType("", tomlArrayHash, item.pos) p.ordered = append(p.ordered, key) case itemKeyStart: // key = .. outerContext := p.context @@ -171,19 +196,21 @@ func (p *parser) topLevel(item item) { p.assertEqual(itemKeyEnd, k.typ) /// The current key is the last part. - p.currentKey = key[len(key)-1] + p.currentKey = key.last() /// All the other parts (if any) are the context; need to set each part /// as implicit. - context := key[:len(key)-1] + context := key.parent() for i := range context { p.addImplicitContext(append(p.context, context[i:i+1]...)) } + p.ordered = append(p.ordered, p.context.add(p.currentKey)) /// Set value. - val, typ := p.value(p.next(), false) - p.set(p.currentKey, val, typ) - p.ordered = append(p.ordered, p.context.add(p.currentKey)) + vItem := p.next() + val, typ := p.value(vItem, false) + p.setValue(p.currentKey, val) + p.setType(p.currentKey, typ, vItem.pos) /// Remove the context we added (preserving any context from [tbl] lines). p.context = outerContext @@ -198,7 +225,7 @@ func (p *parser) keyString(it item) string { switch it.typ { case itemText: return it.val - case itemString, itemMultilineString, + case itemString, itemStringEsc, itemMultilineString, itemRawString, itemRawMultilineString: s, _ := p.value(it, false) return s.(string) @@ -215,12 +242,14 @@ var datetimeRepl = strings.NewReplacer( // value translates an expected value from the lexer into a Go value wrapped // as an empty interface. -func (p *parser) value(it item, parentIsArray bool) (interface{}, tomlType) { +func (p *parser) value(it item, parentIsArray bool) (any, tomlType) { switch it.typ { case itemString: + return it.val, p.typeOfPrimitive(it) + case itemStringEsc: return p.replaceEscapes(it, it.val), p.typeOfPrimitive(it) case itemMultilineString: - return p.replaceEscapes(it, stripFirstNewline(stripEscapedNewlines(it.val))), p.typeOfPrimitive(it) + return p.replaceEscapes(it, p.stripEscapedNewlines(stripFirstNewline(it.val))), p.typeOfPrimitive(it) case itemRawString: return it.val, p.typeOfPrimitive(it) case itemRawMultilineString: @@ -250,7 +279,7 @@ func (p *parser) value(it item, parentIsArray bool) (interface{}, tomlType) { panic("unreachable") } -func (p *parser) valueInteger(it item) (interface{}, tomlType) { +func (p *parser) valueInteger(it item) (any, tomlType) { if !numUnderscoresOK(it.val) { p.panicItemf(it, "Invalid integer %q: underscores must be surrounded by digits", it.val) } @@ -266,7 +295,7 @@ func (p *parser) valueInteger(it item) (interface{}, tomlType) { // So mark the former as a bug but the latter as a legitimate user // error. if e, ok := err.(*strconv.NumError); ok && e.Err == strconv.ErrRange { - p.panicItemf(it, "Integer '%s' is out of the range of 64-bit signed integers.", it.val) + p.panicErr(it, errParseRange{i: it.val, size: "int64"}) } else { p.bug("Expected integer value, but got '%s'.", it.val) } @@ -274,7 +303,7 @@ func (p *parser) valueInteger(it item) (interface{}, tomlType) { return num, p.typeOfPrimitive(it) } -func (p *parser) valueFloat(it item) (interface{}, tomlType) { +func (p *parser) valueFloat(it item) (any, tomlType) { parts := strings.FieldsFunc(it.val, func(r rune) bool { switch r { case '.', 'e', 'E': @@ -298,31 +327,42 @@ func (p *parser) valueFloat(it item) (interface{}, tomlType) { p.panicItemf(it, "Invalid float %q: '.' must be followed by one or more digits", it.val) } val := strings.Replace(it.val, "_", "", -1) - if val == "+nan" || val == "-nan" { // Go doesn't support this, but TOML spec does. + signbit := false + if val == "+nan" || val == "-nan" { + signbit = val == "-nan" val = "nan" } num, err := strconv.ParseFloat(val, 64) if err != nil { if e, ok := err.(*strconv.NumError); ok && e.Err == strconv.ErrRange { - p.panicItemf(it, "Float '%s' is out of the range of 64-bit IEEE-754 floating-point numbers.", it.val) + p.panicErr(it, errParseRange{i: it.val, size: "float64"}) } else { p.panicItemf(it, "Invalid float value: %q", it.val) } } + if signbit { + num = math.Copysign(num, -1) + } return num, p.typeOfPrimitive(it) } var dtTypes = []struct { fmt string zone *time.Location + next bool }{ - {time.RFC3339Nano, time.Local}, - {"2006-01-02T15:04:05.999999999", internal.LocalDatetime}, - {"2006-01-02", internal.LocalDate}, - {"15:04:05.999999999", internal.LocalTime}, + {time.RFC3339Nano, time.Local, false}, + {"2006-01-02T15:04:05.999999999", internal.LocalDatetime, false}, + {"2006-01-02", internal.LocalDate, false}, + {"15:04:05.999999999", internal.LocalTime, false}, + + // tomlNext + {"2006-01-02T15:04Z07:00", time.Local, true}, + {"2006-01-02T15:04", internal.LocalDatetime, true}, + {"15:04", internal.LocalTime, true}, } -func (p *parser) valueDatetime(it item) (interface{}, tomlType) { +func (p *parser) valueDatetime(it item) (any, tomlType) { it.val = datetimeRepl.Replace(it.val) var ( t time.Time @@ -330,29 +370,49 @@ func (p *parser) valueDatetime(it item) (interface{}, tomlType) { err error ) for _, dt := range dtTypes { + if dt.next && !p.tomlNext { + continue + } t, err = time.ParseInLocation(dt.fmt, it.val, dt.zone) if err == nil { + if missingLeadingZero(it.val, dt.fmt) { + p.panicErr(it, errParseDate{it.val}) + } ok = true break } } if !ok { - p.panicItemf(it, "Invalid TOML Datetime: %q.", it.val) + p.panicErr(it, errParseDate{it.val}) } return t, p.typeOfPrimitive(it) } -func (p *parser) valueArray(it item) (interface{}, tomlType) { - p.setType(p.currentKey, tomlArray) +// Go's time.Parse() will accept numbers without a leading zero; there isn't any +// way to require it. https://github.com/golang/go/issues/29911 +// +// Depend on the fact that the separators (- and :) should always be at the same +// location. +func missingLeadingZero(d, l string) bool { + for i, c := range []byte(l) { + if c == '.' || c == 'Z' { + return false + } + if (c < '0' || c > '9') && d[i] != c { + return true + } + } + return false +} - // p.setType(p.currentKey, typ) - var ( - types []tomlType +func (p *parser) valueArray(it item) (any, tomlType) { + p.setType(p.currentKey, tomlArray, it.pos) - // Initialize to a non-nil empty slice. This makes it consistent with - // how S = [] decodes into a non-nil slice inside something like struct - // { S []string }. See #338 - array = []interface{}{} + var ( + // Initialize to a non-nil slice to make it consistent with how S = [] + // decodes into a non-nil slice inside something like struct { S + // []string }. See #338 + array = make([]any, 0, 2) ) for it = p.next(); it.typ != itemArrayEnd; it = p.next() { if it.typ == itemCommentStart { @@ -362,20 +422,20 @@ func (p *parser) valueArray(it item) (interface{}, tomlType) { val, typ := p.value(it, true) array = append(array, val) - types = append(types, typ) - // XXX: types isn't used here, we need it to record the accurate type + // XXX: type isn't used here, we need it to record the accurate type // information. // // Not entirely sure how to best store this; could use "key[0]", // "key[1]" notation, or maybe store it on the Array type? + _ = typ } return array, tomlArray } -func (p *parser) valueInlineTable(it item, parentIsArray bool) (interface{}, tomlType) { +func (p *parser) valueInlineTable(it item, parentIsArray bool) (any, tomlType) { var ( - hash = make(map[string]interface{}) + topHash = make(map[string]any) outerContext = p.context outerKey = p.currentKey ) @@ -403,19 +463,33 @@ func (p *parser) valueInlineTable(it item, parentIsArray bool) (interface{}, tom p.assertEqual(itemKeyEnd, k.typ) /// The current key is the last part. - p.currentKey = key[len(key)-1] + p.currentKey = key.last() /// All the other parts (if any) are the context; need to set each part /// as implicit. - context := key[:len(key)-1] + context := key.parent() for i := range context { p.addImplicitContext(append(p.context, context[i:i+1]...)) } + p.ordered = append(p.ordered, p.context.add(p.currentKey)) /// Set the value. val, typ := p.value(p.next(), false) - p.set(p.currentKey, val, typ) - p.ordered = append(p.ordered, p.context.add(p.currentKey)) + p.setValue(p.currentKey, val) + p.setType(p.currentKey, typ, it.pos) + + hash := topHash + for _, c := range context { + h, ok := hash[c] + if !ok { + h = make(map[string]any) + hash[c] = h + } + hash, ok = h.(map[string]any) + if !ok { + p.panicf("%q is not a table", p.context) + } + } hash[p.currentKey] = val /// Restore context. @@ -423,7 +497,7 @@ func (p *parser) valueInlineTable(it item, parentIsArray bool) (interface{}, tom } p.context = outerContext p.currentKey = outerKey - return hash, tomlHash + return topHash, tomlHash } // numHasLeadingZero checks if this number has leading zeroes, allowing for '0', @@ -453,9 +527,9 @@ func numUnderscoresOK(s string) bool { } } - // isHexadecimal is a superset of all the permissable characters - // surrounding an underscore. - accept = isHexadecimal(r) + // isHexis a superset of all the permissable characters surrounding an + // underscore. + accept = isHex(r) } return accept } @@ -478,21 +552,19 @@ func numPeriodsOK(s string) bool { // Establishing the context also makes sure that the key isn't a duplicate, and // will create implicit hashes automatically. func (p *parser) addContext(key Key, array bool) { - var ok bool - - // Always start at the top level and drill down for our context. + /// Always start at the top level and drill down for our context. hashContext := p.mapping - keyContext := make(Key, 0) + keyContext := make(Key, 0, len(key)-1) - // We only need implicit hashes for key[0:-1] - for _, k := range key[0 : len(key)-1] { - _, ok = hashContext[k] + /// We only need implicit hashes for the parents. + for _, k := range key.parent() { + _, ok := hashContext[k] keyContext = append(keyContext, k) // No key? Make an implicit hash and move on. if !ok { p.addImplicit(keyContext) - hashContext[k] = make(map[string]interface{}) + hashContext[k] = make(map[string]any) } // If the hash context is actually an array of tables, then set @@ -501,9 +573,9 @@ func (p *parser) addContext(key Key, array bool) { // Otherwise, it better be a table, since this MUST be a key group (by // virtue of it not being the last element in a key). switch t := hashContext[k].(type) { - case []map[string]interface{}: + case []map[string]any: hashContext = t[len(t)-1] - case map[string]interface{}: + case map[string]any: hashContext = t default: p.panicf("Key '%s' was already created as a hash.", keyContext) @@ -514,39 +586,33 @@ func (p *parser) addContext(key Key, array bool) { if array { // If this is the first element for this array, then allocate a new // list of tables for it. - k := key[len(key)-1] + k := key.last() if _, ok := hashContext[k]; !ok { - hashContext[k] = make([]map[string]interface{}, 0, 4) + hashContext[k] = make([]map[string]any, 0, 4) } // Add a new table. But make sure the key hasn't already been used // for something else. - if hash, ok := hashContext[k].([]map[string]interface{}); ok { - hashContext[k] = append(hash, make(map[string]interface{})) + if hash, ok := hashContext[k].([]map[string]any); ok { + hashContext[k] = append(hash, make(map[string]any)) } else { p.panicf("Key '%s' was already created and cannot be used as an array.", key) } } else { - p.setValue(key[len(key)-1], make(map[string]interface{})) + p.setValue(key.last(), make(map[string]any)) } - p.context = append(p.context, key[len(key)-1]) -} - -// set calls setValue and setType. -func (p *parser) set(key string, val interface{}, typ tomlType) { - p.setValue(key, val) - p.setType(key, typ) + p.context = append(p.context, key.last()) } // setValue sets the given key to the given value in the current context. // It will make sure that the key hasn't already been defined, account for // implicit key groups. -func (p *parser) setValue(key string, value interface{}) { +func (p *parser) setValue(key string, value any) { var ( - tmpHash interface{} + tmpHash any ok bool hash = p.mapping - keyContext Key + keyContext = make(Key, 0, len(p.context)+1) ) for _, k := range p.context { keyContext = append(keyContext, k) @@ -554,11 +620,11 @@ func (p *parser) setValue(key string, value interface{}) { p.bug("Context for key '%s' has not been established.", keyContext) } switch t := tmpHash.(type) { - case []map[string]interface{}: + case []map[string]any: // The context is a table of hashes. Pick the most recent table // defined as the current hash. hash = t[len(t)-1] - case map[string]interface{}: + case map[string]any: hash = t default: p.panicf("Key '%s' has already been defined.", keyContext) @@ -585,9 +651,8 @@ func (p *parser) setValue(key string, value interface{}) { p.removeImplicit(keyContext) return } - - // Otherwise, we have a concrete key trying to override a previous - // key, which is *always* wrong. + // Otherwise, we have a concrete key trying to override a previous key, + // which is *always* wrong. p.panicf("Key '%s' has already been defined.", keyContext) } @@ -599,7 +664,7 @@ func (p *parser) setValue(key string, value interface{}) { // // Note that if `key` is empty, then the type given will be applied to the // current context (which is either a table or an array of tables). -func (p *parser) setType(key string, typ tomlType) { +func (p *parser) setType(key string, typ tomlType, pos Position) { keyContext := make(Key, 0, len(p.context)+1) keyContext = append(keyContext, p.context...) if len(key) > 0 { // allow type setting for hashes @@ -611,19 +676,16 @@ func (p *parser) setType(key string, typ tomlType) { if len(keyContext) == 0 { keyContext = Key{""} } - p.types[keyContext.String()] = typ + p.keyInfo[keyContext.String()] = keyInfo{tomlType: typ, pos: pos} } // Implicit keys need to be created when tables are implied in "a.b.c.d = 1" and // "[a.b.c]" (the "a", "b", and "c" hashes are never created explicitly). -func (p *parser) addImplicit(key Key) { p.implicits[key.String()] = struct{}{} } -func (p *parser) removeImplicit(key Key) { delete(p.implicits, key.String()) } -func (p *parser) isImplicit(key Key) bool { _, ok := p.implicits[key.String()]; return ok } -func (p *parser) isArray(key Key) bool { return p.types[key.String()] == tomlArray } -func (p *parser) addImplicitContext(key Key) { - p.addImplicit(key) - p.addContext(key, false) -} +func (p *parser) addImplicit(key Key) { p.implicits[key.String()] = struct{}{} } +func (p *parser) removeImplicit(key Key) { delete(p.implicits, key.String()) } +func (p *parser) isImplicit(key Key) bool { _, ok := p.implicits[key.String()]; return ok } +func (p *parser) isArray(key Key) bool { return p.keyInfo[key.String()].tomlType == tomlArray } +func (p *parser) addImplicitContext(key Key) { p.addImplicit(key); p.addContext(key, false) } // current returns the full key name of the current context. func (p *parser) current() string { @@ -646,112 +708,131 @@ func stripFirstNewline(s string) string { return s } -// Remove newlines inside triple-quoted strings if a line ends with "\". -func stripEscapedNewlines(s string) string { - split := strings.Split(s, "\n") - if len(split) < 1 { - return s - } - - escNL := false // Keep track of the last non-blank line was escaped. - for i, line := range split { - line = strings.TrimRight(line, " \t\r") - - if len(line) == 0 || line[len(line)-1] != '\\' { - split[i] = strings.TrimRight(split[i], "\r") - if !escNL && i != len(split)-1 { - split[i] += "\n" - } - continue +// stripEscapedNewlines removes whitespace after line-ending backslashes in +// multiline strings. +// +// A line-ending backslash is an unescaped \ followed only by whitespace until +// the next newline. After a line-ending backslash, all whitespace is removed +// until the next non-whitespace character. +func (p *parser) stripEscapedNewlines(s string) string { + var ( + b strings.Builder + i int + ) + b.Grow(len(s)) + for { + ix := strings.Index(s[i:], `\`) + if ix < 0 { + b.WriteString(s) + return b.String() } + i += ix - escBS := true - for j := len(line) - 1; j >= 0 && line[j] == '\\'; j-- { - escBS = !escBS + if len(s) > i+1 && s[i+1] == '\\' { + // Escaped backslash. + i += 2 + continue } - if escNL { - line = strings.TrimLeft(line, " \t\r") + // Scan until the next non-whitespace. + j := i + 1 + whitespaceLoop: + for ; j < len(s); j++ { + switch s[j] { + case ' ', '\t', '\r', '\n': + default: + break whitespaceLoop + } } - escNL = !escBS - - if escBS { - split[i] += "\n" + if j == i+1 { + // Not a whitespace escape. + i++ continue } - - split[i] = line[:len(line)-1] // Remove \ - if len(split)-1 > i { - split[i+1] = strings.TrimLeft(split[i+1], " \t\r") + if !strings.Contains(s[i:j], "\n") { + // This is not a line-ending backslash. (It's a bad escape sequence, + // but we can let replaceEscapes catch it.) + i++ + continue } + b.WriteString(s[:i]) + s = s[j:] + i = 0 } - return strings.Join(split, "") } func (p *parser) replaceEscapes(it item, str string) string { - replaced := make([]rune, 0, len(str)) - s := []byte(str) - r := 0 - for r < len(s) { - if s[r] != '\\' { - c, size := utf8.DecodeRune(s[r:]) - r += size - replaced = append(replaced, c) + var ( + b strings.Builder + skip = 0 + ) + b.Grow(len(str)) + for i, c := range str { + if skip > 0 { + skip-- continue } - r += 1 - if r >= len(s) { + if c != '\\' { + b.WriteRune(c) + continue + } + + if i >= len(str) { p.bug("Escape sequence at end of string.") return "" } - switch s[r] { + switch str[i+1] { default: - p.bug("Expected valid escape code after \\, but got %q.", s[r]) - return "" + p.bug("Expected valid escape code after \\, but got %q.", str[i+1]) case ' ', '\t': - p.panicItemf(it, "invalid escape: '\\%c'", s[r]) - return "" + p.panicItemf(it, "invalid escape: '\\%c'", str[i+1]) case 'b': - replaced = append(replaced, rune(0x0008)) - r += 1 + b.WriteByte(0x08) + skip = 1 case 't': - replaced = append(replaced, rune(0x0009)) - r += 1 + b.WriteByte(0x09) + skip = 1 case 'n': - replaced = append(replaced, rune(0x000A)) - r += 1 + b.WriteByte(0x0a) + skip = 1 case 'f': - replaced = append(replaced, rune(0x000C)) - r += 1 + b.WriteByte(0x0c) + skip = 1 case 'r': - replaced = append(replaced, rune(0x000D)) - r += 1 + b.WriteByte(0x0d) + skip = 1 + case 'e': + if p.tomlNext { + b.WriteByte(0x1b) + skip = 1 + } case '"': - replaced = append(replaced, rune(0x0022)) - r += 1 + b.WriteByte(0x22) + skip = 1 case '\\': - replaced = append(replaced, rune(0x005C)) - r += 1 + b.WriteByte(0x5c) + skip = 1 + // The lexer guarantees the correct number of characters are present; + // don't need to check here. + case 'x': + if p.tomlNext { + escaped := p.asciiEscapeToUnicode(it, str[i+2:i+4]) + b.WriteRune(escaped) + skip = 3 + } case 'u': - // At this point, we know we have a Unicode escape of the form - // `uXXXX` at [r, r+5). (Because the lexer guarantees this - // for us.) - escaped := p.asciiEscapeToUnicode(it, s[r+1:r+5]) - replaced = append(replaced, escaped) - r += 5 + escaped := p.asciiEscapeToUnicode(it, str[i+2:i+6]) + b.WriteRune(escaped) + skip = 5 case 'U': - // At this point, we know we have a Unicode escape of the form - // `uXXXX` at [r, r+9). (Because the lexer guarantees this - // for us.) - escaped := p.asciiEscapeToUnicode(it, s[r+1:r+9]) - replaced = append(replaced, escaped) - r += 9 + escaped := p.asciiEscapeToUnicode(it, str[i+2:i+10]) + b.WriteRune(escaped) + skip = 9 } } - return string(replaced) + return b.String() } -func (p *parser) asciiEscapeToUnicode(it item, bs []byte) rune { - s := string(bs) +func (p *parser) asciiEscapeToUnicode(it item, s string) rune { hex, err := strconv.ParseUint(strings.ToLower(s), 16, 32) if err != nil { p.bug("Could not parse '%s' as a hexadecimal number, but the lexer claims it's OK: %s", s, err) diff --git a/vendor/github.com/BurntSushi/toml/type_fields.go b/vendor/github.com/BurntSushi/toml/type_fields.go index 254ca82e5494..10c51f7eeb41 100644 --- a/vendor/github.com/BurntSushi/toml/type_fields.go +++ b/vendor/github.com/BurntSushi/toml/type_fields.go @@ -25,10 +25,8 @@ type field struct { // breaking ties with index sequence. type byName []field -func (x byName) Len() int { return len(x) } - +func (x byName) Len() int { return len(x) } func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } - func (x byName) Less(i, j int) bool { if x[i].name != x[j].name { return x[i].name < x[j].name @@ -45,10 +43,8 @@ func (x byName) Less(i, j int) bool { // byIndex sorts field by index sequence. type byIndex []field -func (x byIndex) Len() int { return len(x) } - +func (x byIndex) Len() int { return len(x) } func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] } - func (x byIndex) Less(i, j int) bool { for k, xik := range x[i].index { if k >= len(x[j].index) { diff --git a/vendor/github.com/BurntSushi/toml/type_toml.go b/vendor/github.com/BurntSushi/toml/type_toml.go index 4e90d77373b9..1c090d331e3f 100644 --- a/vendor/github.com/BurntSushi/toml/type_toml.go +++ b/vendor/github.com/BurntSushi/toml/type_toml.go @@ -22,13 +22,8 @@ func typeIsTable(t tomlType) bool { type tomlBaseType string -func (btype tomlBaseType) typeString() string { - return string(btype) -} - -func (btype tomlBaseType) String() string { - return btype.typeString() -} +func (btype tomlBaseType) typeString() string { return string(btype) } +func (btype tomlBaseType) String() string { return btype.typeString() } var ( tomlInteger tomlBaseType = "Integer" @@ -54,7 +49,7 @@ func (p *parser) typeOfPrimitive(lexItem item) tomlType { return tomlFloat case itemDatetime: return tomlDatetime - case itemString: + case itemString, itemStringEsc: return tomlString case itemMultilineString: return tomlString diff --git a/vendor/github.com/alessio/shellescape/.golangci.yml b/vendor/github.com/alessio/shellescape/.golangci.yml index cd4a17e442cb..836dabbba4f0 100644 --- a/vendor/github.com/alessio/shellescape/.golangci.yml +++ b/vendor/github.com/alessio/shellescape/.golangci.yml @@ -6,25 +6,20 @@ linters: disable-all: true enable: - bodyclose - - deadcode - - depguard - dogsled - goconst - gocritic - gofmt - goimports - - golint - gosec - gosimple - govet - ineffassign - - interfacer - - maligned - misspell - prealloc - - scopelint + - exportloopref + - revive - staticcheck - - structcheck - stylecheck - typecheck - unconvert diff --git a/vendor/github.com/alessio/shellescape/.goreleaser.yml b/vendor/github.com/alessio/shellescape/.goreleaser.yml index 064c9374d790..0915eb869b4b 100644 --- a/vendor/github.com/alessio/shellescape/.goreleaser.yml +++ b/vendor/github.com/alessio/shellescape/.goreleaser.yml @@ -9,18 +9,39 @@ before: builds: - env: - CGO_ENABLED=0 + - >- + {{- if eq .Os "darwin" }} + {{- if eq .Arch "amd64"}}CC=o64-clang{{- end }} + {{- if eq .Arch "arm64"}}CC=aarch64-apple-darwin20.2-clang{{- end }} + {{- end }} + {{- if eq .Os "windows" }} + {{- if eq .Arch "amd64" }}CC=x86_64-w64-mingw32-gcc{{- end }} + {{- end }} main: ./cmd/escargs goos: - linux - windows - darwin -archives: - - replacements: - darwin: Darwin - linux: Linux - windows: Windows - 386: i386 - amd64: x86_64 + - freebsd + goarch: + - amd64 + - arm64 + - arm + goarm: + - 6 + - 7 + goamd64: + - v2 + - v3 + ignore: + - goos: darwin + goarch: 386 + - goos: linux + goarch: arm + goarm: 7 + - goarm: mips64 + - gomips: hardfloat + - goamd64: v4 checksum: name_template: 'checksums.txt' snapshot: diff --git a/vendor/github.com/emicklei/go-restful/v3/CHANGES.md b/vendor/github.com/emicklei/go-restful/v3/CHANGES.md index 5edd5a7ca9a3..9e790390b627 100644 --- a/vendor/github.com/emicklei/go-restful/v3/CHANGES.md +++ b/vendor/github.com/emicklei/go-restful/v3/CHANGES.md @@ -1,5 +1,17 @@ # Change history of go-restful + +## [v3.12.0] - 2024-03-11 +- add Flush method #529 (#538) +- fix: Improper handling of empty POST requests (#543) + +## [v3.11.3] - 2024-01-09 +- better not have 2 tags on one commit + +## [v3.11.1, v3.11.2] - 2024-01-09 + +- fix by restoring custom JSON handler functions (Mike Beaumont #540) + ## [v3.11.0] - 2023-08-19 - restored behavior as <= v3.9.0 with option to change path strategy using TrimRightSlashEnabled. diff --git a/vendor/github.com/emicklei/go-restful/v3/README.md b/vendor/github.com/emicklei/go-restful/v3/README.md index e3e30080ec18..7234604e47b8 100644 --- a/vendor/github.com/emicklei/go-restful/v3/README.md +++ b/vendor/github.com/emicklei/go-restful/v3/README.md @@ -2,7 +2,6 @@ go-restful ========== package for building REST-style Web Services using Google Go -[![Build Status](https://travis-ci.org/emicklei/go-restful.png)](https://travis-ci.org/emicklei/go-restful) [![Go Report Card](https://goreportcard.com/badge/github.com/emicklei/go-restful)](https://goreportcard.com/report/github.com/emicklei/go-restful) [![GoDoc](https://godoc.org/github.com/emicklei/go-restful?status.svg)](https://pkg.go.dev/github.com/emicklei/go-restful) [![codecov](https://codecov.io/gh/emicklei/go-restful/branch/master/graph/badge.svg)](https://codecov.io/gh/emicklei/go-restful) @@ -95,8 +94,7 @@ There are several hooks to customize the behavior of the go-restful package. - Trace logging - Compression - Encoders for other serializers -- Use [jsoniter](https://github.com/json-iterator/go) by building this package using a build tag, e.g. `go build -tags=jsoniter .` -- Use the package variable `TrimRightSlashEnabled` (default true) to control the behavior of matching routes that end with a slash `/` +- Use the package variable `TrimRightSlashEnabled` (default true) to control the behavior of matching routes that end with a slash `/` ## Resources diff --git a/vendor/github.com/emicklei/go-restful/v3/compress.go b/vendor/github.com/emicklei/go-restful/v3/compress.go index 1ff239f99fe7..80adf55fdfee 100644 --- a/vendor/github.com/emicklei/go-restful/v3/compress.go +++ b/vendor/github.com/emicklei/go-restful/v3/compress.go @@ -49,6 +49,16 @@ func (c *CompressingResponseWriter) CloseNotify() <-chan bool { return c.writer.(http.CloseNotifier).CloseNotify() } +// Flush is part of http.Flusher interface. Noop if the underlying writer doesn't support it. +func (c *CompressingResponseWriter) Flush() { + flusher, ok := c.writer.(http.Flusher) + if !ok { + // writer doesn't support http.Flusher interface + return + } + flusher.Flush() +} + // Close the underlying compressor func (c *CompressingResponseWriter) Close() error { if c.isCompressorClosed() { diff --git a/vendor/github.com/emicklei/go-restful/v3/entity_accessors.go b/vendor/github.com/emicklei/go-restful/v3/entity_accessors.go index 66dfc824f55b..9808752acdf9 100644 --- a/vendor/github.com/emicklei/go-restful/v3/entity_accessors.go +++ b/vendor/github.com/emicklei/go-restful/v3/entity_accessors.go @@ -5,11 +5,18 @@ package restful // that can be found in the LICENSE file. import ( + "encoding/json" "encoding/xml" "strings" "sync" ) +var ( + MarshalIndent = json.MarshalIndent + NewDecoder = json.NewDecoder + NewEncoder = json.NewEncoder +) + // EntityReaderWriter can read and write values using an encoding such as JSON,XML. type EntityReaderWriter interface { // Read a serialized version of the value from the request. diff --git a/vendor/github.com/emicklei/go-restful/v3/json.go b/vendor/github.com/emicklei/go-restful/v3/json.go deleted file mode 100644 index 871165166a16..000000000000 --- a/vendor/github.com/emicklei/go-restful/v3/json.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build !jsoniter - -package restful - -import "encoding/json" - -var ( - MarshalIndent = json.MarshalIndent - NewDecoder = json.NewDecoder - NewEncoder = json.NewEncoder -) diff --git a/vendor/github.com/emicklei/go-restful/v3/jsoniter.go b/vendor/github.com/emicklei/go-restful/v3/jsoniter.go deleted file mode 100644 index 11b8f8ae7f17..000000000000 --- a/vendor/github.com/emicklei/go-restful/v3/jsoniter.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build jsoniter - -package restful - -import "github.com/json-iterator/go" - -var ( - json = jsoniter.ConfigCompatibleWithStandardLibrary - MarshalIndent = json.MarshalIndent - NewDecoder = json.NewDecoder - NewEncoder = json.NewEncoder -) diff --git a/vendor/github.com/emicklei/go-restful/v3/jsr311.go b/vendor/github.com/emicklei/go-restful/v3/jsr311.go index 07a0c91e9424..a9b3faaa81fa 100644 --- a/vendor/github.com/emicklei/go-restful/v3/jsr311.go +++ b/vendor/github.com/emicklei/go-restful/v3/jsr311.go @@ -155,7 +155,7 @@ func (r RouterJSR311) detectRoute(routes []Route, httpRequest *http.Request) (*R method, length := httpRequest.Method, httpRequest.Header.Get("Content-Length") if (method == http.MethodPost || method == http.MethodPut || - method == http.MethodPatch) && length == "" { + method == http.MethodPatch) && (length == "" || length == "0") { return nil, NewError( http.StatusUnsupportedMediaType, fmt.Sprintf("415: Unsupported Media Type\n\nAvailable representations: %s", strings.Join(available, ", ")), diff --git a/vendor/github.com/go-task/slim-sprig/.editorconfig b/vendor/github.com/go-task/slim-sprig/v3/.editorconfig similarity index 100% rename from vendor/github.com/go-task/slim-sprig/.editorconfig rename to vendor/github.com/go-task/slim-sprig/v3/.editorconfig diff --git a/vendor/github.com/go-task/slim-sprig/.gitattributes b/vendor/github.com/go-task/slim-sprig/v3/.gitattributes similarity index 100% rename from vendor/github.com/go-task/slim-sprig/.gitattributes rename to vendor/github.com/go-task/slim-sprig/v3/.gitattributes diff --git a/vendor/github.com/go-task/slim-sprig/.gitignore b/vendor/github.com/go-task/slim-sprig/v3/.gitignore similarity index 100% rename from vendor/github.com/go-task/slim-sprig/.gitignore rename to vendor/github.com/go-task/slim-sprig/v3/.gitignore diff --git a/vendor/github.com/go-task/slim-sprig/CHANGELOG.md b/vendor/github.com/go-task/slim-sprig/v3/CHANGELOG.md similarity index 95% rename from vendor/github.com/go-task/slim-sprig/CHANGELOG.md rename to vendor/github.com/go-task/slim-sprig/v3/CHANGELOG.md index 61d8ebffc375..2ce45dd4eca6 100644 --- a/vendor/github.com/go-task/slim-sprig/CHANGELOG.md +++ b/vendor/github.com/go-task/slim-sprig/v3/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## Release 3.2.3 (2022-11-29) + +### Changed + +- Updated docs (thanks @book987 @aJetHorn @neelayu @pellizzetti @apricote @SaigyoujiYuyuko233 @AlekSi) +- #348: Updated huandu/xstrings which fixed a snake case bug (thanks @yxxhero) +- #353: Updated masterminds/semver which included bug fixes +- #354: Updated golang.org/x/crypto which included bug fixes + +## Release 3.2.2 (2021-02-04) + +This is a re-release of 3.2.1 to satisfy something with the Go module system. + +## Release 3.2.1 (2021-02-04) + +### Changed + +- Upgraded `Masterminds/goutils` to `v1.1.1`. see the [Security Advisory](https://github.com/Masterminds/goutils/security/advisories/GHSA-xg2h-wx96-xgxr) + ## Release 3.2.0 (2020-12-14) ### Added diff --git a/vendor/github.com/go-task/slim-sprig/LICENSE.txt b/vendor/github.com/go-task/slim-sprig/v3/LICENSE.txt similarity index 100% rename from vendor/github.com/go-task/slim-sprig/LICENSE.txt rename to vendor/github.com/go-task/slim-sprig/v3/LICENSE.txt diff --git a/vendor/github.com/go-task/slim-sprig/README.md b/vendor/github.com/go-task/slim-sprig/v3/README.md similarity index 88% rename from vendor/github.com/go-task/slim-sprig/README.md rename to vendor/github.com/go-task/slim-sprig/v3/README.md index 72579471ff0e..b5ab564254f4 100644 --- a/vendor/github.com/go-task/slim-sprig/README.md +++ b/vendor/github.com/go-task/slim-sprig/v3/README.md @@ -1,4 +1,4 @@ -# Slim-Sprig: Template functions for Go templates [![GoDoc](https://godoc.org/github.com/go-task/slim-sprig?status.svg)](https://godoc.org/github.com/go-task/slim-sprig) [![Go Report Card](https://goreportcard.com/badge/github.com/go-task/slim-sprig)](https://goreportcard.com/report/github.com/go-task/slim-sprig) +# Slim-Sprig: Template functions for Go templates [![Go Reference](https://pkg.go.dev/badge/github.com/go-task/slim-sprig/v3.svg)](https://pkg.go.dev/github.com/go-task/slim-sprig/v3) Slim-Sprig is a fork of [Sprig](https://github.com/Masterminds/sprig), but with all functions that depend on external (non standard library) or crypto packages diff --git a/vendor/github.com/go-task/slim-sprig/Taskfile.yml b/vendor/github.com/go-task/slim-sprig/v3/Taskfile.yml similarity index 89% rename from vendor/github.com/go-task/slim-sprig/Taskfile.yml rename to vendor/github.com/go-task/slim-sprig/v3/Taskfile.yml index cdcfd223b719..8e6346bb19eb 100644 --- a/vendor/github.com/go-task/slim-sprig/Taskfile.yml +++ b/vendor/github.com/go-task/slim-sprig/v3/Taskfile.yml @@ -1,6 +1,6 @@ # https://taskfile.dev -version: '2' +version: '3' tasks: default: diff --git a/vendor/github.com/go-task/slim-sprig/crypto.go b/vendor/github.com/go-task/slim-sprig/v3/crypto.go similarity index 100% rename from vendor/github.com/go-task/slim-sprig/crypto.go rename to vendor/github.com/go-task/slim-sprig/v3/crypto.go diff --git a/vendor/github.com/go-task/slim-sprig/date.go b/vendor/github.com/go-task/slim-sprig/v3/date.go similarity index 100% rename from vendor/github.com/go-task/slim-sprig/date.go rename to vendor/github.com/go-task/slim-sprig/v3/date.go diff --git a/vendor/github.com/go-task/slim-sprig/defaults.go b/vendor/github.com/go-task/slim-sprig/v3/defaults.go similarity index 100% rename from vendor/github.com/go-task/slim-sprig/defaults.go rename to vendor/github.com/go-task/slim-sprig/v3/defaults.go diff --git a/vendor/github.com/go-task/slim-sprig/dict.go b/vendor/github.com/go-task/slim-sprig/v3/dict.go similarity index 100% rename from vendor/github.com/go-task/slim-sprig/dict.go rename to vendor/github.com/go-task/slim-sprig/v3/dict.go diff --git a/vendor/github.com/go-task/slim-sprig/doc.go b/vendor/github.com/go-task/slim-sprig/v3/doc.go similarity index 100% rename from vendor/github.com/go-task/slim-sprig/doc.go rename to vendor/github.com/go-task/slim-sprig/v3/doc.go diff --git a/vendor/github.com/go-task/slim-sprig/functions.go b/vendor/github.com/go-task/slim-sprig/v3/functions.go similarity index 100% rename from vendor/github.com/go-task/slim-sprig/functions.go rename to vendor/github.com/go-task/slim-sprig/v3/functions.go diff --git a/vendor/github.com/go-task/slim-sprig/list.go b/vendor/github.com/go-task/slim-sprig/v3/list.go similarity index 100% rename from vendor/github.com/go-task/slim-sprig/list.go rename to vendor/github.com/go-task/slim-sprig/v3/list.go diff --git a/vendor/github.com/go-task/slim-sprig/network.go b/vendor/github.com/go-task/slim-sprig/v3/network.go similarity index 100% rename from vendor/github.com/go-task/slim-sprig/network.go rename to vendor/github.com/go-task/slim-sprig/v3/network.go diff --git a/vendor/github.com/go-task/slim-sprig/numeric.go b/vendor/github.com/go-task/slim-sprig/v3/numeric.go similarity index 100% rename from vendor/github.com/go-task/slim-sprig/numeric.go rename to vendor/github.com/go-task/slim-sprig/v3/numeric.go diff --git a/vendor/github.com/go-task/slim-sprig/reflect.go b/vendor/github.com/go-task/slim-sprig/v3/reflect.go similarity index 100% rename from vendor/github.com/go-task/slim-sprig/reflect.go rename to vendor/github.com/go-task/slim-sprig/v3/reflect.go diff --git a/vendor/github.com/go-task/slim-sprig/regex.go b/vendor/github.com/go-task/slim-sprig/v3/regex.go similarity index 100% rename from vendor/github.com/go-task/slim-sprig/regex.go rename to vendor/github.com/go-task/slim-sprig/v3/regex.go diff --git a/vendor/github.com/go-task/slim-sprig/strings.go b/vendor/github.com/go-task/slim-sprig/v3/strings.go similarity index 100% rename from vendor/github.com/go-task/slim-sprig/strings.go rename to vendor/github.com/go-task/slim-sprig/v3/strings.go diff --git a/vendor/github.com/go-task/slim-sprig/url.go b/vendor/github.com/go-task/slim-sprig/v3/url.go similarity index 100% rename from vendor/github.com/go-task/slim-sprig/url.go rename to vendor/github.com/go-task/slim-sprig/v3/url.go diff --git a/vendor/github.com/google/pprof/profile/encode.go b/vendor/github.com/google/pprof/profile/encode.go index 182c926b9089..860bb304c349 100644 --- a/vendor/github.com/google/pprof/profile/encode.go +++ b/vendor/github.com/google/pprof/profile/encode.go @@ -530,6 +530,7 @@ func (p *Line) decoder() []decoder { func (p *Line) encode(b *buffer) { encodeUint64Opt(b, 1, p.functionIDX) encodeInt64Opt(b, 2, p.Line) + encodeInt64Opt(b, 3, p.Column) } var lineDecoder = []decoder{ @@ -538,6 +539,8 @@ var lineDecoder = []decoder{ func(b *buffer, m message) error { return decodeUint64(b, &m.(*Line).functionIDX) }, // optional int64 line = 2 func(b *buffer, m message) error { return decodeInt64(b, &m.(*Line).Line) }, + // optional int64 column = 3 + func(b *buffer, m message) error { return decodeInt64(b, &m.(*Line).Column) }, } func (p *Function) decoder() []decoder { diff --git a/vendor/github.com/google/pprof/profile/legacy_java_profile.go b/vendor/github.com/google/pprof/profile/legacy_java_profile.go index 91f45e53c6c2..4580bab18396 100644 --- a/vendor/github.com/google/pprof/profile/legacy_java_profile.go +++ b/vendor/github.com/google/pprof/profile/legacy_java_profile.go @@ -56,7 +56,7 @@ func javaCPUProfile(b []byte, period int64, parse func(b []byte) (uint64, []byte } // Strip out addresses for better merge. - if err = p.Aggregate(true, true, true, true, false); err != nil { + if err = p.Aggregate(true, true, true, true, false, false); err != nil { return nil, err } @@ -99,7 +99,7 @@ func parseJavaProfile(b []byte) (*Profile, error) { } // Strip out addresses for better merge. - if err = p.Aggregate(true, true, true, true, false); err != nil { + if err = p.Aggregate(true, true, true, true, false, false); err != nil { return nil, err } diff --git a/vendor/github.com/google/pprof/profile/merge.go b/vendor/github.com/google/pprof/profile/merge.go index 4b66282cb8e0..eee0132e7406 100644 --- a/vendor/github.com/google/pprof/profile/merge.go +++ b/vendor/github.com/google/pprof/profile/merge.go @@ -326,12 +326,13 @@ func (l *Location) key() locationKey { key.addr -= l.Mapping.Start key.mappingID = l.Mapping.ID } - lines := make([]string, len(l.Line)*2) + lines := make([]string, len(l.Line)*3) for i, line := range l.Line { if line.Function != nil { lines[i*2] = strconv.FormatUint(line.Function.ID, 16) } lines[i*2+1] = strconv.FormatInt(line.Line, 16) + lines[i*2+2] = strconv.FormatInt(line.Column, 16) } key.lines = strings.Join(lines, "|") return key @@ -418,6 +419,7 @@ func (pm *profileMerger) mapLine(src Line) Line { ln := Line{ Function: pm.mapFunction(src.Function), Line: src.Line, + Column: src.Column, } return ln } diff --git a/vendor/github.com/google/pprof/profile/profile.go b/vendor/github.com/google/pprof/profile/profile.go index 60ef7e92687f..62df80a55636 100644 --- a/vendor/github.com/google/pprof/profile/profile.go +++ b/vendor/github.com/google/pprof/profile/profile.go @@ -145,6 +145,7 @@ type Location struct { type Line struct { Function *Function Line int64 + Column int64 functionIDX uint64 } @@ -436,7 +437,7 @@ func (p *Profile) CheckValid() error { // Aggregate merges the locations in the profile into equivalence // classes preserving the request attributes. It also updates the // samples to point to the merged locations. -func (p *Profile) Aggregate(inlineFrame, function, filename, linenumber, address bool) error { +func (p *Profile) Aggregate(inlineFrame, function, filename, linenumber, columnnumber, address bool) error { for _, m := range p.Mapping { m.HasInlineFrames = m.HasInlineFrames && inlineFrame m.HasFunctions = m.HasFunctions && function @@ -458,7 +459,7 @@ func (p *Profile) Aggregate(inlineFrame, function, filename, linenumber, address } // Aggregate locations - if !inlineFrame || !address || !linenumber { + if !inlineFrame || !address || !linenumber || !columnnumber { for _, l := range p.Location { if !inlineFrame && len(l.Line) > 1 { l.Line = l.Line[len(l.Line)-1:] @@ -466,6 +467,12 @@ func (p *Profile) Aggregate(inlineFrame, function, filename, linenumber, address if !linenumber { for i := range l.Line { l.Line[i].Line = 0 + l.Line[i].Column = 0 + } + } + if !columnnumber { + for i := range l.Line { + l.Line[i].Column = 0 } } if !address { @@ -627,10 +634,11 @@ func (l *Location) string() string { for li := range l.Line { lnStr := "??" if fn := l.Line[li].Function; fn != nil { - lnStr = fmt.Sprintf("%s %s:%d s=%d", + lnStr = fmt.Sprintf("%s %s:%d:%d s=%d", fn.Name, fn.Filename, l.Line[li].Line, + l.Line[li].Column, fn.StartLine) if fn.Name != fn.SystemName { lnStr = lnStr + "(" + fn.SystemName + ")" diff --git a/vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md b/vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md index 44222220a383..0a894979998f 100644 --- a/vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md +++ b/vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md @@ -1,3 +1,23 @@ +## 2.17.2 + +### Fixes +- fix: close files [32259c8] +- fix github output log level for skipped specs [780e7a3] + +### Maintenance +- Bump github.com/google/pprof [d91fe4e] +- Bump github.com/go-task/slim-sprig to v3 [8cb662e] +- Bump golang.org/x/net in /integration/_fixtures/version_mismatch_fixture (#1391) [3134422] +- Bump github-pages from 230 to 231 in /docs (#1384) [eca81b4] +- Bump golang.org/x/tools from 0.19.0 to 0.20.0 (#1383) [760def8] +- Bump golang.org/x/net from 0.23.0 to 0.24.0 (#1381) [4ce33f4] +- Fix test for gomega version bump [f2fcd97] +- Bump github.com/onsi/gomega from 1.30.0 to 1.33.0 (#1390) [fd622d2] +- Bump golang.org/x/tools from 0.17.0 to 0.19.0 (#1368) [5474a26] +- Bump github-pages from 229 to 230 in /docs (#1359) [e6d1170] +- Bump google.golang.org/protobuf from 1.28.0 to 1.33.0 (#1374) [7f447b2] +- Bump golang.org/x/net from 0.20.0 to 0.23.0 (#1380) [f15239a] + ## 2.17.1 ### Fixes diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/bootstrap_command.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/bootstrap_command.go index 73aff0b7a185..b2dc59be66fd 100644 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/bootstrap_command.go +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/bootstrap_command.go @@ -7,7 +7,7 @@ import ( "os" "text/template" - sprig "github.com/go-task/slim-sprig" + sprig "github.com/go-task/slim-sprig/v3" "github.com/onsi/ginkgo/v2/ginkgo/command" "github.com/onsi/ginkgo/v2/ginkgo/internal" "github.com/onsi/ginkgo/v2/types" diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/generate_command.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/generate_command.go index be01dec979dc..cf3b7cb6d6d5 100644 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/generate_command.go +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/generate_command.go @@ -10,7 +10,7 @@ import ( "strings" "text/template" - sprig "github.com/go-task/slim-sprig" + sprig "github.com/go-task/slim-sprig/v3" "github.com/onsi/ginkgo/v2/ginkgo/command" "github.com/onsi/ginkgo/v2/ginkgo/internal" "github.com/onsi/ginkgo/v2/types" @@ -174,6 +174,7 @@ func moduleName(modRoot string) string { if err != nil { return "" } + defer modFile.Close() mod := make([]byte, 128) _, err = modFile.Read(mod) diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/profiles_and_reports.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/profiles_and_reports.go index 5f35864ddba7..8e16d2bb034b 100644 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/profiles_and_reports.go +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/profiles_and_reports.go @@ -161,6 +161,7 @@ func MergeAndCleanupCoverProfiles(profiles []string, destination string) error { if err != nil { return err } + defer dst.Close() err = DumpCoverProfiles(merged, dst) if err != nil { return err @@ -196,6 +197,7 @@ func MergeProfiles(profilePaths []string, destination string) error { return fmt.Errorf("Could not open profile: %s\n%s", profilePath, err.Error()) } prof, err := profile.Parse(proFile) + _ = proFile.Close() if err != nil { return fmt.Errorf("Could not parse profile: %s\n%s", profilePath, err.Error()) } diff --git a/vendor/github.com/onsi/ginkgo/v2/reporters/default_reporter.go b/vendor/github.com/onsi/ginkgo/v2/reporters/default_reporter.go index 4026859ec397..980973370e06 100644 --- a/vendor/github.com/onsi/ginkgo/v2/reporters/default_reporter.go +++ b/vendor/github.com/onsi/ginkgo/v2/reporters/default_reporter.go @@ -419,7 +419,11 @@ func (r *DefaultReporter) emitFailure(indent uint, state types.SpecState, failur highlightColor := r.highlightColorForState(state) r.emitBlock(r.fi(indent, highlightColor+"[%s] %s{{/}}", r.humanReadableState(state), failure.Message)) if r.conf.GithubOutput { - r.emitBlock(r.fi(indent, "::error file=%s,line=%d::%s %s", failure.Location.FileName, failure.Location.LineNumber, failure.FailureNodeType, failure.TimelineLocation.Time.Format(types.GINKGO_TIME_FORMAT))) + level := "error" + if state.Is(types.SpecStateSkipped) { + level = "notice" + } + r.emitBlock(r.fi(indent, "::%s file=%s,line=%d::%s %s", level, failure.Location.FileName, failure.Location.LineNumber, failure.FailureNodeType, failure.TimelineLocation.Time.Format(types.GINKGO_TIME_FORMAT))) } else { r.emitBlock(r.fi(indent, highlightColor+"In {{bold}}[%s]{{/}}"+highlightColor+" at: {{bold}}%s{{/}} {{gray}}@ %s{{/}}\n", failure.FailureNodeType, failure.Location, failure.TimelineLocation.Time.Format(types.GINKGO_TIME_FORMAT))) } diff --git a/vendor/github.com/onsi/ginkgo/v2/reporters/junit_report.go b/vendor/github.com/onsi/ginkgo/v2/reporters/junit_report.go index 43244a9bd519..2a3215b5138f 100644 --- a/vendor/github.com/onsi/ginkgo/v2/reporters/junit_report.go +++ b/vendor/github.com/onsi/ginkgo/v2/reporters/junit_report.go @@ -324,6 +324,7 @@ func MergeAndCleanupJUnitReports(sources []string, dst string) ([]string, error) continue } err = xml.NewDecoder(f).Decode(&report) + _ = f.Close() if err != nil { messages = append(messages, fmt.Sprintf("Could not decode %s:\n%s", source, err.Error())) continue diff --git a/vendor/github.com/onsi/ginkgo/v2/types/version.go b/vendor/github.com/onsi/ginkgo/v2/types/version.go index 851d42b456b8..5dd0140cd34c 100644 --- a/vendor/github.com/onsi/ginkgo/v2/types/version.go +++ b/vendor/github.com/onsi/ginkgo/v2/types/version.go @@ -1,3 +1,3 @@ package types -const VERSION = "2.17.1" +const VERSION = "2.17.2" diff --git a/vendor/github.com/onsi/gomega/CHANGELOG.md b/vendor/github.com/onsi/gomega/CHANGELOG.md index 01ec5245cdc6..62af14ad2f2a 100644 --- a/vendor/github.com/onsi/gomega/CHANGELOG.md +++ b/vendor/github.com/onsi/gomega/CHANGELOG.md @@ -1,3 +1,22 @@ +## 1.33.1 + +### Fixes +- fix confusing eventually docs [3a66379] + +### Maintenance +- Bump github.com/onsi/ginkgo/v2 from 2.17.1 to 2.17.2 [e9bc35a] + +## 1.33.0 + +### Features + +`Receive` not accepts `Receive(, MATCHER>)`, allowing you to pick out a specific value on the channel that satisfies the provided matcher and is stored in the provided pointer. + +### Maintenance +- Bump github.com/onsi/ginkgo/v2 from 2.15.0 to 2.17.1 (#745) [9999deb] +- Bump github-pages from 229 to 230 in /docs (#735) [cb5ff21] +- Bump golang.org/x/net from 0.20.0 to 0.23.0 (#746) [bac6596] + ## 1.32.0 ### Maintenance diff --git a/vendor/github.com/onsi/gomega/gomega_dsl.go b/vendor/github.com/onsi/gomega/gomega_dsl.go index ffb81b1feb39..9697d5134ff4 100644 --- a/vendor/github.com/onsi/gomega/gomega_dsl.go +++ b/vendor/github.com/onsi/gomega/gomega_dsl.go @@ -22,7 +22,7 @@ import ( "github.com/onsi/gomega/types" ) -const GOMEGA_VERSION = "1.32.0" +const GOMEGA_VERSION = "1.33.1" const nilGomegaPanic = `You are trying to make an assertion, but haven't registered Gomega's fail handler. If you're using Ginkgo then you probably forgot to put your assertion in an It(). @@ -372,11 +372,11 @@ You can ensure that you get a number of consecutive successful tries before succ Finally, in addition to passing timeouts and a context to Eventually you can be more explicit with Eventually's chaining configuration methods: - Eventually(..., "1s", "2s", ctx).Should(...) + Eventually(..., "10s", "2s", ctx).Should(...) is equivalent to - Eventually(...).WithTimeout(time.Second).WithPolling(2*time.Second).WithContext(ctx).Should(...) + Eventually(...).WithTimeout(10*time.Second).WithPolling(2*time.Second).WithContext(ctx).Should(...) */ func Eventually(actualOrCtx interface{}, args ...interface{}) AsyncAssertion { ensureDefaultGomegaIsConfigured() diff --git a/vendor/github.com/onsi/gomega/matchers.go b/vendor/github.com/onsi/gomega/matchers.go index 8860d677fc8f..7ef27dc9c955 100644 --- a/vendor/github.com/onsi/gomega/matchers.go +++ b/vendor/github.com/onsi/gomega/matchers.go @@ -194,20 +194,21 @@ func BeClosed() types.GomegaMatcher { // // will repeatedly attempt to pull values out of `c` until a value matching "bar" is received. // -// Finally, if you want to have a reference to the value *sent* to the channel you can pass the `Receive` matcher a pointer to a variable of the appropriate type: +// Furthermore, if you want to have a reference to the value *sent* to the channel you can pass the `Receive` matcher a pointer to a variable of the appropriate type: // // var myThing thing // Eventually(thingChan).Should(Receive(&myThing)) // Expect(myThing.Sprocket).Should(Equal("foo")) // Expect(myThing.IsValid()).Should(BeTrue()) +// +// Finally, if you want to match the received object as well as get the actual received value into a variable, so you can reason further about the value received, +// you can pass a pointer to a variable of the approriate type first, and second a matcher: +// +// var myThing thing +// Eventually(thingChan).Should(Receive(&myThing, ContainSubstring("bar"))) func Receive(args ...interface{}) types.GomegaMatcher { - var arg interface{} - if len(args) > 0 { - arg = args[0] - } - return &matchers.ReceiveMatcher{ - Arg: arg, + Args: args, } } diff --git a/vendor/github.com/onsi/gomega/matchers/receive_matcher.go b/vendor/github.com/onsi/gomega/matchers/receive_matcher.go index 1936a2ba52f2..948164eaf88b 100644 --- a/vendor/github.com/onsi/gomega/matchers/receive_matcher.go +++ b/vendor/github.com/onsi/gomega/matchers/receive_matcher.go @@ -3,6 +3,7 @@ package matchers import ( + "errors" "fmt" "reflect" @@ -10,7 +11,7 @@ import ( ) type ReceiveMatcher struct { - Arg interface{} + Args []interface{} receivedValue reflect.Value channelClosed bool } @@ -29,15 +30,38 @@ func (matcher *ReceiveMatcher) Match(actual interface{}) (success bool, err erro var subMatcher omegaMatcher var hasSubMatcher bool - - if matcher.Arg != nil { - subMatcher, hasSubMatcher = (matcher.Arg).(omegaMatcher) + var resultReference interface{} + + // Valid arg formats are as follows, always with optional POINTER before + // optional MATCHER: + // - Receive() + // - Receive(POINTER) + // - Receive(MATCHER) + // - Receive(POINTER, MATCHER) + args := matcher.Args + if len(args) > 0 { + arg := args[0] + _, isSubMatcher := arg.(omegaMatcher) + if !isSubMatcher && reflect.ValueOf(arg).Kind() == reflect.Ptr { + // Consume optional POINTER arg first, if it ain't no matcher ;) + resultReference = arg + args = args[1:] + } + } + if len(args) > 0 { + arg := args[0] + subMatcher, hasSubMatcher = arg.(omegaMatcher) if !hasSubMatcher { - argType := reflect.TypeOf(matcher.Arg) - if argType.Kind() != reflect.Ptr { - return false, fmt.Errorf("Cannot assign a value from the channel:\n%s\nTo:\n%s\nYou need to pass a pointer!", format.Object(actual, 1), format.Object(matcher.Arg, 1)) - } + // At this point we assume the dev user wanted to assign a received + // value, so [POINTER,]MATCHER. + return false, fmt.Errorf("Cannot assign a value from the channel:\n%s\nTo:\n%s\nYou need to pass a pointer!", format.Object(actual, 1), format.Object(arg, 1)) } + // Consume optional MATCHER arg. + args = args[1:] + } + if len(args) > 0 { + // If there are still args present, reject all. + return false, errors.New("Receive matcher expects at most an optional pointer and/or an optional matcher") } winnerIndex, value, open := reflect.Select([]reflect.SelectCase{ @@ -58,16 +82,20 @@ func (matcher *ReceiveMatcher) Match(actual interface{}) (success bool, err erro } if hasSubMatcher { - if didReceive { - matcher.receivedValue = value - return subMatcher.Match(matcher.receivedValue.Interface()) + if !didReceive { + return false, nil } - return false, nil + matcher.receivedValue = value + if match, err := subMatcher.Match(matcher.receivedValue.Interface()); err != nil || !match { + return match, err + } + // if we received a match, then fall through in order to handle an + // optional assignment of the received value to the specified reference. } if didReceive { - if matcher.Arg != nil { - outValue := reflect.ValueOf(matcher.Arg) + if resultReference != nil { + outValue := reflect.ValueOf(resultReference) if value.Type().AssignableTo(outValue.Elem().Type()) { outValue.Elem().Set(value) @@ -77,7 +105,7 @@ func (matcher *ReceiveMatcher) Match(actual interface{}) (success bool, err erro outValue.Elem().Set(value.Elem()) return true, nil } else { - return false, fmt.Errorf("Cannot assign a value from the channel:\n%s\nType:\n%s\nTo:\n%s", format.Object(actual, 1), format.Object(value.Interface(), 1), format.Object(matcher.Arg, 1)) + return false, fmt.Errorf("Cannot assign a value from the channel:\n%s\nType:\n%s\nTo:\n%s", format.Object(actual, 1), format.Object(value.Interface(), 1), format.Object(resultReference, 1)) } } @@ -88,7 +116,11 @@ func (matcher *ReceiveMatcher) Match(actual interface{}) (success bool, err erro } func (matcher *ReceiveMatcher) FailureMessage(actual interface{}) (message string) { - subMatcher, hasSubMatcher := (matcher.Arg).(omegaMatcher) + var matcherArg interface{} + if len(matcher.Args) > 0 { + matcherArg = matcher.Args[len(matcher.Args)-1] + } + subMatcher, hasSubMatcher := (matcherArg).(omegaMatcher) closedAddendum := "" if matcher.channelClosed { @@ -105,7 +137,11 @@ func (matcher *ReceiveMatcher) FailureMessage(actual interface{}) (message strin } func (matcher *ReceiveMatcher) NegatedFailureMessage(actual interface{}) (message string) { - subMatcher, hasSubMatcher := (matcher.Arg).(omegaMatcher) + var matcherArg interface{} + if len(matcher.Args) > 0 { + matcherArg = matcher.Args[len(matcher.Args)-1] + } + subMatcher, hasSubMatcher := (matcherArg).(omegaMatcher) closedAddendum := "" if matcher.channelClosed { diff --git a/vendor/github.com/pelletier/go-toml/README.md b/vendor/github.com/pelletier/go-toml/README.md index 6c061712bb10..7399e04bf654 100644 --- a/vendor/github.com/pelletier/go-toml/README.md +++ b/vendor/github.com/pelletier/go-toml/README.md @@ -25,9 +25,9 @@ and [much faster][v2-bench]. If you only need reading and writing TOML documents (majority of cases), those features are implemented and the API unlikely to change. -The remaining features (Document structure editing and tooling) will be added -shortly. While pull-requests are welcome on v1, no active development is -expected on it. When v2.0.0 is released, v1 will be deprecated. +The remaining features will be added shortly. While pull-requests are welcome on +v1, no active development is expected on it. When v2.0.0 is released, v1 will be +deprecated. 👉 [go-toml v2][v2] diff --git a/vendor/github.com/pelletier/go-toml/SECURITY.md b/vendor/github.com/pelletier/go-toml/SECURITY.md new file mode 100644 index 000000000000..b2f21cfc92c9 --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/SECURITY.md @@ -0,0 +1,19 @@ +# Security Policy + +## Supported Versions + +Use this section to tell people about which versions of your project are +currently being supported with security updates. + +| Version | Supported | +| ---------- | ------------------ | +| Latest 2.x | :white_check_mark: | +| All 1.x | :x: | +| All 0.x | :x: | + +## Reporting a Vulnerability + +Email a vulnerability report to `security@pelletier.codes`. Make sure to include +as many details as possible to reproduce the vulnerability. This is a +side-project: I will try to get back to you as quickly as possible, time +permitting in my personal life. Providing a working patch helps very much! diff --git a/vendor/github.com/pelletier/go-toml/marshal.go b/vendor/github.com/pelletier/go-toml/marshal.go index 3443c35452ad..571273049848 100644 --- a/vendor/github.com/pelletier/go-toml/marshal.go +++ b/vendor/github.com/pelletier/go-toml/marshal.go @@ -1113,7 +1113,7 @@ func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}, mval1 *ref return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String()) } - if val.Convert(reflect.TypeOf(int(1))).Int() < 0 { + if val.Type().Kind() != reflect.Uint64 && val.Convert(reflect.TypeOf(int(1))).Int() < 0 { return reflect.ValueOf(nil), fmt.Errorf("%v(%T) is negative so does not fit in %v", tval, tval, mtype.String()) } if reflect.Indirect(reflect.New(mtype)).OverflowUint(val.Convert(reflect.TypeOf(uint64(0))).Uint()) { diff --git a/vendor/github.com/pelletier/go-toml/parser.go b/vendor/github.com/pelletier/go-toml/parser.go index f5e1a44fb4d5..b3726d0dd8cc 100644 --- a/vendor/github.com/pelletier/go-toml/parser.go +++ b/vendor/github.com/pelletier/go-toml/parser.go @@ -293,42 +293,41 @@ func (p *tomlParser) parseRvalue() interface{} { return math.NaN() case tokenInteger: cleanedVal := cleanupNumberToken(tok.val) - var err error - var val int64 + base := 10 + s := cleanedVal + checkInvalidUnderscore := numberContainsInvalidUnderscore if len(cleanedVal) >= 3 && cleanedVal[0] == '0' { switch cleanedVal[1] { case 'x': - err = hexNumberContainsInvalidUnderscore(tok.val) - if err != nil { - p.raiseError(tok, "%s", err) - } - val, err = strconv.ParseInt(cleanedVal[2:], 16, 64) + checkInvalidUnderscore = hexNumberContainsInvalidUnderscore + base = 16 case 'o': - err = numberContainsInvalidUnderscore(tok.val) - if err != nil { - p.raiseError(tok, "%s", err) - } - val, err = strconv.ParseInt(cleanedVal[2:], 8, 64) + base = 8 case 'b': - err = numberContainsInvalidUnderscore(tok.val) - if err != nil { - p.raiseError(tok, "%s", err) - } - val, err = strconv.ParseInt(cleanedVal[2:], 2, 64) + base = 2 default: panic("invalid base") // the lexer should catch this first } - } else { - err = numberContainsInvalidUnderscore(tok.val) - if err != nil { - p.raiseError(tok, "%s", err) - } - val, err = strconv.ParseInt(cleanedVal, 10, 64) + s = cleanedVal[2:] } + + err := checkInvalidUnderscore(tok.val) if err != nil { p.raiseError(tok, "%s", err) } - return val + + var val interface{} + val, err = strconv.ParseInt(s, base, 64) + if err == nil { + return val + } + + if s[0] != '-' { + if val, err = strconv.ParseUint(s, base, 64); err == nil { + return val + } + } + p.raiseError(tok, "%s", err) case tokenFloat: err := numberContainsInvalidUnderscore(tok.val) if err != nil { diff --git a/vendor/github.com/pelletier/go-toml/toml.go b/vendor/github.com/pelletier/go-toml/toml.go index 6d82587c4882..5541b941f8b8 100644 --- a/vendor/github.com/pelletier/go-toml/toml.go +++ b/vendor/github.com/pelletier/go-toml/toml.go @@ -471,7 +471,7 @@ func LoadBytes(b []byte) (tree *Tree, err error) { if _, ok := r.(runtime.Error); ok { panic(r) } - err = errors.New(r.(string)) + err = fmt.Errorf("%s", r) } }() diff --git a/vendor/golang.org/x/mod/modfile/read.go b/vendor/golang.org/x/mod/modfile/read.go index 5b5bb5e115b3..220568259158 100644 --- a/vendor/golang.org/x/mod/modfile/read.go +++ b/vendor/golang.org/x/mod/modfile/read.go @@ -225,7 +225,7 @@ func (x *FileSyntax) Cleanup() { if ww == 0 { continue } - if ww == 1 { + if ww == 1 && len(stmt.RParen.Comments.Before) == 0 { // Collapse block into single line. line := &Line{ Comments: Comments{ diff --git a/vendor/golang.org/x/mod/modfile/rule.go b/vendor/golang.org/x/mod/modfile/rule.go index 35fd1f534cf8..0e7b7e26792b 100644 --- a/vendor/golang.org/x/mod/modfile/rule.go +++ b/vendor/golang.org/x/mod/modfile/rule.go @@ -308,6 +308,7 @@ var laxGoVersionRE = lazyregexp.New(`^v?(([1-9][0-9]*)\.(0|[1-9][0-9]*))([^0-9]. // Toolchains must be named beginning with `go1`, // like "go1.20.3" or "go1.20.3-gccgo". As a special case, "default" is also permitted. +// TODO(samthanawalla): Replace regex with https://pkg.go.dev/go/version#IsValid in 1.23+ var ToolchainRE = lazyregexp.New(`^default$|^go1($|\.)`) func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, args []string, fix VersionFixer, strict bool) { @@ -384,7 +385,7 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a errorf("toolchain directive expects exactly one argument") return } else if strict && !ToolchainRE.MatchString(args[0]) { - errorf("invalid toolchain version '%s': must match format go1.23.0 or local", args[0]) + errorf("invalid toolchain version '%s': must match format go1.23.0 or default", args[0]) return } f.Toolchain = &Toolchain{Syntax: line} @@ -630,7 +631,7 @@ func (f *WorkFile) add(errs *ErrorList, line *Line, verb string, args []string, errorf("go directive expects exactly one argument") return } else if !GoVersionRE.MatchString(args[0]) { - errorf("invalid go version '%s': must match format 1.23", args[0]) + errorf("invalid go version '%s': must match format 1.23.0", args[0]) return } @@ -646,7 +647,7 @@ func (f *WorkFile) add(errs *ErrorList, line *Line, verb string, args []string, errorf("toolchain directive expects exactly one argument") return } else if !ToolchainRE.MatchString(args[0]) { - errorf("invalid toolchain version '%s': must match format go1.23 or local", args[0]) + errorf("invalid toolchain version '%s': must match format go1.23.0 or default", args[0]) return } @@ -974,6 +975,8 @@ func (f *File) AddGoStmt(version string) error { var hint Expr if f.Module != nil && f.Module.Syntax != nil { hint = f.Module.Syntax + } else if f.Syntax == nil { + f.Syntax = new(FileSyntax) } f.Go = &Go{ Version: version, diff --git a/vendor/golang.org/x/sys/unix/mmap_nomremap.go b/vendor/golang.org/x/sys/unix/mmap_nomremap.go index 4b68e59780a2..7f602ffd26d4 100644 --- a/vendor/golang.org/x/sys/unix/mmap_nomremap.go +++ b/vendor/golang.org/x/sys/unix/mmap_nomremap.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build aix || darwin || dragonfly || freebsd || openbsd || solaris +//go:build aix || darwin || dragonfly || freebsd || openbsd || solaris || zos package unix diff --git a/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go b/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go index b473038c6155..27c41b6f0a13 100644 --- a/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go +++ b/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go @@ -1520,6 +1520,14 @@ func (m *mmapper) Munmap(data []byte) (err error) { return nil } +func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) { + return mapper.Mmap(fd, offset, length, prot, flags) +} + +func Munmap(b []byte) (err error) { + return mapper.Munmap(b) +} + func Read(fd int, p []byte) (n int, err error) { n, err = read(fd, p) if raceenabled { diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go index 6395a031d45d..6525c62f3c2f 100644 --- a/vendor/golang.org/x/sys/windows/syscall_windows.go +++ b/vendor/golang.org/x/sys/windows/syscall_windows.go @@ -165,6 +165,7 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile Handle) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW //sys CreateNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *SecurityAttributes) (handle Handle, err error) [failretval==InvalidHandle] = CreateNamedPipeW //sys ConnectNamedPipe(pipe Handle, overlapped *Overlapped) (err error) +//sys DisconnectNamedPipe(pipe Handle) (err error) //sys GetNamedPipeInfo(pipe Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) //sys GetNamedPipeHandleState(pipe Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW //sys SetNamedPipeHandleState(pipe Handle, state *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32) (err error) = SetNamedPipeHandleState @@ -348,8 +349,19 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys SetProcessPriorityBoost(process Handle, disable bool) (err error) = kernel32.SetProcessPriorityBoost //sys GetProcessWorkingSetSizeEx(hProcess Handle, lpMinimumWorkingSetSize *uintptr, lpMaximumWorkingSetSize *uintptr, flags *uint32) //sys SetProcessWorkingSetSizeEx(hProcess Handle, dwMinimumWorkingSetSize uintptr, dwMaximumWorkingSetSize uintptr, flags uint32) (err error) +//sys ClearCommBreak(handle Handle) (err error) +//sys ClearCommError(handle Handle, lpErrors *uint32, lpStat *ComStat) (err error) +//sys EscapeCommFunction(handle Handle, dwFunc uint32) (err error) +//sys GetCommState(handle Handle, lpDCB *DCB) (err error) +//sys GetCommModemStatus(handle Handle, lpModemStat *uint32) (err error) //sys GetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) +//sys PurgeComm(handle Handle, dwFlags uint32) (err error) +//sys SetCommBreak(handle Handle) (err error) +//sys SetCommMask(handle Handle, dwEvtMask uint32) (err error) +//sys SetCommState(handle Handle, lpDCB *DCB) (err error) //sys SetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) +//sys SetupComm(handle Handle, dwInQueue uint32, dwOutQueue uint32) (err error) +//sys WaitCommEvent(handle Handle, lpEvtMask *uint32, lpOverlapped *Overlapped) (err error) //sys GetActiveProcessorCount(groupNumber uint16) (ret uint32) //sys GetMaximumProcessorCount(groupNumber uint16) (ret uint32) //sys EnumWindows(enumFunc uintptr, param unsafe.Pointer) (err error) = user32.EnumWindows @@ -1834,3 +1846,73 @@ func ResizePseudoConsole(pconsole Handle, size Coord) error { // accept arguments that can be casted to uintptr, and Coord can't. return resizePseudoConsole(pconsole, *((*uint32)(unsafe.Pointer(&size)))) } + +// DCB constants. See https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-dcb. +const ( + CBR_110 = 110 + CBR_300 = 300 + CBR_600 = 600 + CBR_1200 = 1200 + CBR_2400 = 2400 + CBR_4800 = 4800 + CBR_9600 = 9600 + CBR_14400 = 14400 + CBR_19200 = 19200 + CBR_38400 = 38400 + CBR_57600 = 57600 + CBR_115200 = 115200 + CBR_128000 = 128000 + CBR_256000 = 256000 + + DTR_CONTROL_DISABLE = 0x00000000 + DTR_CONTROL_ENABLE = 0x00000010 + DTR_CONTROL_HANDSHAKE = 0x00000020 + + RTS_CONTROL_DISABLE = 0x00000000 + RTS_CONTROL_ENABLE = 0x00001000 + RTS_CONTROL_HANDSHAKE = 0x00002000 + RTS_CONTROL_TOGGLE = 0x00003000 + + NOPARITY = 0 + ODDPARITY = 1 + EVENPARITY = 2 + MARKPARITY = 3 + SPACEPARITY = 4 + + ONESTOPBIT = 0 + ONE5STOPBITS = 1 + TWOSTOPBITS = 2 +) + +// EscapeCommFunction constants. See https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-escapecommfunction. +const ( + SETXOFF = 1 + SETXON = 2 + SETRTS = 3 + CLRRTS = 4 + SETDTR = 5 + CLRDTR = 6 + SETBREAK = 8 + CLRBREAK = 9 +) + +// PurgeComm constants. See https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-purgecomm. +const ( + PURGE_TXABORT = 0x0001 + PURGE_RXABORT = 0x0002 + PURGE_TXCLEAR = 0x0004 + PURGE_RXCLEAR = 0x0008 +) + +// SetCommMask constants. See https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setcommmask. +const ( + EV_RXCHAR = 0x0001 + EV_RXFLAG = 0x0002 + EV_TXEMPTY = 0x0004 + EV_CTS = 0x0008 + EV_DSR = 0x0010 + EV_RLSD = 0x0020 + EV_BREAK = 0x0040 + EV_ERR = 0x0080 + EV_RING = 0x0100 +) diff --git a/vendor/golang.org/x/sys/windows/types_windows.go b/vendor/golang.org/x/sys/windows/types_windows.go index 359780f6ace5..d8cb71db0a61 100644 --- a/vendor/golang.org/x/sys/windows/types_windows.go +++ b/vendor/golang.org/x/sys/windows/types_windows.go @@ -3380,3 +3380,27 @@ type BLOB struct { Size uint32 BlobData *byte } + +type ComStat struct { + Flags uint32 + CBInQue uint32 + CBOutQue uint32 +} + +type DCB struct { + DCBlength uint32 + BaudRate uint32 + Flags uint32 + wReserved uint16 + XonLim uint16 + XoffLim uint16 + ByteSize uint8 + Parity uint8 + StopBits uint8 + XonChar byte + XoffChar byte + ErrorChar byte + EofChar byte + EvtChar byte + wReserved1 uint16 +} diff --git a/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/vendor/golang.org/x/sys/windows/zsyscall_windows.go index e8791c82c30f..5c6035ddfa92 100644 --- a/vendor/golang.org/x/sys/windows/zsyscall_windows.go +++ b/vendor/golang.org/x/sys/windows/zsyscall_windows.go @@ -188,6 +188,8 @@ var ( procAssignProcessToJobObject = modkernel32.NewProc("AssignProcessToJobObject") procCancelIo = modkernel32.NewProc("CancelIo") procCancelIoEx = modkernel32.NewProc("CancelIoEx") + procClearCommBreak = modkernel32.NewProc("ClearCommBreak") + procClearCommError = modkernel32.NewProc("ClearCommError") procCloseHandle = modkernel32.NewProc("CloseHandle") procClosePseudoConsole = modkernel32.NewProc("ClosePseudoConsole") procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe") @@ -212,7 +214,9 @@ var ( procDeleteProcThreadAttributeList = modkernel32.NewProc("DeleteProcThreadAttributeList") procDeleteVolumeMountPointW = modkernel32.NewProc("DeleteVolumeMountPointW") procDeviceIoControl = modkernel32.NewProc("DeviceIoControl") + procDisconnectNamedPipe = modkernel32.NewProc("DisconnectNamedPipe") procDuplicateHandle = modkernel32.NewProc("DuplicateHandle") + procEscapeCommFunction = modkernel32.NewProc("EscapeCommFunction") procExitProcess = modkernel32.NewProc("ExitProcess") procExpandEnvironmentStringsW = modkernel32.NewProc("ExpandEnvironmentStringsW") procFindClose = modkernel32.NewProc("FindClose") @@ -236,6 +240,8 @@ var ( procGenerateConsoleCtrlEvent = modkernel32.NewProc("GenerateConsoleCtrlEvent") procGetACP = modkernel32.NewProc("GetACP") procGetActiveProcessorCount = modkernel32.NewProc("GetActiveProcessorCount") + procGetCommModemStatus = modkernel32.NewProc("GetCommModemStatus") + procGetCommState = modkernel32.NewProc("GetCommState") procGetCommTimeouts = modkernel32.NewProc("GetCommTimeouts") procGetCommandLineW = modkernel32.NewProc("GetCommandLineW") procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW") @@ -322,6 +328,7 @@ var ( procProcess32NextW = modkernel32.NewProc("Process32NextW") procProcessIdToSessionId = modkernel32.NewProc("ProcessIdToSessionId") procPulseEvent = modkernel32.NewProc("PulseEvent") + procPurgeComm = modkernel32.NewProc("PurgeComm") procQueryDosDeviceW = modkernel32.NewProc("QueryDosDeviceW") procQueryFullProcessImageNameW = modkernel32.NewProc("QueryFullProcessImageNameW") procQueryInformationJobObject = modkernel32.NewProc("QueryInformationJobObject") @@ -335,6 +342,9 @@ var ( procResetEvent = modkernel32.NewProc("ResetEvent") procResizePseudoConsole = modkernel32.NewProc("ResizePseudoConsole") procResumeThread = modkernel32.NewProc("ResumeThread") + procSetCommBreak = modkernel32.NewProc("SetCommBreak") + procSetCommMask = modkernel32.NewProc("SetCommMask") + procSetCommState = modkernel32.NewProc("SetCommState") procSetCommTimeouts = modkernel32.NewProc("SetCommTimeouts") procSetConsoleCursorPosition = modkernel32.NewProc("SetConsoleCursorPosition") procSetConsoleMode = modkernel32.NewProc("SetConsoleMode") @@ -342,7 +352,6 @@ var ( procSetDefaultDllDirectories = modkernel32.NewProc("SetDefaultDllDirectories") procSetDllDirectoryW = modkernel32.NewProc("SetDllDirectoryW") procSetEndOfFile = modkernel32.NewProc("SetEndOfFile") - procSetFileValidData = modkernel32.NewProc("SetFileValidData") procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW") procSetErrorMode = modkernel32.NewProc("SetErrorMode") procSetEvent = modkernel32.NewProc("SetEvent") @@ -351,6 +360,7 @@ var ( procSetFileInformationByHandle = modkernel32.NewProc("SetFileInformationByHandle") procSetFilePointer = modkernel32.NewProc("SetFilePointer") procSetFileTime = modkernel32.NewProc("SetFileTime") + procSetFileValidData = modkernel32.NewProc("SetFileValidData") procSetHandleInformation = modkernel32.NewProc("SetHandleInformation") procSetInformationJobObject = modkernel32.NewProc("SetInformationJobObject") procSetNamedPipeHandleState = modkernel32.NewProc("SetNamedPipeHandleState") @@ -361,6 +371,7 @@ var ( procSetStdHandle = modkernel32.NewProc("SetStdHandle") procSetVolumeLabelW = modkernel32.NewProc("SetVolumeLabelW") procSetVolumeMountPointW = modkernel32.NewProc("SetVolumeMountPointW") + procSetupComm = modkernel32.NewProc("SetupComm") procSizeofResource = modkernel32.NewProc("SizeofResource") procSleepEx = modkernel32.NewProc("SleepEx") procTerminateJobObject = modkernel32.NewProc("TerminateJobObject") @@ -379,6 +390,7 @@ var ( procVirtualQueryEx = modkernel32.NewProc("VirtualQueryEx") procVirtualUnlock = modkernel32.NewProc("VirtualUnlock") procWTSGetActiveConsoleSessionId = modkernel32.NewProc("WTSGetActiveConsoleSessionId") + procWaitCommEvent = modkernel32.NewProc("WaitCommEvent") procWaitForMultipleObjects = modkernel32.NewProc("WaitForMultipleObjects") procWaitForSingleObject = modkernel32.NewProc("WaitForSingleObject") procWriteConsoleW = modkernel32.NewProc("WriteConsoleW") @@ -1641,6 +1653,22 @@ func CancelIoEx(s Handle, o *Overlapped) (err error) { return } +func ClearCommBreak(handle Handle) (err error) { + r1, _, e1 := syscall.Syscall(procClearCommBreak.Addr(), 1, uintptr(handle), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func ClearCommError(handle Handle, lpErrors *uint32, lpStat *ComStat) (err error) { + r1, _, e1 := syscall.Syscall(procClearCommError.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(lpErrors)), uintptr(unsafe.Pointer(lpStat))) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func CloseHandle(handle Handle) (err error) { r1, _, e1 := syscall.Syscall(procCloseHandle.Addr(), 1, uintptr(handle), 0, 0) if r1 == 0 { @@ -1845,6 +1873,14 @@ func DeviceIoControl(handle Handle, ioControlCode uint32, inBuffer *byte, inBuff return } +func DisconnectNamedPipe(pipe Handle) (err error) { + r1, _, e1 := syscall.Syscall(procDisconnectNamedPipe.Addr(), 1, uintptr(pipe), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error) { var _p0 uint32 if bInheritHandle { @@ -1857,6 +1893,14 @@ func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetP return } +func EscapeCommFunction(handle Handle, dwFunc uint32) (err error) { + r1, _, e1 := syscall.Syscall(procEscapeCommFunction.Addr(), 2, uintptr(handle), uintptr(dwFunc), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func ExitProcess(exitcode uint32) { syscall.Syscall(procExitProcess.Addr(), 1, uintptr(exitcode), 0, 0) return @@ -2058,6 +2102,22 @@ func GetActiveProcessorCount(groupNumber uint16) (ret uint32) { return } +func GetCommModemStatus(handle Handle, lpModemStat *uint32) (err error) { + r1, _, e1 := syscall.Syscall(procGetCommModemStatus.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(lpModemStat)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func GetCommState(handle Handle, lpDCB *DCB) (err error) { + r1, _, e1 := syscall.Syscall(procGetCommState.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(lpDCB)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func GetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) { r1, _, e1 := syscall.Syscall(procGetCommTimeouts.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(timeouts)), 0) if r1 == 0 { @@ -2810,6 +2870,14 @@ func PulseEvent(event Handle) (err error) { return } +func PurgeComm(handle Handle, dwFlags uint32) (err error) { + r1, _, e1 := syscall.Syscall(procPurgeComm.Addr(), 2, uintptr(handle), uintptr(dwFlags), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func QueryDosDevice(deviceName *uint16, targetPath *uint16, max uint32) (n uint32, err error) { r0, _, e1 := syscall.Syscall(procQueryDosDeviceW.Addr(), 3, uintptr(unsafe.Pointer(deviceName)), uintptr(unsafe.Pointer(targetPath)), uintptr(max)) n = uint32(r0) @@ -2924,6 +2992,30 @@ func ResumeThread(thread Handle) (ret uint32, err error) { return } +func SetCommBreak(handle Handle) (err error) { + r1, _, e1 := syscall.Syscall(procSetCommBreak.Addr(), 1, uintptr(handle), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func SetCommMask(handle Handle, dwEvtMask uint32) (err error) { + r1, _, e1 := syscall.Syscall(procSetCommMask.Addr(), 2, uintptr(handle), uintptr(dwEvtMask), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func SetCommState(handle Handle, lpDCB *DCB) (err error) { + r1, _, e1 := syscall.Syscall(procSetCommState.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(lpDCB)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func SetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) { r1, _, e1 := syscall.Syscall(procSetCommTimeouts.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(timeouts)), 0) if r1 == 0 { @@ -2989,14 +3081,6 @@ func SetEndOfFile(handle Handle) (err error) { return } -func SetFileValidData(handle Handle, validDataLength int64) (err error) { - r1, _, e1 := syscall.Syscall(procSetFileValidData.Addr(), 2, uintptr(handle), uintptr(validDataLength), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - func SetEnvironmentVariable(name *uint16, value *uint16) (err error) { r1, _, e1 := syscall.Syscall(procSetEnvironmentVariableW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0) if r1 == 0 { @@ -3060,6 +3144,14 @@ func SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetim return } +func SetFileValidData(handle Handle, validDataLength int64) (err error) { + r1, _, e1 := syscall.Syscall(procSetFileValidData.Addr(), 2, uintptr(handle), uintptr(validDataLength), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error) { r1, _, e1 := syscall.Syscall(procSetHandleInformation.Addr(), 3, uintptr(handle), uintptr(mask), uintptr(flags)) if r1 == 0 { @@ -3145,6 +3237,14 @@ func SetVolumeMountPoint(volumeMountPoint *uint16, volumeName *uint16) (err erro return } +func SetupComm(handle Handle, dwInQueue uint32, dwOutQueue uint32) (err error) { + r1, _, e1 := syscall.Syscall(procSetupComm.Addr(), 3, uintptr(handle), uintptr(dwInQueue), uintptr(dwOutQueue)) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func SizeofResource(module Handle, resInfo Handle) (size uint32, err error) { r0, _, e1 := syscall.Syscall(procSizeofResource.Addr(), 2, uintptr(module), uintptr(resInfo), 0) size = uint32(r0) @@ -3291,6 +3391,14 @@ func WTSGetActiveConsoleSessionId() (sessionID uint32) { return } +func WaitCommEvent(handle Handle, lpEvtMask *uint32, lpOverlapped *Overlapped) (err error) { + r1, _, e1 := syscall.Syscall(procWaitCommEvent.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(lpEvtMask)), uintptr(unsafe.Pointer(lpOverlapped))) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func waitForMultipleObjects(count uint32, handles uintptr, waitAll bool, waitMilliseconds uint32) (event uint32, err error) { var _p0 uint32 if waitAll { diff --git a/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go b/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go index 03543bd4bb8f..137cc8df1d86 100644 --- a/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go +++ b/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go @@ -47,7 +47,7 @@ import ( func Find(importPath, srcDir string) (filename, path string) { cmd := exec.Command("go", "list", "-json", "-export", "--", importPath) cmd.Dir = srcDir - out, err := cmd.CombinedOutput() + out, err := cmd.Output() if err != nil { return "", "" } diff --git a/vendor/golang.org/x/tools/go/packages/packages.go b/vendor/golang.org/x/tools/go/packages/packages.go index f33b0afc22cf..865d90597a94 100644 --- a/vendor/golang.org/x/tools/go/packages/packages.go +++ b/vendor/golang.org/x/tools/go/packages/packages.go @@ -9,6 +9,7 @@ package packages import ( "context" "encoding/json" + "errors" "fmt" "go/ast" "go/parser" @@ -24,6 +25,8 @@ import ( "sync" "time" + "golang.org/x/sync/errgroup" + "golang.org/x/tools/go/gcexportdata" "golang.org/x/tools/internal/gocommand" "golang.org/x/tools/internal/packagesinternal" @@ -255,8 +258,27 @@ func Load(cfg *Config, patterns ...string) ([]*Package, error) { // defaultDriver will fall back to the go list driver. // The boolean result indicates that an external driver handled the request. func defaultDriver(cfg *Config, patterns ...string) (*DriverResponse, bool, error) { + const ( + // windowsArgMax specifies the maximum command line length for + // the Windows' CreateProcess function. + windowsArgMax = 32767 + // maxEnvSize is a very rough estimation of the maximum environment + // size of a user. + maxEnvSize = 16384 + // safeArgMax specifies the maximum safe command line length to use + // by the underlying driver excl. the environment. We choose the Windows' + // ARG_MAX as the starting point because it's one of the lowest ARG_MAX + // constants out of the different supported platforms, + // e.g., https://www.in-ulm.de/~mascheck/various/argmax/#results. + safeArgMax = windowsArgMax - maxEnvSize + ) + chunks, err := splitIntoChunks(patterns, safeArgMax) + if err != nil { + return nil, false, err + } + if driver := findExternalDriver(cfg); driver != nil { - response, err := driver(cfg, patterns...) + response, err := callDriverOnChunks(driver, cfg, chunks) if err != nil { return nil, false, err } else if !response.NotHandled { @@ -265,11 +287,82 @@ func defaultDriver(cfg *Config, patterns ...string) (*DriverResponse, bool, erro // (fall through) } - response, err := goListDriver(cfg, patterns...) + response, err := callDriverOnChunks(goListDriver, cfg, chunks) if err != nil { return nil, false, err } - return response, false, nil + return response, false, err +} + +// splitIntoChunks chunks the slice so that the total number of characters +// in a chunk is no longer than argMax. +func splitIntoChunks(patterns []string, argMax int) ([][]string, error) { + if argMax <= 0 { + return nil, errors.New("failed to split patterns into chunks, negative safe argMax value") + } + var chunks [][]string + charsInChunk := 0 + nextChunkStart := 0 + for i, v := range patterns { + vChars := len(v) + if vChars > argMax { + // a single pattern is longer than the maximum safe ARG_MAX, hardly should happen + return nil, errors.New("failed to split patterns into chunks, a pattern is too long") + } + charsInChunk += vChars + 1 // +1 is for a whitespace between patterns that has to be counted too + if charsInChunk > argMax { + chunks = append(chunks, patterns[nextChunkStart:i]) + nextChunkStart = i + charsInChunk = vChars + } + } + // add the last chunk + if nextChunkStart < len(patterns) { + chunks = append(chunks, patterns[nextChunkStart:]) + } + return chunks, nil +} + +func callDriverOnChunks(driver driver, cfg *Config, chunks [][]string) (*DriverResponse, error) { + if len(chunks) == 0 { + return driver(cfg) + } + responses := make([]*DriverResponse, len(chunks)) + errNotHandled := errors.New("driver returned NotHandled") + var g errgroup.Group + for i, chunk := range chunks { + i := i + chunk := chunk + g.Go(func() (err error) { + responses[i], err = driver(cfg, chunk...) + if responses[i] != nil && responses[i].NotHandled { + err = errNotHandled + } + return err + }) + } + if err := g.Wait(); err != nil { + if errors.Is(err, errNotHandled) { + return &DriverResponse{NotHandled: true}, nil + } + return nil, err + } + return mergeResponses(responses...), nil +} + +func mergeResponses(responses ...*DriverResponse) *DriverResponse { + if len(responses) == 0 { + return nil + } + response := newDeduper() + response.dr.NotHandled = false + response.dr.Compiler = responses[0].Compiler + response.dr.Arch = responses[0].Arch + response.dr.GoVersion = responses[0].GoVersion + for _, v := range responses { + response.addAll(v) + } + return response.dr } // A Package describes a loaded Go package. @@ -1025,7 +1118,7 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) { Sizes: ld.sizes, // may be nil } if lpkg.Module != nil && lpkg.Module.GoVersion != "" { - typesinternal.SetGoVersion(tc, "go"+lpkg.Module.GoVersion) + tc.GoVersion = "go" + lpkg.Module.GoVersion } if (ld.Mode & typecheckCgo) != 0 { if !typesinternal.SetUsesCgo(tc) { @@ -1036,10 +1129,24 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) { return } } - types.NewChecker(tc, ld.Fset, lpkg.Types, lpkg.TypesInfo).Files(lpkg.Syntax) + typErr := types.NewChecker(tc, ld.Fset, lpkg.Types, lpkg.TypesInfo).Files(lpkg.Syntax) lpkg.importErrors = nil // no longer needed + // In go/types go1.21 and go1.22, Checker.Files failed fast with a + // a "too new" error, without calling tc.Error and without + // proceeding to type-check the package (#66525). + // We rely on the runtimeVersion error to give the suggested remedy. + if typErr != nil && len(lpkg.Errors) == 0 && len(lpkg.Syntax) > 0 { + if msg := typErr.Error(); strings.HasPrefix(msg, "package requires newer Go version") { + appendError(types.Error{ + Fset: ld.Fset, + Pos: lpkg.Syntax[0].Package, + Msg: msg, + }) + } + } + // If !Cgo, the type-checker uses FakeImportC mode, so // it doesn't invoke the importer for import "C", // nor report an error for the import, @@ -1061,6 +1168,12 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) { } } + // If types.Checker.Files had an error that was unreported, + // make sure to report the unknown error so the package is illTyped. + if typErr != nil && len(lpkg.Errors) == 0 { + appendError(typErr) + } + // Record accumulated errors. illTyped := len(lpkg.Errors) > 0 if !illTyped { diff --git a/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go b/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go index 11d5c8c3adf1..a2386c347a25 100644 --- a/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go +++ b/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go @@ -29,9 +29,12 @@ import ( "strconv" "strings" - "golang.org/x/tools/internal/typeparams" + "golang.org/x/tools/internal/aliases" + "golang.org/x/tools/internal/typesinternal" ) +// TODO(adonovan): think about generic aliases. + // A Path is an opaque name that identifies a types.Object // relative to its package. Conceptually, the name consists of a // sequence of destructuring operations applied to the package scope @@ -223,7 +226,7 @@ func (enc *Encoder) For(obj types.Object) (Path, error) { // Reject obviously non-viable cases. switch obj := obj.(type) { case *types.TypeName: - if _, ok := obj.Type().(*types.TypeParam); !ok { + if _, ok := aliases.Unalias(obj.Type()).(*types.TypeParam); !ok { // With the exception of type parameters, only package-level type names // have a path. return "", fmt.Errorf("no path for %v", obj) @@ -310,7 +313,7 @@ func (enc *Encoder) For(obj types.Object) (Path, error) { } // Inspect declared methods of defined types. - if T, ok := o.Type().(*types.Named); ok { + if T, ok := aliases.Unalias(o.Type()).(*types.Named); ok { path = append(path, opType) // The method index here is always with respect // to the underlying go/types data structures, @@ -391,17 +394,12 @@ func (enc *Encoder) concreteMethod(meth *types.Func) (Path, bool) { // of objectpath will only be giving us origin methods, anyway, as referring // to instantiated methods is usually not useful. - if typeparams.OriginMethod(meth) != meth { + if meth.Origin() != meth { return "", false } - recvT := meth.Type().(*types.Signature).Recv().Type() - if ptr, ok := recvT.(*types.Pointer); ok { - recvT = ptr.Elem() - } - - named, ok := recvT.(*types.Named) - if !ok { + _, named := typesinternal.ReceiverNamed(meth.Type().(*types.Signature).Recv()) + if named == nil { return "", false } @@ -444,6 +442,8 @@ func (enc *Encoder) concreteMethod(meth *types.Func) (Path, bool) { // nil, it will be allocated as necessary. func find(obj types.Object, T types.Type, path []byte, seen map[*types.TypeName]bool) []byte { switch T := T.(type) { + case *aliases.Alias: + return find(obj, aliases.Unalias(T), path, seen) case *types.Basic, *types.Named: // Named types belonging to pkg were handled already, // so T must belong to another package. No path. @@ -616,6 +616,7 @@ func Object(pkg *types.Package, p Path) (types.Object, error) { // Inv: t != nil, obj == nil + t = aliases.Unalias(t) switch code { case opElem: hasElem, ok := t.(hasElem) // Pointer, Slice, Array, Chan, Map diff --git a/vendor/golang.org/x/tools/internal/aliases/aliases.go b/vendor/golang.org/x/tools/internal/aliases/aliases.go new file mode 100644 index 000000000000..f89112c8ee57 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/aliases/aliases.go @@ -0,0 +1,28 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package aliases + +import ( + "go/token" + "go/types" +) + +// Package aliases defines backward compatible shims +// for the types.Alias type representation added in 1.22. +// This defines placeholders for x/tools until 1.26. + +// NewAlias creates a new TypeName in Package pkg that +// is an alias for the type rhs. +// +// When GoVersion>=1.22 and GODEBUG=gotypesalias=1, +// the Type() of the return value is a *types.Alias. +func NewAlias(pos token.Pos, pkg *types.Package, name string, rhs types.Type) *types.TypeName { + if enabled() { + tname := types.NewTypeName(pos, pkg, name, nil) + newAlias(tname, rhs) + return tname + } + return types.NewTypeName(pos, pkg, name, rhs) +} diff --git a/vendor/golang.org/x/tools/internal/aliases/aliases_go121.go b/vendor/golang.org/x/tools/internal/aliases/aliases_go121.go new file mode 100644 index 000000000000..1872b56ff8fc --- /dev/null +++ b/vendor/golang.org/x/tools/internal/aliases/aliases_go121.go @@ -0,0 +1,30 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !go1.22 +// +build !go1.22 + +package aliases + +import ( + "go/types" +) + +// Alias is a placeholder for a go/types.Alias for <=1.21. +// It will never be created by go/types. +type Alias struct{} + +func (*Alias) String() string { panic("unreachable") } + +func (*Alias) Underlying() types.Type { panic("unreachable") } + +func (*Alias) Obj() *types.TypeName { panic("unreachable") } + +// Unalias returns the type t for go <=1.21. +func Unalias(t types.Type) types.Type { return t } + +// Always false for go <=1.21. Ignores GODEBUG. +func enabled() bool { return false } + +func newAlias(name *types.TypeName, rhs types.Type) *Alias { panic("unreachable") } diff --git a/vendor/golang.org/x/tools/internal/aliases/aliases_go122.go b/vendor/golang.org/x/tools/internal/aliases/aliases_go122.go new file mode 100644 index 000000000000..8b92116284d0 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/aliases/aliases_go122.go @@ -0,0 +1,72 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.22 +// +build go1.22 + +package aliases + +import ( + "go/ast" + "go/parser" + "go/token" + "go/types" + "os" + "strings" + "sync" +) + +// Alias is an alias of types.Alias. +type Alias = types.Alias + +// Unalias is a wrapper of types.Unalias. +func Unalias(t types.Type) types.Type { return types.Unalias(t) } + +// newAlias is an internal alias around types.NewAlias. +// Direct usage is discouraged as the moment. +// Try to use NewAlias instead. +func newAlias(tname *types.TypeName, rhs types.Type) *Alias { + a := types.NewAlias(tname, rhs) + // TODO(go.dev/issue/65455): Remove kludgy workaround to set a.actual as a side-effect. + Unalias(a) + return a +} + +// enabled returns true when types.Aliases are enabled. +func enabled() bool { + // Use the gotypesalias value in GODEBUG if set. + godebug := os.Getenv("GODEBUG") + value := -1 // last set value. + for _, f := range strings.Split(godebug, ",") { + switch f { + case "gotypesalias=1": + value = 1 + case "gotypesalias=0": + value = 0 + } + } + switch value { + case 0: + return false + case 1: + return true + default: + return aliasesDefault() + } +} + +// aliasesDefault reports if aliases are enabled by default. +func aliasesDefault() bool { + // Dynamically check if Aliases will be produced from go/types. + aliasesDefaultOnce.Do(func() { + fset := token.NewFileSet() + f, _ := parser.ParseFile(fset, "a.go", "package p; type A = int", 0) + pkg, _ := new(types.Config).Check("p", fset, []*ast.File{f}, nil) + _, gotypesaliasDefault = pkg.Scope().Lookup("A").Type().(*types.Alias) + }) + return gotypesaliasDefault +} + +var gotypesaliasDefault bool +var aliasesDefaultOnce sync.Once diff --git a/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go b/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go index 2d078ccb19c5..39df91124a46 100644 --- a/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go +++ b/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go @@ -259,13 +259,6 @@ func Import(packages map[string]*types.Package, path, srcDir string, lookup func return } -func deref(typ types.Type) types.Type { - if p, _ := typ.(*types.Pointer); p != nil { - return p.Elem() - } - return typ -} - type byPath []*types.Package func (a byPath) Len() int { return len(a) } diff --git a/vendor/golang.org/x/tools/internal/gcimporter/iexport.go b/vendor/golang.org/x/tools/internal/gcimporter/iexport.go index 2ee8c70164f8..683bd7395a6b 100644 --- a/vendor/golang.org/x/tools/internal/gcimporter/iexport.go +++ b/vendor/golang.org/x/tools/internal/gcimporter/iexport.go @@ -21,8 +21,10 @@ import ( "sort" "strconv" "strings" + "unsafe" "golang.org/x/tools/go/types/objectpath" + "golang.org/x/tools/internal/aliases" "golang.org/x/tools/internal/tokeninternal" ) @@ -463,7 +465,7 @@ func (p *iexporter) doDecl(obj types.Object) { switch obj := obj.(type) { case *types.Var: - w.tag('V') + w.tag(varTag) w.pos(obj.Pos()) w.typ(obj.Type(), obj.Pkg()) @@ -481,9 +483,9 @@ func (p *iexporter) doDecl(obj types.Object) { // Function. if sig.TypeParams().Len() == 0 { - w.tag('F') + w.tag(funcTag) } else { - w.tag('G') + w.tag(genericFuncTag) } w.pos(obj.Pos()) // The tparam list of the function type is the declaration of the type @@ -499,20 +501,20 @@ func (p *iexporter) doDecl(obj types.Object) { w.signature(sig) case *types.Const: - w.tag('C') + w.tag(constTag) w.pos(obj.Pos()) w.value(obj.Type(), obj.Val()) case *types.TypeName: t := obj.Type() - if tparam, ok := t.(*types.TypeParam); ok { - w.tag('P') + if tparam, ok := aliases.Unalias(t).(*types.TypeParam); ok { + w.tag(typeParamTag) w.pos(obj.Pos()) constraint := tparam.Constraint() if p.version >= iexportVersionGo1_18 { implicit := false - if iface, _ := constraint.(*types.Interface); iface != nil { + if iface, _ := aliases.Unalias(constraint).(*types.Interface); iface != nil { implicit = iface.IsImplicit() } w.bool(implicit) @@ -522,8 +524,13 @@ func (p *iexporter) doDecl(obj types.Object) { } if obj.IsAlias() { - w.tag('A') + w.tag(aliasTag) w.pos(obj.Pos()) + if alias, ok := t.(*aliases.Alias); ok { + // Preserve materialized aliases, + // even of non-exported types. + t = aliasRHS(alias) + } w.typ(t, obj.Pkg()) break } @@ -535,9 +542,9 @@ func (p *iexporter) doDecl(obj types.Object) { } if named.TypeParams().Len() == 0 { - w.tag('T') + w.tag(typeTag) } else { - w.tag('U') + w.tag(genericTypeTag) } w.pos(obj.Pos()) @@ -547,7 +554,7 @@ func (p *iexporter) doDecl(obj types.Object) { w.tparamList(obj.Name(), named.TypeParams(), obj.Pkg()) } - underlying := obj.Type().Underlying() + underlying := named.Underlying() w.typ(underlying, obj.Pkg()) if types.IsInterface(t) { @@ -738,6 +745,11 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) { }() } switch t := t.(type) { + case *aliases.Alias: + // TODO(adonovan): support parameterized aliases, following *types.Named. + w.startType(aliasType) + w.qualifiedType(t.Obj()) + case *types.Named: if targs := t.TypeArgs(); targs.Len() > 0 { w.startType(instanceType) @@ -843,7 +855,7 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) { for i := 0; i < n; i++ { ft := t.EmbeddedType(i) tPkg := pkg - if named, _ := ft.(*types.Named); named != nil { + if named, _ := aliases.Unalias(ft).(*types.Named); named != nil { w.pos(named.Obj().Pos()) } else { w.pos(token.NoPos) @@ -1319,3 +1331,19 @@ func (e internalError) Error() string { return "gcimporter: " + string(e) } func internalErrorf(format string, args ...interface{}) error { return internalError(fmt.Sprintf(format, args...)) } + +// aliasRHS removes exactly one Alias constructor. +func aliasRHS(alias *aliases.Alias) types.Type { + // TODO(adonovan): if proposal #66559 is accepted, this will + // become Alias.RHS(alias). In the meantime, we must punch + // through the drywall. + type go123Alias struct { + _ *types.TypeName + _ *types.TypeParamList + RHS types.Type + _ types.Type + } + var raw *go123Alias + *(**aliases.Alias)(unsafe.Pointer(&raw)) = alias + return raw.RHS +} diff --git a/vendor/golang.org/x/tools/internal/gcimporter/iimport.go b/vendor/golang.org/x/tools/internal/gcimporter/iimport.go index 9fffa9ad05cb..2732121b5efa 100644 --- a/vendor/golang.org/x/tools/internal/gcimporter/iimport.go +++ b/vendor/golang.org/x/tools/internal/gcimporter/iimport.go @@ -22,6 +22,8 @@ import ( "strings" "golang.org/x/tools/go/types/objectpath" + "golang.org/x/tools/internal/aliases" + "golang.org/x/tools/internal/typesinternal" ) type intReader struct { @@ -78,6 +80,20 @@ const ( typeParamType instanceType unionType + aliasType +) + +// Object tags +const ( + varTag = 'V' + funcTag = 'F' + genericFuncTag = 'G' + constTag = 'C' + aliasTag = 'A' + genericAliasTag = 'B' + typeParamTag = 'P' + typeTag = 'T' + genericTypeTag = 'U' ) // IImportData imports a package from the serialized package data @@ -322,7 +338,7 @@ func iimportCommon(fset *token.FileSet, getPackages GetPackagesFunc, data []byte } // SetConstraint can't be called if the constraint type is not yet complete. - // When type params are created in the 'P' case of (*importReader).obj(), + // When type params are created in the typeParamTag case of (*importReader).obj(), // the associated constraint type may not be complete due to recursion. // Therefore, we defer calling SetConstraint there, and call it here instead // after all types are complete. @@ -522,7 +538,7 @@ func canReuse(def *types.Named, rhs types.Type) bool { if def == nil { return true } - iface, _ := rhs.(*types.Interface) + iface, _ := aliases.Unalias(rhs).(*types.Interface) if iface == nil { return true } @@ -544,25 +560,29 @@ func (r *importReader) obj(name string) { pos := r.pos() switch tag { - case 'A': + case aliasTag: typ := r.typ() - - r.declare(types.NewTypeName(pos, r.currPkg, name, typ)) - - case 'C': + // TODO(adonovan): support generic aliases: + // if tag == genericAliasTag { + // tparams := r.tparamList() + // alias.SetTypeParams(tparams) + // } + r.declare(aliases.NewAlias(pos, r.currPkg, name, typ)) + + case constTag: typ, val := r.value() r.declare(types.NewConst(pos, r.currPkg, name, typ, val)) - case 'F', 'G': + case funcTag, genericFuncTag: var tparams []*types.TypeParam - if tag == 'G' { + if tag == genericFuncTag { tparams = r.tparamList() } sig := r.signature(nil, nil, tparams) r.declare(types.NewFunc(pos, r.currPkg, name, sig)) - case 'T', 'U': + case typeTag, genericTypeTag: // Types can be recursive. We need to setup a stub // declaration before recursing. obj := types.NewTypeName(pos, r.currPkg, name, nil) @@ -570,7 +590,7 @@ func (r *importReader) obj(name string) { // Declare obj before calling r.tparamList, so the new type name is recognized // if used in the constraint of one of its own typeparams (see #48280). r.declare(obj) - if tag == 'U' { + if tag == genericTypeTag { tparams := r.tparamList() named.SetTypeParams(tparams) } @@ -587,14 +607,13 @@ func (r *importReader) obj(name string) { // If the receiver has any targs, set those as the // rparams of the method (since those are the // typeparams being used in the method sig/body). - base := baseType(recv.Type()) - assert(base != nil) - targs := base.TypeArgs() + _, recvNamed := typesinternal.ReceiverNamed(recv) + targs := recvNamed.TypeArgs() var rparams []*types.TypeParam if targs.Len() > 0 { rparams = make([]*types.TypeParam, targs.Len()) for i := range rparams { - rparams[i] = targs.At(i).(*types.TypeParam) + rparams[i] = aliases.Unalias(targs.At(i)).(*types.TypeParam) } } msig := r.signature(recv, rparams, nil) @@ -603,7 +622,7 @@ func (r *importReader) obj(name string) { } } - case 'P': + case typeParamTag: // We need to "declare" a typeparam in order to have a name that // can be referenced recursively (if needed) in the type param's // bound. @@ -624,7 +643,7 @@ func (r *importReader) obj(name string) { } constraint := r.typ() if implicit { - iface, _ := constraint.(*types.Interface) + iface, _ := aliases.Unalias(constraint).(*types.Interface) if iface == nil { errorf("non-interface constraint marked implicit") } @@ -636,7 +655,7 @@ func (r *importReader) obj(name string) { // completely set up all types in ImportData. r.p.later = append(r.p.later, setConstraintArgs{t: t, constraint: constraint}) - case 'V': + case varTag: typ := r.typ() r.declare(types.NewVar(pos, r.currPkg, name, typ)) @@ -831,7 +850,7 @@ func (r *importReader) typ() types.Type { } func isInterface(t types.Type) bool { - _, ok := t.(*types.Interface) + _, ok := aliases.Unalias(t).(*types.Interface) return ok } @@ -853,7 +872,7 @@ func (r *importReader) doType(base *types.Named) (res types.Type) { errorf("unexpected kind tag in %q: %v", r.p.ipath, k) return nil - case definedType: + case aliasType, definedType: pkg, name := r.qualifiedIdent() r.p.doDecl(pkg, name) return pkg.Scope().Lookup(name).(*types.TypeName).Type() @@ -1030,7 +1049,7 @@ func (r *importReader) tparamList() []*types.TypeParam { for i := range xs { // Note: the standard library importer is tolerant of nil types here, // though would panic in SetTypeParams. - xs[i] = r.typ().(*types.TypeParam) + xs[i] = aliases.Unalias(r.typ()).(*types.TypeParam) } return xs } @@ -1077,13 +1096,3 @@ func (r *importReader) byte() byte { } return x } - -func baseType(typ types.Type) *types.Named { - // pointer receivers are never types.Named types - if p, _ := typ.(*types.Pointer); p != nil { - typ = p.Elem() - } - // receiver base types are always (possibly generic) types.Named types - n, _ := typ.(*types.Named) - return n -} diff --git a/vendor/golang.org/x/tools/internal/gcimporter/support_go117.go b/vendor/golang.org/x/tools/internal/gcimporter/support_go117.go deleted file mode 100644 index d892273efb61..000000000000 --- a/vendor/golang.org/x/tools/internal/gcimporter/support_go117.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.18 -// +build !go1.18 - -package gcimporter - -import "go/types" - -const iexportVersion = iexportVersionGo1_11 - -func additionalPredeclared() []types.Type { - return nil -} diff --git a/vendor/golang.org/x/tools/internal/gcimporter/support_go118.go b/vendor/golang.org/x/tools/internal/gcimporter/support_go118.go index edbe6ea7041d..0cd3b91b65ad 100644 --- a/vendor/golang.org/x/tools/internal/gcimporter/support_go118.go +++ b/vendor/golang.org/x/tools/internal/gcimporter/support_go118.go @@ -2,9 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build go1.18 -// +build go1.18 - package gcimporter import "go/types" diff --git a/vendor/golang.org/x/tools/internal/gcimporter/unified_no.go b/vendor/golang.org/x/tools/internal/gcimporter/unified_no.go index 286bf445483d..38b624cadab6 100644 --- a/vendor/golang.org/x/tools/internal/gcimporter/unified_no.go +++ b/vendor/golang.org/x/tools/internal/gcimporter/unified_no.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !(go1.18 && goexperiment.unified) -// +build !go1.18 !goexperiment.unified +//go:build !goexperiment.unified +// +build !goexperiment.unified package gcimporter diff --git a/vendor/golang.org/x/tools/internal/gcimporter/unified_yes.go b/vendor/golang.org/x/tools/internal/gcimporter/unified_yes.go index b5d69ffbe682..b5118d0b3a50 100644 --- a/vendor/golang.org/x/tools/internal/gcimporter/unified_yes.go +++ b/vendor/golang.org/x/tools/internal/gcimporter/unified_yes.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build go1.18 && goexperiment.unified -// +build go1.18,goexperiment.unified +//go:build goexperiment.unified +// +build goexperiment.unified package gcimporter diff --git a/vendor/golang.org/x/tools/internal/gcimporter/ureader_no.go b/vendor/golang.org/x/tools/internal/gcimporter/ureader_no.go deleted file mode 100644 index 8eb20729c2ad..000000000000 --- a/vendor/golang.org/x/tools/internal/gcimporter/ureader_no.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.18 -// +build !go1.18 - -package gcimporter - -import ( - "fmt" - "go/token" - "go/types" -) - -func UImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) { - err = fmt.Errorf("go/tools compiled with a Go version earlier than 1.18 cannot read unified IR export data") - return -} diff --git a/vendor/golang.org/x/tools/internal/gcimporter/ureader_yes.go b/vendor/golang.org/x/tools/internal/gcimporter/ureader_yes.go index b977435f626d..b3be452ae8a4 100644 --- a/vendor/golang.org/x/tools/internal/gcimporter/ureader_yes.go +++ b/vendor/golang.org/x/tools/internal/gcimporter/ureader_yes.go @@ -4,9 +4,6 @@ // Derived from go/internal/gcimporter/ureader.go -//go:build go1.18 -// +build go1.18 - package gcimporter import ( @@ -16,6 +13,7 @@ import ( "sort" "strings" + "golang.org/x/tools/internal/aliases" "golang.org/x/tools/internal/pkgbits" ) @@ -526,7 +524,7 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) { case pkgbits.ObjAlias: pos := r.pos() typ := r.typ() - declare(types.NewTypeName(pos, objPkg, objName, typ)) + declare(aliases.NewAlias(pos, objPkg, objName, typ)) case pkgbits.ObjConst: pos := r.pos() @@ -553,7 +551,7 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) { // If the underlying type is an interface, we need to // duplicate its methods so we can replace the receiver // parameter's type (#49906). - if iface, ok := underlying.(*types.Interface); ok && iface.NumExplicitMethods() != 0 { + if iface, ok := aliases.Unalias(underlying).(*types.Interface); ok && iface.NumExplicitMethods() != 0 { methods := make([]*types.Func, iface.NumExplicitMethods()) for i := range methods { fn := iface.ExplicitMethod(i) diff --git a/vendor/golang.org/x/tools/internal/gocommand/invoke.go b/vendor/golang.org/x/tools/internal/gocommand/invoke.go index 55312522dc2d..f7de3c8283b2 100644 --- a/vendor/golang.org/x/tools/internal/gocommand/invoke.go +++ b/vendor/golang.org/x/tools/internal/gocommand/invoke.go @@ -158,12 +158,15 @@ type Invocation struct { BuildFlags []string // If ModFlag is set, the go command is invoked with -mod=ModFlag. + // TODO(rfindley): remove, in favor of Args. ModFlag string // If ModFile is set, the go command is invoked with -modfile=ModFile. + // TODO(rfindley): remove, in favor of Args. ModFile string // If Overlay is set, the go command is invoked with -overlay=Overlay. + // TODO(rfindley): remove, in favor of Args. Overlay string // If CleanEnv is set, the invocation will run only with the environment diff --git a/vendor/golang.org/x/tools/internal/imports/fix.go b/vendor/golang.org/x/tools/internal/imports/fix.go index 6a18f63a44dc..55980327616e 100644 --- a/vendor/golang.org/x/tools/internal/imports/fix.go +++ b/vendor/golang.org/x/tools/internal/imports/fix.go @@ -31,6 +31,7 @@ import ( "golang.org/x/tools/internal/event" "golang.org/x/tools/internal/gocommand" "golang.org/x/tools/internal/gopathwalk" + "golang.org/x/tools/internal/stdlib" ) // importToGroup is a list of functions which map from an import path to @@ -511,9 +512,9 @@ func (p *pass) assumeSiblingImportsValid() { } for left, rights := range refs { if imp, ok := importsByName[left]; ok { - if m, ok := stdlib[imp.ImportPath]; ok { + if m, ok := stdlib.PackageSymbols[imp.ImportPath]; ok { // We have the stdlib in memory; no need to guess. - rights = copyExports(m) + rights = symbolNameSet(m) } p.addCandidate(imp, &packageInfo{ // no name; we already know it. @@ -641,7 +642,7 @@ func getCandidatePkgs(ctx context.Context, wrappedCallback *scanCallback, filena dupCheck := map[string]struct{}{} // Start off with the standard library. - for importPath, exports := range stdlib { + for importPath, symbols := range stdlib.PackageSymbols { p := &pkg{ dir: filepath.Join(goenv["GOROOT"], "src", importPath), importPathShort: importPath, @@ -650,6 +651,13 @@ func getCandidatePkgs(ctx context.Context, wrappedCallback *scanCallback, filena } dupCheck[importPath] = struct{}{} if notSelf(p) && wrappedCallback.dirFound(p) && wrappedCallback.packageNameLoaded(p) { + var exports []stdlib.Symbol + for _, sym := range symbols { + switch sym.Kind { + case stdlib.Func, stdlib.Type, stdlib.Var, stdlib.Const: + exports = append(exports, sym) + } + } wrappedCallback.exportsLoaded(p, exports) } } @@ -670,7 +678,7 @@ func getCandidatePkgs(ctx context.Context, wrappedCallback *scanCallback, filena dupCheck[pkg.importPathShort] = struct{}{} return notSelf(pkg) && wrappedCallback.packageNameLoaded(pkg) }, - exportsLoaded: func(pkg *pkg, exports []string) { + exportsLoaded: func(pkg *pkg, exports []stdlib.Symbol) { // If we're an x_test, load the package under test's test variant. if strings.HasSuffix(filePkg, "_test") && pkg.dir == filepath.Dir(filename) { var err error @@ -795,7 +803,7 @@ func GetImportPaths(ctx context.Context, wrapped func(ImportFix), searchPrefix, // A PackageExport is a package and its exports. type PackageExport struct { Fix *ImportFix - Exports []string + Exports []stdlib.Symbol } // GetPackageExports returns all known packages with name pkg and their exports. @@ -810,8 +818,8 @@ func GetPackageExports(ctx context.Context, wrapped func(PackageExport), searchP packageNameLoaded: func(pkg *pkg) bool { return pkg.packageName == searchPkg }, - exportsLoaded: func(pkg *pkg, exports []string) { - sort.Strings(exports) + exportsLoaded: func(pkg *pkg, exports []stdlib.Symbol) { + sortSymbols(exports) wrapped(PackageExport{ Fix: &ImportFix{ StmtInfo: ImportInfo{ @@ -988,8 +996,10 @@ func (e *ProcessEnv) GetResolver() (Resolver, error) { // already know the view type. if len(e.Env["GOMOD"]) == 0 && len(e.Env["GOWORK"]) == 0 { e.resolver = newGopathResolver(e) + } else if r, err := newModuleResolver(e, e.ModCache); err != nil { + e.resolverErr = err } else { - e.resolver, e.resolverErr = newModuleResolver(e, e.ModCache) + e.resolver = Resolver(r) } } @@ -1054,7 +1064,7 @@ func addStdlibCandidates(pass *pass, refs references) error { if path.Base(pkg) == pass.f.Name.Name && filepath.Join(goenv["GOROOT"], "src", pkg) == pass.srcDir { return } - exports := copyExports(stdlib[pkg]) + exports := symbolNameSet(stdlib.PackageSymbols[pkg]) pass.addCandidate( &ImportInfo{ImportPath: pkg}, &packageInfo{name: path.Base(pkg), exports: exports}) @@ -1066,7 +1076,7 @@ func addStdlibCandidates(pass *pass, refs references) error { add("math/rand") continue } - for importPath := range stdlib { + for importPath := range stdlib.PackageSymbols { if path.Base(importPath) == left { add(importPath) } @@ -1085,7 +1095,7 @@ type Resolver interface { // loadExports returns the set of exported symbols in the package at dir. // loadExports may be called concurrently. - loadExports(ctx context.Context, pkg *pkg, includeTest bool) (string, []string, error) + loadExports(ctx context.Context, pkg *pkg, includeTest bool) (string, []stdlib.Symbol, error) // scoreImportPath returns the relevance for an import path. scoreImportPath(ctx context.Context, path string) float64 @@ -1114,7 +1124,7 @@ type scanCallback struct { // If it returns true, the package's exports will be loaded. packageNameLoaded func(pkg *pkg) bool // exportsLoaded is called when a package's exports have been loaded. - exportsLoaded func(pkg *pkg, exports []string) + exportsLoaded func(pkg *pkg, exports []stdlib.Symbol) } func addExternalCandidates(ctx context.Context, pass *pass, refs references, filename string) error { @@ -1295,7 +1305,7 @@ func (r *gopathResolver) loadPackageNames(importPaths []string, srcDir string) ( // importPathToName finds out the actual package name, as declared in its .go files. func importPathToName(bctx *build.Context, importPath, srcDir string) string { // Fast path for standard library without going to disk. - if _, ok := stdlib[importPath]; ok { + if stdlib.HasPackage(importPath) { return path.Base(importPath) // stdlib packages always match their paths. } @@ -1493,7 +1503,7 @@ func (r *gopathResolver) scan(ctx context.Context, callback *scanCallback) error } func (r *gopathResolver) scoreImportPath(ctx context.Context, path string) float64 { - if _, ok := stdlib[path]; ok { + if stdlib.HasPackage(path) { return MaxRelevance } return MaxRelevance - 1 @@ -1510,7 +1520,7 @@ func filterRoots(roots []gopathwalk.Root, include func(gopathwalk.Root) bool) [] return result } -func (r *gopathResolver) loadExports(ctx context.Context, pkg *pkg, includeTest bool) (string, []string, error) { +func (r *gopathResolver) loadExports(ctx context.Context, pkg *pkg, includeTest bool) (string, []stdlib.Symbol, error) { if info, ok := r.cache.Load(pkg.dir); ok && !includeTest { return r.cache.CacheExports(ctx, r.env, info) } @@ -1530,7 +1540,7 @@ func VendorlessPath(ipath string) string { return ipath } -func loadExportsFromFiles(ctx context.Context, env *ProcessEnv, dir string, includeTest bool) (string, []string, error) { +func loadExportsFromFiles(ctx context.Context, env *ProcessEnv, dir string, includeTest bool) (string, []stdlib.Symbol, error) { // Look for non-test, buildable .go files which could provide exports. all, err := os.ReadDir(dir) if err != nil { @@ -1554,7 +1564,7 @@ func loadExportsFromFiles(ctx context.Context, env *ProcessEnv, dir string, incl } var pkgName string - var exports []string + var exports []stdlib.Symbol fset := token.NewFileSet() for _, fi := range files { select { @@ -1581,21 +1591,41 @@ func loadExportsFromFiles(ctx context.Context, env *ProcessEnv, dir string, incl continue } pkgName = f.Name.Name - for name := range f.Scope.Objects { + for name, obj := range f.Scope.Objects { if ast.IsExported(name) { - exports = append(exports, name) + var kind stdlib.Kind + switch obj.Kind { + case ast.Con: + kind = stdlib.Const + case ast.Typ: + kind = stdlib.Type + case ast.Var: + kind = stdlib.Var + case ast.Fun: + kind = stdlib.Func + } + exports = append(exports, stdlib.Symbol{ + Name: name, + Kind: kind, + Version: 0, // unknown; be permissive + }) } } } + sortSymbols(exports) if env.Logf != nil { - sortedExports := append([]string(nil), exports...) - sort.Strings(sortedExports) - env.Logf("loaded exports in dir %v (package %v): %v", dir, pkgName, strings.Join(sortedExports, ", ")) + env.Logf("loaded exports in dir %v (package %v): %v", dir, pkgName, exports) } return pkgName, exports, nil } +func sortSymbols(syms []stdlib.Symbol) { + sort.Slice(syms, func(i, j int) bool { + return syms[i].Name < syms[j].Name + }) +} + // findImport searches for a package with the given symbols. // If no package is found, findImport returns ("", false, nil) func findImport(ctx context.Context, pass *pass, candidates []pkgDistance, pkgName string, symbols map[string]bool) (*pkg, error) { @@ -1662,7 +1692,7 @@ func findImport(ctx context.Context, pass *pass, candidates []pkgDistance, pkgNa exportsMap := make(map[string]bool, len(exports)) for _, sym := range exports { - exportsMap[sym] = true + exportsMap[sym.Name] = true } // If it doesn't have the right @@ -1820,10 +1850,13 @@ func (fn visitFn) Visit(node ast.Node) ast.Visitor { return fn(node) } -func copyExports(pkg []string) map[string]bool { - m := make(map[string]bool, len(pkg)) - for _, v := range pkg { - m[v] = true +func symbolNameSet(symbols []stdlib.Symbol) map[string]bool { + names := make(map[string]bool) + for _, sym := range symbols { + switch sym.Kind { + case stdlib.Const, stdlib.Var, stdlib.Type, stdlib.Func: + names[sym.Name] = true + } } - return m + return names } diff --git a/vendor/golang.org/x/tools/internal/imports/imports.go b/vendor/golang.org/x/tools/internal/imports/imports.go index 660407548e5a..f83465520a45 100644 --- a/vendor/golang.org/x/tools/internal/imports/imports.go +++ b/vendor/golang.org/x/tools/internal/imports/imports.go @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:generate go run mkstdlib.go - // Package imports implements a Go pretty-printer (like package "go/format") // that also adds or removes import statements as necessary. package imports @@ -109,7 +107,7 @@ func ApplyFixes(fixes []*ImportFix, filename string, src []byte, opt *Options, e } // formatFile formats the file syntax tree. -// It may mutate the token.FileSet. +// It may mutate the token.FileSet and the ast.File. // // If an adjust function is provided, it is called after formatting // with the original source (formatFile's src parameter) and the diff --git a/vendor/golang.org/x/tools/internal/imports/mod.go b/vendor/golang.org/x/tools/internal/imports/mod.go index 3d0f38f6c231..21ef938978e1 100644 --- a/vendor/golang.org/x/tools/internal/imports/mod.go +++ b/vendor/golang.org/x/tools/internal/imports/mod.go @@ -21,6 +21,7 @@ import ( "golang.org/x/tools/internal/event" "golang.org/x/tools/internal/gocommand" "golang.org/x/tools/internal/gopathwalk" + "golang.org/x/tools/internal/stdlib" ) // Notes(rfindley): ModuleResolver appears to be heavily optimized for scanning @@ -313,15 +314,19 @@ func (r *ModuleResolver) ClearForNewScan() Resolver { // TODO(rfindley): move this to a new env.go, consolidating ProcessEnv methods. func (e *ProcessEnv) ClearModuleInfo() { if r, ok := e.resolver.(*ModuleResolver); ok { - resolver, resolverErr := newModuleResolver(e, e.ModCache) - if resolverErr == nil { - <-r.scanSema // acquire (guards caches) - resolver.moduleCacheCache = r.moduleCacheCache - resolver.otherCache = r.otherCache - r.scanSema <- struct{}{} // release + resolver, err := newModuleResolver(e, e.ModCache) + if err != nil { + e.resolver = nil + e.resolverErr = err + return } - e.resolver = resolver - e.resolverErr = resolverErr + + <-r.scanSema // acquire (guards caches) + resolver.moduleCacheCache = r.moduleCacheCache + resolver.otherCache = r.otherCache + r.scanSema <- struct{}{} // release + + e.UpdateResolver(resolver) } } @@ -412,7 +417,7 @@ func (r *ModuleResolver) cachePackageName(info directoryPackageInfo) (string, er return r.otherCache.CachePackageName(info) } -func (r *ModuleResolver) cacheExports(ctx context.Context, env *ProcessEnv, info directoryPackageInfo) (string, []string, error) { +func (r *ModuleResolver) cacheExports(ctx context.Context, env *ProcessEnv, info directoryPackageInfo) (string, []stdlib.Symbol, error) { if info.rootType == gopathwalk.RootModuleCache { return r.moduleCacheCache.CacheExports(ctx, env, info) } @@ -632,7 +637,7 @@ func (r *ModuleResolver) scan(ctx context.Context, callback *scanCallback) error } func (r *ModuleResolver) scoreImportPath(ctx context.Context, path string) float64 { - if _, ok := stdlib[path]; ok { + if stdlib.HasPackage(path) { return MaxRelevance } mod, _ := r.findPackage(path) @@ -710,7 +715,7 @@ func (r *ModuleResolver) canonicalize(info directoryPackageInfo) (*pkg, error) { return res, nil } -func (r *ModuleResolver) loadExports(ctx context.Context, pkg *pkg, includeTest bool) (string, []string, error) { +func (r *ModuleResolver) loadExports(ctx context.Context, pkg *pkg, includeTest bool) (string, []stdlib.Symbol, error) { if info, ok := r.cacheLoad(pkg.dir); ok && !includeTest { return r.cacheExports(ctx, r.env, info) } diff --git a/vendor/golang.org/x/tools/internal/imports/mod_cache.go b/vendor/golang.org/x/tools/internal/imports/mod_cache.go index cfc54657656d..b1192696b28e 100644 --- a/vendor/golang.org/x/tools/internal/imports/mod_cache.go +++ b/vendor/golang.org/x/tools/internal/imports/mod_cache.go @@ -14,6 +14,7 @@ import ( "golang.org/x/mod/module" "golang.org/x/tools/internal/gopathwalk" + "golang.org/x/tools/internal/stdlib" ) // To find packages to import, the resolver needs to know about all of @@ -73,7 +74,7 @@ type directoryPackageInfo struct { // the default build context GOOS and GOARCH. // // We can make this explicit, and key exports by GOOS, GOARCH. - exports []string + exports []stdlib.Symbol } // reachedStatus returns true when info has a status at least target and any error associated with @@ -229,7 +230,7 @@ func (d *DirInfoCache) CachePackageName(info directoryPackageInfo) (string, erro return info.packageName, info.err } -func (d *DirInfoCache) CacheExports(ctx context.Context, env *ProcessEnv, info directoryPackageInfo) (string, []string, error) { +func (d *DirInfoCache) CacheExports(ctx context.Context, env *ProcessEnv, info directoryPackageInfo) (string, []stdlib.Symbol, error) { if reached, _ := info.reachedStatus(exportsLoaded); reached { return info.packageName, info.exports, info.err } diff --git a/vendor/golang.org/x/tools/internal/imports/sortimports.go b/vendor/golang.org/x/tools/internal/imports/sortimports.go index 1a0a7ebd9e4d..da8194fd965b 100644 --- a/vendor/golang.org/x/tools/internal/imports/sortimports.go +++ b/vendor/golang.org/x/tools/internal/imports/sortimports.go @@ -18,7 +18,7 @@ import ( // sortImports sorts runs of consecutive import lines in import blocks in f. // It also removes duplicate imports when it is possible to do so without data loss. // -// It may mutate the token.File. +// It may mutate the token.File and the ast.File. func sortImports(localPrefix string, tokFile *token.File, f *ast.File) { for i, d := range f.Decls { d, ok := d.(*ast.GenDecl) diff --git a/vendor/golang.org/x/tools/internal/imports/zstdlib.go b/vendor/golang.org/x/tools/internal/imports/zstdlib.go deleted file mode 100644 index 8db24df2ff46..000000000000 --- a/vendor/golang.org/x/tools/internal/imports/zstdlib.go +++ /dev/null @@ -1,11406 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Code generated by mkstdlib.go. DO NOT EDIT. - -package imports - -var stdlib = map[string][]string{ - "archive/tar": { - "ErrFieldTooLong", - "ErrHeader", - "ErrInsecurePath", - "ErrWriteAfterClose", - "ErrWriteTooLong", - "FileInfoHeader", - "Format", - "FormatGNU", - "FormatPAX", - "FormatUSTAR", - "FormatUnknown", - "Header", - "NewReader", - "NewWriter", - "Reader", - "TypeBlock", - "TypeChar", - "TypeCont", - "TypeDir", - "TypeFifo", - "TypeGNULongLink", - "TypeGNULongName", - "TypeGNUSparse", - "TypeLink", - "TypeReg", - "TypeRegA", - "TypeSymlink", - "TypeXGlobalHeader", - "TypeXHeader", - "Writer", - }, - "archive/zip": { - "Compressor", - "Decompressor", - "Deflate", - "ErrAlgorithm", - "ErrChecksum", - "ErrFormat", - "ErrInsecurePath", - "File", - "FileHeader", - "FileInfoHeader", - "NewReader", - "NewWriter", - "OpenReader", - "ReadCloser", - "Reader", - "RegisterCompressor", - "RegisterDecompressor", - "Store", - "Writer", - }, - "bufio": { - "ErrAdvanceTooFar", - "ErrBadReadCount", - "ErrBufferFull", - "ErrFinalToken", - "ErrInvalidUnreadByte", - "ErrInvalidUnreadRune", - "ErrNegativeAdvance", - "ErrNegativeCount", - "ErrTooLong", - "MaxScanTokenSize", - "NewReadWriter", - "NewReader", - "NewReaderSize", - "NewScanner", - "NewWriter", - "NewWriterSize", - "ReadWriter", - "Reader", - "ScanBytes", - "ScanLines", - "ScanRunes", - "ScanWords", - "Scanner", - "SplitFunc", - "Writer", - }, - "bytes": { - "Buffer", - "Clone", - "Compare", - "Contains", - "ContainsAny", - "ContainsFunc", - "ContainsRune", - "Count", - "Cut", - "CutPrefix", - "CutSuffix", - "Equal", - "EqualFold", - "ErrTooLarge", - "Fields", - "FieldsFunc", - "HasPrefix", - "HasSuffix", - "Index", - "IndexAny", - "IndexByte", - "IndexFunc", - "IndexRune", - "Join", - "LastIndex", - "LastIndexAny", - "LastIndexByte", - "LastIndexFunc", - "Map", - "MinRead", - "NewBuffer", - "NewBufferString", - "NewReader", - "Reader", - "Repeat", - "Replace", - "ReplaceAll", - "Runes", - "Split", - "SplitAfter", - "SplitAfterN", - "SplitN", - "Title", - "ToLower", - "ToLowerSpecial", - "ToTitle", - "ToTitleSpecial", - "ToUpper", - "ToUpperSpecial", - "ToValidUTF8", - "Trim", - "TrimFunc", - "TrimLeft", - "TrimLeftFunc", - "TrimPrefix", - "TrimRight", - "TrimRightFunc", - "TrimSpace", - "TrimSuffix", - }, - "cmp": { - "Compare", - "Less", - "Or", - "Ordered", - }, - "compress/bzip2": { - "NewReader", - "StructuralError", - }, - "compress/flate": { - "BestCompression", - "BestSpeed", - "CorruptInputError", - "DefaultCompression", - "HuffmanOnly", - "InternalError", - "NewReader", - "NewReaderDict", - "NewWriter", - "NewWriterDict", - "NoCompression", - "ReadError", - "Reader", - "Resetter", - "WriteError", - "Writer", - }, - "compress/gzip": { - "BestCompression", - "BestSpeed", - "DefaultCompression", - "ErrChecksum", - "ErrHeader", - "Header", - "HuffmanOnly", - "NewReader", - "NewWriter", - "NewWriterLevel", - "NoCompression", - "Reader", - "Writer", - }, - "compress/lzw": { - "LSB", - "MSB", - "NewReader", - "NewWriter", - "Order", - "Reader", - "Writer", - }, - "compress/zlib": { - "BestCompression", - "BestSpeed", - "DefaultCompression", - "ErrChecksum", - "ErrDictionary", - "ErrHeader", - "HuffmanOnly", - "NewReader", - "NewReaderDict", - "NewWriter", - "NewWriterLevel", - "NewWriterLevelDict", - "NoCompression", - "Resetter", - "Writer", - }, - "container/heap": { - "Fix", - "Init", - "Interface", - "Pop", - "Push", - "Remove", - }, - "container/list": { - "Element", - "List", - "New", - }, - "container/ring": { - "New", - "Ring", - }, - "context": { - "AfterFunc", - "Background", - "CancelCauseFunc", - "CancelFunc", - "Canceled", - "Cause", - "Context", - "DeadlineExceeded", - "TODO", - "WithCancel", - "WithCancelCause", - "WithDeadline", - "WithDeadlineCause", - "WithTimeout", - "WithTimeoutCause", - "WithValue", - "WithoutCancel", - }, - "crypto": { - "BLAKE2b_256", - "BLAKE2b_384", - "BLAKE2b_512", - "BLAKE2s_256", - "Decrypter", - "DecrypterOpts", - "Hash", - "MD4", - "MD5", - "MD5SHA1", - "PrivateKey", - "PublicKey", - "RIPEMD160", - "RegisterHash", - "SHA1", - "SHA224", - "SHA256", - "SHA384", - "SHA3_224", - "SHA3_256", - "SHA3_384", - "SHA3_512", - "SHA512", - "SHA512_224", - "SHA512_256", - "Signer", - "SignerOpts", - }, - "crypto/aes": { - "BlockSize", - "KeySizeError", - "NewCipher", - }, - "crypto/cipher": { - "AEAD", - "Block", - "BlockMode", - "NewCBCDecrypter", - "NewCBCEncrypter", - "NewCFBDecrypter", - "NewCFBEncrypter", - "NewCTR", - "NewGCM", - "NewGCMWithNonceSize", - "NewGCMWithTagSize", - "NewOFB", - "Stream", - "StreamReader", - "StreamWriter", - }, - "crypto/des": { - "BlockSize", - "KeySizeError", - "NewCipher", - "NewTripleDESCipher", - }, - "crypto/dsa": { - "ErrInvalidPublicKey", - "GenerateKey", - "GenerateParameters", - "L1024N160", - "L2048N224", - "L2048N256", - "L3072N256", - "ParameterSizes", - "Parameters", - "PrivateKey", - "PublicKey", - "Sign", - "Verify", - }, - "crypto/ecdh": { - "Curve", - "P256", - "P384", - "P521", - "PrivateKey", - "PublicKey", - "X25519", - }, - "crypto/ecdsa": { - "GenerateKey", - "PrivateKey", - "PublicKey", - "Sign", - "SignASN1", - "Verify", - "VerifyASN1", - }, - "crypto/ed25519": { - "GenerateKey", - "NewKeyFromSeed", - "Options", - "PrivateKey", - "PrivateKeySize", - "PublicKey", - "PublicKeySize", - "SeedSize", - "Sign", - "SignatureSize", - "Verify", - "VerifyWithOptions", - }, - "crypto/elliptic": { - "Curve", - "CurveParams", - "GenerateKey", - "Marshal", - "MarshalCompressed", - "P224", - "P256", - "P384", - "P521", - "Unmarshal", - "UnmarshalCompressed", - }, - "crypto/hmac": { - "Equal", - "New", - }, - "crypto/md5": { - "BlockSize", - "New", - "Size", - "Sum", - }, - "crypto/rand": { - "Int", - "Prime", - "Read", - "Reader", - }, - "crypto/rc4": { - "Cipher", - "KeySizeError", - "NewCipher", - }, - "crypto/rsa": { - "CRTValue", - "DecryptOAEP", - "DecryptPKCS1v15", - "DecryptPKCS1v15SessionKey", - "EncryptOAEP", - "EncryptPKCS1v15", - "ErrDecryption", - "ErrMessageTooLong", - "ErrVerification", - "GenerateKey", - "GenerateMultiPrimeKey", - "OAEPOptions", - "PKCS1v15DecryptOptions", - "PSSOptions", - "PSSSaltLengthAuto", - "PSSSaltLengthEqualsHash", - "PrecomputedValues", - "PrivateKey", - "PublicKey", - "SignPKCS1v15", - "SignPSS", - "VerifyPKCS1v15", - "VerifyPSS", - }, - "crypto/sha1": { - "BlockSize", - "New", - "Size", - "Sum", - }, - "crypto/sha256": { - "BlockSize", - "New", - "New224", - "Size", - "Size224", - "Sum224", - "Sum256", - }, - "crypto/sha512": { - "BlockSize", - "New", - "New384", - "New512_224", - "New512_256", - "Size", - "Size224", - "Size256", - "Size384", - "Sum384", - "Sum512", - "Sum512_224", - "Sum512_256", - }, - "crypto/subtle": { - "ConstantTimeByteEq", - "ConstantTimeCompare", - "ConstantTimeCopy", - "ConstantTimeEq", - "ConstantTimeLessOrEq", - "ConstantTimeSelect", - "XORBytes", - }, - "crypto/tls": { - "AlertError", - "Certificate", - "CertificateRequestInfo", - "CertificateVerificationError", - "CipherSuite", - "CipherSuiteName", - "CipherSuites", - "Client", - "ClientAuthType", - "ClientHelloInfo", - "ClientSessionCache", - "ClientSessionState", - "Config", - "Conn", - "ConnectionState", - "CurveID", - "CurveP256", - "CurveP384", - "CurveP521", - "Dial", - "DialWithDialer", - "Dialer", - "ECDSAWithP256AndSHA256", - "ECDSAWithP384AndSHA384", - "ECDSAWithP521AndSHA512", - "ECDSAWithSHA1", - "Ed25519", - "InsecureCipherSuites", - "Listen", - "LoadX509KeyPair", - "NewLRUClientSessionCache", - "NewListener", - "NewResumptionState", - "NoClientCert", - "PKCS1WithSHA1", - "PKCS1WithSHA256", - "PKCS1WithSHA384", - "PKCS1WithSHA512", - "PSSWithSHA256", - "PSSWithSHA384", - "PSSWithSHA512", - "ParseSessionState", - "QUICClient", - "QUICConfig", - "QUICConn", - "QUICEncryptionLevel", - "QUICEncryptionLevelApplication", - "QUICEncryptionLevelEarly", - "QUICEncryptionLevelHandshake", - "QUICEncryptionLevelInitial", - "QUICEvent", - "QUICEventKind", - "QUICHandshakeDone", - "QUICNoEvent", - "QUICRejectedEarlyData", - "QUICServer", - "QUICSessionTicketOptions", - "QUICSetReadSecret", - "QUICSetWriteSecret", - "QUICTransportParameters", - "QUICTransportParametersRequired", - "QUICWriteData", - "RecordHeaderError", - "RenegotiateFreelyAsClient", - "RenegotiateNever", - "RenegotiateOnceAsClient", - "RenegotiationSupport", - "RequestClientCert", - "RequireAndVerifyClientCert", - "RequireAnyClientCert", - "Server", - "SessionState", - "SignatureScheme", - "TLS_AES_128_GCM_SHA256", - "TLS_AES_256_GCM_SHA384", - "TLS_CHACHA20_POLY1305_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", - "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", - "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", - "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", - "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", - "TLS_ECDHE_RSA_WITH_RC4_128_SHA", - "TLS_FALLBACK_SCSV", - "TLS_RSA_WITH_3DES_EDE_CBC_SHA", - "TLS_RSA_WITH_AES_128_CBC_SHA", - "TLS_RSA_WITH_AES_128_CBC_SHA256", - "TLS_RSA_WITH_AES_128_GCM_SHA256", - "TLS_RSA_WITH_AES_256_CBC_SHA", - "TLS_RSA_WITH_AES_256_GCM_SHA384", - "TLS_RSA_WITH_RC4_128_SHA", - "VerifyClientCertIfGiven", - "VersionName", - "VersionSSL30", - "VersionTLS10", - "VersionTLS11", - "VersionTLS12", - "VersionTLS13", - "X25519", - "X509KeyPair", - }, - "crypto/x509": { - "CANotAuthorizedForExtKeyUsage", - "CANotAuthorizedForThisName", - "CertPool", - "Certificate", - "CertificateInvalidError", - "CertificateRequest", - "ConstraintViolationError", - "CreateCertificate", - "CreateCertificateRequest", - "CreateRevocationList", - "DSA", - "DSAWithSHA1", - "DSAWithSHA256", - "DecryptPEMBlock", - "ECDSA", - "ECDSAWithSHA1", - "ECDSAWithSHA256", - "ECDSAWithSHA384", - "ECDSAWithSHA512", - "Ed25519", - "EncryptPEMBlock", - "ErrUnsupportedAlgorithm", - "Expired", - "ExtKeyUsage", - "ExtKeyUsageAny", - "ExtKeyUsageClientAuth", - "ExtKeyUsageCodeSigning", - "ExtKeyUsageEmailProtection", - "ExtKeyUsageIPSECEndSystem", - "ExtKeyUsageIPSECTunnel", - "ExtKeyUsageIPSECUser", - "ExtKeyUsageMicrosoftCommercialCodeSigning", - "ExtKeyUsageMicrosoftKernelCodeSigning", - "ExtKeyUsageMicrosoftServerGatedCrypto", - "ExtKeyUsageNetscapeServerGatedCrypto", - "ExtKeyUsageOCSPSigning", - "ExtKeyUsageServerAuth", - "ExtKeyUsageTimeStamping", - "HostnameError", - "IncompatibleUsage", - "IncorrectPasswordError", - "InsecureAlgorithmError", - "InvalidReason", - "IsEncryptedPEMBlock", - "KeyUsage", - "KeyUsageCRLSign", - "KeyUsageCertSign", - "KeyUsageContentCommitment", - "KeyUsageDataEncipherment", - "KeyUsageDecipherOnly", - "KeyUsageDigitalSignature", - "KeyUsageEncipherOnly", - "KeyUsageKeyAgreement", - "KeyUsageKeyEncipherment", - "MD2WithRSA", - "MD5WithRSA", - "MarshalECPrivateKey", - "MarshalPKCS1PrivateKey", - "MarshalPKCS1PublicKey", - "MarshalPKCS8PrivateKey", - "MarshalPKIXPublicKey", - "NameConstraintsWithoutSANs", - "NameMismatch", - "NewCertPool", - "NotAuthorizedToSign", - "OID", - "OIDFromInts", - "PEMCipher", - "PEMCipher3DES", - "PEMCipherAES128", - "PEMCipherAES192", - "PEMCipherAES256", - "PEMCipherDES", - "ParseCRL", - "ParseCertificate", - "ParseCertificateRequest", - "ParseCertificates", - "ParseDERCRL", - "ParseECPrivateKey", - "ParsePKCS1PrivateKey", - "ParsePKCS1PublicKey", - "ParsePKCS8PrivateKey", - "ParsePKIXPublicKey", - "ParseRevocationList", - "PublicKeyAlgorithm", - "PureEd25519", - "RSA", - "RevocationList", - "RevocationListEntry", - "SHA1WithRSA", - "SHA256WithRSA", - "SHA256WithRSAPSS", - "SHA384WithRSA", - "SHA384WithRSAPSS", - "SHA512WithRSA", - "SHA512WithRSAPSS", - "SetFallbackRoots", - "SignatureAlgorithm", - "SystemCertPool", - "SystemRootsError", - "TooManyConstraints", - "TooManyIntermediates", - "UnconstrainedName", - "UnhandledCriticalExtension", - "UnknownAuthorityError", - "UnknownPublicKeyAlgorithm", - "UnknownSignatureAlgorithm", - "VerifyOptions", - }, - "crypto/x509/pkix": { - "AlgorithmIdentifier", - "AttributeTypeAndValue", - "AttributeTypeAndValueSET", - "CertificateList", - "Extension", - "Name", - "RDNSequence", - "RelativeDistinguishedNameSET", - "RevokedCertificate", - "TBSCertificateList", - }, - "database/sql": { - "ColumnType", - "Conn", - "DB", - "DBStats", - "Drivers", - "ErrConnDone", - "ErrNoRows", - "ErrTxDone", - "IsolationLevel", - "LevelDefault", - "LevelLinearizable", - "LevelReadCommitted", - "LevelReadUncommitted", - "LevelRepeatableRead", - "LevelSerializable", - "LevelSnapshot", - "LevelWriteCommitted", - "Named", - "NamedArg", - "Null", - "NullBool", - "NullByte", - "NullFloat64", - "NullInt16", - "NullInt32", - "NullInt64", - "NullString", - "NullTime", - "Open", - "OpenDB", - "Out", - "RawBytes", - "Register", - "Result", - "Row", - "Rows", - "Scanner", - "Stmt", - "Tx", - "TxOptions", - }, - "database/sql/driver": { - "Bool", - "ColumnConverter", - "Conn", - "ConnBeginTx", - "ConnPrepareContext", - "Connector", - "DefaultParameterConverter", - "Driver", - "DriverContext", - "ErrBadConn", - "ErrRemoveArgument", - "ErrSkip", - "Execer", - "ExecerContext", - "Int32", - "IsScanValue", - "IsValue", - "IsolationLevel", - "NamedValue", - "NamedValueChecker", - "NotNull", - "Null", - "Pinger", - "Queryer", - "QueryerContext", - "Result", - "ResultNoRows", - "Rows", - "RowsAffected", - "RowsColumnTypeDatabaseTypeName", - "RowsColumnTypeLength", - "RowsColumnTypeNullable", - "RowsColumnTypePrecisionScale", - "RowsColumnTypeScanType", - "RowsNextResultSet", - "SessionResetter", - "Stmt", - "StmtExecContext", - "StmtQueryContext", - "String", - "Tx", - "TxOptions", - "Validator", - "Value", - "ValueConverter", - "Valuer", - }, - "debug/buildinfo": { - "BuildInfo", - "Read", - "ReadFile", - }, - "debug/dwarf": { - "AddrType", - "ArrayType", - "Attr", - "AttrAbstractOrigin", - "AttrAccessibility", - "AttrAddrBase", - "AttrAddrClass", - "AttrAlignment", - "AttrAllocated", - "AttrArtificial", - "AttrAssociated", - "AttrBaseTypes", - "AttrBinaryScale", - "AttrBitOffset", - "AttrBitSize", - "AttrByteSize", - "AttrCallAllCalls", - "AttrCallAllSourceCalls", - "AttrCallAllTailCalls", - "AttrCallColumn", - "AttrCallDataLocation", - "AttrCallDataValue", - "AttrCallFile", - "AttrCallLine", - "AttrCallOrigin", - "AttrCallPC", - "AttrCallParameter", - "AttrCallReturnPC", - "AttrCallTailCall", - "AttrCallTarget", - "AttrCallTargetClobbered", - "AttrCallValue", - "AttrCalling", - "AttrCommonRef", - "AttrCompDir", - "AttrConstExpr", - "AttrConstValue", - "AttrContainingType", - "AttrCount", - "AttrDataBitOffset", - "AttrDataLocation", - "AttrDataMemberLoc", - "AttrDecimalScale", - "AttrDecimalSign", - "AttrDeclColumn", - "AttrDeclFile", - "AttrDeclLine", - "AttrDeclaration", - "AttrDefaultValue", - "AttrDefaulted", - "AttrDeleted", - "AttrDescription", - "AttrDigitCount", - "AttrDiscr", - "AttrDiscrList", - "AttrDiscrValue", - "AttrDwoName", - "AttrElemental", - "AttrEncoding", - "AttrEndianity", - "AttrEntrypc", - "AttrEnumClass", - "AttrExplicit", - "AttrExportSymbols", - "AttrExtension", - "AttrExternal", - "AttrFrameBase", - "AttrFriend", - "AttrHighpc", - "AttrIdentifierCase", - "AttrImport", - "AttrInline", - "AttrIsOptional", - "AttrLanguage", - "AttrLinkageName", - "AttrLocation", - "AttrLoclistsBase", - "AttrLowerBound", - "AttrLowpc", - "AttrMacroInfo", - "AttrMacros", - "AttrMainSubprogram", - "AttrMutable", - "AttrName", - "AttrNamelistItem", - "AttrNoreturn", - "AttrObjectPointer", - "AttrOrdering", - "AttrPictureString", - "AttrPriority", - "AttrProducer", - "AttrPrototyped", - "AttrPure", - "AttrRanges", - "AttrRank", - "AttrRecursive", - "AttrReference", - "AttrReturnAddr", - "AttrRnglistsBase", - "AttrRvalueReference", - "AttrSegment", - "AttrSibling", - "AttrSignature", - "AttrSmall", - "AttrSpecification", - "AttrStartScope", - "AttrStaticLink", - "AttrStmtList", - "AttrStrOffsetsBase", - "AttrStride", - "AttrStrideSize", - "AttrStringLength", - "AttrStringLengthBitSize", - "AttrStringLengthByteSize", - "AttrThreadsScaled", - "AttrTrampoline", - "AttrType", - "AttrUpperBound", - "AttrUseLocation", - "AttrUseUTF8", - "AttrVarParam", - "AttrVirtuality", - "AttrVisibility", - "AttrVtableElemLoc", - "BasicType", - "BoolType", - "CharType", - "Class", - "ClassAddrPtr", - "ClassAddress", - "ClassBlock", - "ClassConstant", - "ClassExprLoc", - "ClassFlag", - "ClassLinePtr", - "ClassLocList", - "ClassLocListPtr", - "ClassMacPtr", - "ClassRangeListPtr", - "ClassReference", - "ClassReferenceAlt", - "ClassReferenceSig", - "ClassRngList", - "ClassRngListsPtr", - "ClassStrOffsetsPtr", - "ClassString", - "ClassStringAlt", - "ClassUnknown", - "CommonType", - "ComplexType", - "Data", - "DecodeError", - "DotDotDotType", - "Entry", - "EnumType", - "EnumValue", - "ErrUnknownPC", - "Field", - "FloatType", - "FuncType", - "IntType", - "LineEntry", - "LineFile", - "LineReader", - "LineReaderPos", - "New", - "Offset", - "PtrType", - "QualType", - "Reader", - "StructField", - "StructType", - "Tag", - "TagAccessDeclaration", - "TagArrayType", - "TagAtomicType", - "TagBaseType", - "TagCallSite", - "TagCallSiteParameter", - "TagCatchDwarfBlock", - "TagClassType", - "TagCoarrayType", - "TagCommonDwarfBlock", - "TagCommonInclusion", - "TagCompileUnit", - "TagCondition", - "TagConstType", - "TagConstant", - "TagDwarfProcedure", - "TagDynamicType", - "TagEntryPoint", - "TagEnumerationType", - "TagEnumerator", - "TagFileType", - "TagFormalParameter", - "TagFriend", - "TagGenericSubrange", - "TagImmutableType", - "TagImportedDeclaration", - "TagImportedModule", - "TagImportedUnit", - "TagInheritance", - "TagInlinedSubroutine", - "TagInterfaceType", - "TagLabel", - "TagLexDwarfBlock", - "TagMember", - "TagModule", - "TagMutableType", - "TagNamelist", - "TagNamelistItem", - "TagNamespace", - "TagPackedType", - "TagPartialUnit", - "TagPointerType", - "TagPtrToMemberType", - "TagReferenceType", - "TagRestrictType", - "TagRvalueReferenceType", - "TagSetType", - "TagSharedType", - "TagSkeletonUnit", - "TagStringType", - "TagStructType", - "TagSubprogram", - "TagSubrangeType", - "TagSubroutineType", - "TagTemplateAlias", - "TagTemplateTypeParameter", - "TagTemplateValueParameter", - "TagThrownType", - "TagTryDwarfBlock", - "TagTypeUnit", - "TagTypedef", - "TagUnionType", - "TagUnspecifiedParameters", - "TagUnspecifiedType", - "TagVariable", - "TagVariant", - "TagVariantPart", - "TagVolatileType", - "TagWithStmt", - "Type", - "TypedefType", - "UcharType", - "UintType", - "UnspecifiedType", - "UnsupportedType", - "VoidType", - }, - "debug/elf": { - "ARM_MAGIC_TRAMP_NUMBER", - "COMPRESS_HIOS", - "COMPRESS_HIPROC", - "COMPRESS_LOOS", - "COMPRESS_LOPROC", - "COMPRESS_ZLIB", - "COMPRESS_ZSTD", - "Chdr32", - "Chdr64", - "Class", - "CompressionType", - "DF_1_CONFALT", - "DF_1_DIRECT", - "DF_1_DISPRELDNE", - "DF_1_DISPRELPND", - "DF_1_EDITED", - "DF_1_ENDFILTEE", - "DF_1_GLOBAL", - "DF_1_GLOBAUDIT", - "DF_1_GROUP", - "DF_1_IGNMULDEF", - "DF_1_INITFIRST", - "DF_1_INTERPOSE", - "DF_1_KMOD", - "DF_1_LOADFLTR", - "DF_1_NOCOMMON", - "DF_1_NODEFLIB", - "DF_1_NODELETE", - "DF_1_NODIRECT", - "DF_1_NODUMP", - "DF_1_NOHDR", - "DF_1_NOKSYMS", - "DF_1_NOOPEN", - "DF_1_NORELOC", - "DF_1_NOW", - "DF_1_ORIGIN", - "DF_1_PIE", - "DF_1_SINGLETON", - "DF_1_STUB", - "DF_1_SYMINTPOSE", - "DF_1_TRANS", - "DF_1_WEAKFILTER", - "DF_BIND_NOW", - "DF_ORIGIN", - "DF_STATIC_TLS", - "DF_SYMBOLIC", - "DF_TEXTREL", - "DT_ADDRRNGHI", - "DT_ADDRRNGLO", - "DT_AUDIT", - "DT_AUXILIARY", - "DT_BIND_NOW", - "DT_CHECKSUM", - "DT_CONFIG", - "DT_DEBUG", - "DT_DEPAUDIT", - "DT_ENCODING", - "DT_FEATURE", - "DT_FILTER", - "DT_FINI", - "DT_FINI_ARRAY", - "DT_FINI_ARRAYSZ", - "DT_FLAGS", - "DT_FLAGS_1", - "DT_GNU_CONFLICT", - "DT_GNU_CONFLICTSZ", - "DT_GNU_HASH", - "DT_GNU_LIBLIST", - "DT_GNU_LIBLISTSZ", - "DT_GNU_PRELINKED", - "DT_HASH", - "DT_HIOS", - "DT_HIPROC", - "DT_INIT", - "DT_INIT_ARRAY", - "DT_INIT_ARRAYSZ", - "DT_JMPREL", - "DT_LOOS", - "DT_LOPROC", - "DT_MIPS_AUX_DYNAMIC", - "DT_MIPS_BASE_ADDRESS", - "DT_MIPS_COMPACT_SIZE", - "DT_MIPS_CONFLICT", - "DT_MIPS_CONFLICTNO", - "DT_MIPS_CXX_FLAGS", - "DT_MIPS_DELTA_CLASS", - "DT_MIPS_DELTA_CLASSSYM", - "DT_MIPS_DELTA_CLASSSYM_NO", - "DT_MIPS_DELTA_CLASS_NO", - "DT_MIPS_DELTA_INSTANCE", - "DT_MIPS_DELTA_INSTANCE_NO", - "DT_MIPS_DELTA_RELOC", - "DT_MIPS_DELTA_RELOC_NO", - "DT_MIPS_DELTA_SYM", - "DT_MIPS_DELTA_SYM_NO", - "DT_MIPS_DYNSTR_ALIGN", - "DT_MIPS_FLAGS", - "DT_MIPS_GOTSYM", - "DT_MIPS_GP_VALUE", - "DT_MIPS_HIDDEN_GOTIDX", - "DT_MIPS_HIPAGENO", - "DT_MIPS_ICHECKSUM", - "DT_MIPS_INTERFACE", - "DT_MIPS_INTERFACE_SIZE", - "DT_MIPS_IVERSION", - "DT_MIPS_LIBLIST", - "DT_MIPS_LIBLISTNO", - "DT_MIPS_LOCALPAGE_GOTIDX", - "DT_MIPS_LOCAL_GOTIDX", - "DT_MIPS_LOCAL_GOTNO", - "DT_MIPS_MSYM", - "DT_MIPS_OPTIONS", - "DT_MIPS_PERF_SUFFIX", - "DT_MIPS_PIXIE_INIT", - "DT_MIPS_PLTGOT", - "DT_MIPS_PROTECTED_GOTIDX", - "DT_MIPS_RLD_MAP", - "DT_MIPS_RLD_MAP_REL", - "DT_MIPS_RLD_TEXT_RESOLVE_ADDR", - "DT_MIPS_RLD_VERSION", - "DT_MIPS_RWPLT", - "DT_MIPS_SYMBOL_LIB", - "DT_MIPS_SYMTABNO", - "DT_MIPS_TIME_STAMP", - "DT_MIPS_UNREFEXTNO", - "DT_MOVEENT", - "DT_MOVESZ", - "DT_MOVETAB", - "DT_NEEDED", - "DT_NULL", - "DT_PLTGOT", - "DT_PLTPAD", - "DT_PLTPADSZ", - "DT_PLTREL", - "DT_PLTRELSZ", - "DT_POSFLAG_1", - "DT_PPC64_GLINK", - "DT_PPC64_OPD", - "DT_PPC64_OPDSZ", - "DT_PPC64_OPT", - "DT_PPC_GOT", - "DT_PPC_OPT", - "DT_PREINIT_ARRAY", - "DT_PREINIT_ARRAYSZ", - "DT_REL", - "DT_RELA", - "DT_RELACOUNT", - "DT_RELAENT", - "DT_RELASZ", - "DT_RELCOUNT", - "DT_RELENT", - "DT_RELSZ", - "DT_RPATH", - "DT_RUNPATH", - "DT_SONAME", - "DT_SPARC_REGISTER", - "DT_STRSZ", - "DT_STRTAB", - "DT_SYMBOLIC", - "DT_SYMENT", - "DT_SYMINENT", - "DT_SYMINFO", - "DT_SYMINSZ", - "DT_SYMTAB", - "DT_SYMTAB_SHNDX", - "DT_TEXTREL", - "DT_TLSDESC_GOT", - "DT_TLSDESC_PLT", - "DT_USED", - "DT_VALRNGHI", - "DT_VALRNGLO", - "DT_VERDEF", - "DT_VERDEFNUM", - "DT_VERNEED", - "DT_VERNEEDNUM", - "DT_VERSYM", - "Data", - "Dyn32", - "Dyn64", - "DynFlag", - "DynFlag1", - "DynTag", - "EI_ABIVERSION", - "EI_CLASS", - "EI_DATA", - "EI_NIDENT", - "EI_OSABI", - "EI_PAD", - "EI_VERSION", - "ELFCLASS32", - "ELFCLASS64", - "ELFCLASSNONE", - "ELFDATA2LSB", - "ELFDATA2MSB", - "ELFDATANONE", - "ELFMAG", - "ELFOSABI_86OPEN", - "ELFOSABI_AIX", - "ELFOSABI_ARM", - "ELFOSABI_AROS", - "ELFOSABI_CLOUDABI", - "ELFOSABI_FENIXOS", - "ELFOSABI_FREEBSD", - "ELFOSABI_HPUX", - "ELFOSABI_HURD", - "ELFOSABI_IRIX", - "ELFOSABI_LINUX", - "ELFOSABI_MODESTO", - "ELFOSABI_NETBSD", - "ELFOSABI_NONE", - "ELFOSABI_NSK", - "ELFOSABI_OPENBSD", - "ELFOSABI_OPENVMS", - "ELFOSABI_SOLARIS", - "ELFOSABI_STANDALONE", - "ELFOSABI_TRU64", - "EM_386", - "EM_486", - "EM_56800EX", - "EM_68HC05", - "EM_68HC08", - "EM_68HC11", - "EM_68HC12", - "EM_68HC16", - "EM_68K", - "EM_78KOR", - "EM_8051", - "EM_860", - "EM_88K", - "EM_960", - "EM_AARCH64", - "EM_ALPHA", - "EM_ALPHA_STD", - "EM_ALTERA_NIOS2", - "EM_AMDGPU", - "EM_ARC", - "EM_ARCA", - "EM_ARC_COMPACT", - "EM_ARC_COMPACT2", - "EM_ARM", - "EM_AVR", - "EM_AVR32", - "EM_BA1", - "EM_BA2", - "EM_BLACKFIN", - "EM_BPF", - "EM_C166", - "EM_CDP", - "EM_CE", - "EM_CLOUDSHIELD", - "EM_COGE", - "EM_COLDFIRE", - "EM_COOL", - "EM_COREA_1ST", - "EM_COREA_2ND", - "EM_CR", - "EM_CR16", - "EM_CRAYNV2", - "EM_CRIS", - "EM_CRX", - "EM_CSR_KALIMBA", - "EM_CUDA", - "EM_CYPRESS_M8C", - "EM_D10V", - "EM_D30V", - "EM_DSP24", - "EM_DSPIC30F", - "EM_DXP", - "EM_ECOG1", - "EM_ECOG16", - "EM_ECOG1X", - "EM_ECOG2", - "EM_ETPU", - "EM_EXCESS", - "EM_F2MC16", - "EM_FIREPATH", - "EM_FR20", - "EM_FR30", - "EM_FT32", - "EM_FX66", - "EM_H8S", - "EM_H8_300", - "EM_H8_300H", - "EM_H8_500", - "EM_HUANY", - "EM_IA_64", - "EM_INTEL205", - "EM_INTEL206", - "EM_INTEL207", - "EM_INTEL208", - "EM_INTEL209", - "EM_IP2K", - "EM_JAVELIN", - "EM_K10M", - "EM_KM32", - "EM_KMX16", - "EM_KMX32", - "EM_KMX8", - "EM_KVARC", - "EM_L10M", - "EM_LANAI", - "EM_LATTICEMICO32", - "EM_LOONGARCH", - "EM_M16C", - "EM_M32", - "EM_M32C", - "EM_M32R", - "EM_MANIK", - "EM_MAX", - "EM_MAXQ30", - "EM_MCHP_PIC", - "EM_MCST_ELBRUS", - "EM_ME16", - "EM_METAG", - "EM_MICROBLAZE", - "EM_MIPS", - "EM_MIPS_RS3_LE", - "EM_MIPS_RS4_BE", - "EM_MIPS_X", - "EM_MMA", - "EM_MMDSP_PLUS", - "EM_MMIX", - "EM_MN10200", - "EM_MN10300", - "EM_MOXIE", - "EM_MSP430", - "EM_NCPU", - "EM_NDR1", - "EM_NDS32", - "EM_NONE", - "EM_NORC", - "EM_NS32K", - "EM_OPEN8", - "EM_OPENRISC", - "EM_PARISC", - "EM_PCP", - "EM_PDP10", - "EM_PDP11", - "EM_PDSP", - "EM_PJ", - "EM_PPC", - "EM_PPC64", - "EM_PRISM", - "EM_QDSP6", - "EM_R32C", - "EM_RCE", - "EM_RH32", - "EM_RISCV", - "EM_RL78", - "EM_RS08", - "EM_RX", - "EM_S370", - "EM_S390", - "EM_SCORE7", - "EM_SEP", - "EM_SE_C17", - "EM_SE_C33", - "EM_SH", - "EM_SHARC", - "EM_SLE9X", - "EM_SNP1K", - "EM_SPARC", - "EM_SPARC32PLUS", - "EM_SPARCV9", - "EM_ST100", - "EM_ST19", - "EM_ST200", - "EM_ST7", - "EM_ST9PLUS", - "EM_STARCORE", - "EM_STM8", - "EM_STXP7X", - "EM_SVX", - "EM_TILE64", - "EM_TILEGX", - "EM_TILEPRO", - "EM_TINYJ", - "EM_TI_ARP32", - "EM_TI_C2000", - "EM_TI_C5500", - "EM_TI_C6000", - "EM_TI_PRU", - "EM_TMM_GPP", - "EM_TPC", - "EM_TRICORE", - "EM_TRIMEDIA", - "EM_TSK3000", - "EM_UNICORE", - "EM_V800", - "EM_V850", - "EM_VAX", - "EM_VIDEOCORE", - "EM_VIDEOCORE3", - "EM_VIDEOCORE5", - "EM_VISIUM", - "EM_VPP500", - "EM_X86_64", - "EM_XCORE", - "EM_XGATE", - "EM_XIMO16", - "EM_XTENSA", - "EM_Z80", - "EM_ZSP", - "ET_CORE", - "ET_DYN", - "ET_EXEC", - "ET_HIOS", - "ET_HIPROC", - "ET_LOOS", - "ET_LOPROC", - "ET_NONE", - "ET_REL", - "EV_CURRENT", - "EV_NONE", - "ErrNoSymbols", - "File", - "FileHeader", - "FormatError", - "Header32", - "Header64", - "ImportedSymbol", - "Machine", - "NT_FPREGSET", - "NT_PRPSINFO", - "NT_PRSTATUS", - "NType", - "NewFile", - "OSABI", - "Open", - "PF_MASKOS", - "PF_MASKPROC", - "PF_R", - "PF_W", - "PF_X", - "PT_AARCH64_ARCHEXT", - "PT_AARCH64_UNWIND", - "PT_ARM_ARCHEXT", - "PT_ARM_EXIDX", - "PT_DYNAMIC", - "PT_GNU_EH_FRAME", - "PT_GNU_MBIND_HI", - "PT_GNU_MBIND_LO", - "PT_GNU_PROPERTY", - "PT_GNU_RELRO", - "PT_GNU_STACK", - "PT_HIOS", - "PT_HIPROC", - "PT_INTERP", - "PT_LOAD", - "PT_LOOS", - "PT_LOPROC", - "PT_MIPS_ABIFLAGS", - "PT_MIPS_OPTIONS", - "PT_MIPS_REGINFO", - "PT_MIPS_RTPROC", - "PT_NOTE", - "PT_NULL", - "PT_OPENBSD_BOOTDATA", - "PT_OPENBSD_RANDOMIZE", - "PT_OPENBSD_WXNEEDED", - "PT_PAX_FLAGS", - "PT_PHDR", - "PT_S390_PGSTE", - "PT_SHLIB", - "PT_SUNWSTACK", - "PT_SUNW_EH_FRAME", - "PT_TLS", - "Prog", - "Prog32", - "Prog64", - "ProgFlag", - "ProgHeader", - "ProgType", - "R_386", - "R_386_16", - "R_386_32", - "R_386_32PLT", - "R_386_8", - "R_386_COPY", - "R_386_GLOB_DAT", - "R_386_GOT32", - "R_386_GOT32X", - "R_386_GOTOFF", - "R_386_GOTPC", - "R_386_IRELATIVE", - "R_386_JMP_SLOT", - "R_386_NONE", - "R_386_PC16", - "R_386_PC32", - "R_386_PC8", - "R_386_PLT32", - "R_386_RELATIVE", - "R_386_SIZE32", - "R_386_TLS_DESC", - "R_386_TLS_DESC_CALL", - "R_386_TLS_DTPMOD32", - "R_386_TLS_DTPOFF32", - "R_386_TLS_GD", - "R_386_TLS_GD_32", - "R_386_TLS_GD_CALL", - "R_386_TLS_GD_POP", - "R_386_TLS_GD_PUSH", - "R_386_TLS_GOTDESC", - "R_386_TLS_GOTIE", - "R_386_TLS_IE", - "R_386_TLS_IE_32", - "R_386_TLS_LDM", - "R_386_TLS_LDM_32", - "R_386_TLS_LDM_CALL", - "R_386_TLS_LDM_POP", - "R_386_TLS_LDM_PUSH", - "R_386_TLS_LDO_32", - "R_386_TLS_LE", - "R_386_TLS_LE_32", - "R_386_TLS_TPOFF", - "R_386_TLS_TPOFF32", - "R_390", - "R_390_12", - "R_390_16", - "R_390_20", - "R_390_32", - "R_390_64", - "R_390_8", - "R_390_COPY", - "R_390_GLOB_DAT", - "R_390_GOT12", - "R_390_GOT16", - "R_390_GOT20", - "R_390_GOT32", - "R_390_GOT64", - "R_390_GOTENT", - "R_390_GOTOFF", - "R_390_GOTOFF16", - "R_390_GOTOFF64", - "R_390_GOTPC", - "R_390_GOTPCDBL", - "R_390_GOTPLT12", - "R_390_GOTPLT16", - "R_390_GOTPLT20", - "R_390_GOTPLT32", - "R_390_GOTPLT64", - "R_390_GOTPLTENT", - "R_390_GOTPLTOFF16", - "R_390_GOTPLTOFF32", - "R_390_GOTPLTOFF64", - "R_390_JMP_SLOT", - "R_390_NONE", - "R_390_PC16", - "R_390_PC16DBL", - "R_390_PC32", - "R_390_PC32DBL", - "R_390_PC64", - "R_390_PLT16DBL", - "R_390_PLT32", - "R_390_PLT32DBL", - "R_390_PLT64", - "R_390_RELATIVE", - "R_390_TLS_DTPMOD", - "R_390_TLS_DTPOFF", - "R_390_TLS_GD32", - "R_390_TLS_GD64", - "R_390_TLS_GDCALL", - "R_390_TLS_GOTIE12", - "R_390_TLS_GOTIE20", - "R_390_TLS_GOTIE32", - "R_390_TLS_GOTIE64", - "R_390_TLS_IE32", - "R_390_TLS_IE64", - "R_390_TLS_IEENT", - "R_390_TLS_LDCALL", - "R_390_TLS_LDM32", - "R_390_TLS_LDM64", - "R_390_TLS_LDO32", - "R_390_TLS_LDO64", - "R_390_TLS_LE32", - "R_390_TLS_LE64", - "R_390_TLS_LOAD", - "R_390_TLS_TPOFF", - "R_AARCH64", - "R_AARCH64_ABS16", - "R_AARCH64_ABS32", - "R_AARCH64_ABS64", - "R_AARCH64_ADD_ABS_LO12_NC", - "R_AARCH64_ADR_GOT_PAGE", - "R_AARCH64_ADR_PREL_LO21", - "R_AARCH64_ADR_PREL_PG_HI21", - "R_AARCH64_ADR_PREL_PG_HI21_NC", - "R_AARCH64_CALL26", - "R_AARCH64_CONDBR19", - "R_AARCH64_COPY", - "R_AARCH64_GLOB_DAT", - "R_AARCH64_GOT_LD_PREL19", - "R_AARCH64_IRELATIVE", - "R_AARCH64_JUMP26", - "R_AARCH64_JUMP_SLOT", - "R_AARCH64_LD64_GOTOFF_LO15", - "R_AARCH64_LD64_GOTPAGE_LO15", - "R_AARCH64_LD64_GOT_LO12_NC", - "R_AARCH64_LDST128_ABS_LO12_NC", - "R_AARCH64_LDST16_ABS_LO12_NC", - "R_AARCH64_LDST32_ABS_LO12_NC", - "R_AARCH64_LDST64_ABS_LO12_NC", - "R_AARCH64_LDST8_ABS_LO12_NC", - "R_AARCH64_LD_PREL_LO19", - "R_AARCH64_MOVW_SABS_G0", - "R_AARCH64_MOVW_SABS_G1", - "R_AARCH64_MOVW_SABS_G2", - "R_AARCH64_MOVW_UABS_G0", - "R_AARCH64_MOVW_UABS_G0_NC", - "R_AARCH64_MOVW_UABS_G1", - "R_AARCH64_MOVW_UABS_G1_NC", - "R_AARCH64_MOVW_UABS_G2", - "R_AARCH64_MOVW_UABS_G2_NC", - "R_AARCH64_MOVW_UABS_G3", - "R_AARCH64_NONE", - "R_AARCH64_NULL", - "R_AARCH64_P32_ABS16", - "R_AARCH64_P32_ABS32", - "R_AARCH64_P32_ADD_ABS_LO12_NC", - "R_AARCH64_P32_ADR_GOT_PAGE", - "R_AARCH64_P32_ADR_PREL_LO21", - "R_AARCH64_P32_ADR_PREL_PG_HI21", - "R_AARCH64_P32_CALL26", - "R_AARCH64_P32_CONDBR19", - "R_AARCH64_P32_COPY", - "R_AARCH64_P32_GLOB_DAT", - "R_AARCH64_P32_GOT_LD_PREL19", - "R_AARCH64_P32_IRELATIVE", - "R_AARCH64_P32_JUMP26", - "R_AARCH64_P32_JUMP_SLOT", - "R_AARCH64_P32_LD32_GOT_LO12_NC", - "R_AARCH64_P32_LDST128_ABS_LO12_NC", - "R_AARCH64_P32_LDST16_ABS_LO12_NC", - "R_AARCH64_P32_LDST32_ABS_LO12_NC", - "R_AARCH64_P32_LDST64_ABS_LO12_NC", - "R_AARCH64_P32_LDST8_ABS_LO12_NC", - "R_AARCH64_P32_LD_PREL_LO19", - "R_AARCH64_P32_MOVW_SABS_G0", - "R_AARCH64_P32_MOVW_UABS_G0", - "R_AARCH64_P32_MOVW_UABS_G0_NC", - "R_AARCH64_P32_MOVW_UABS_G1", - "R_AARCH64_P32_PREL16", - "R_AARCH64_P32_PREL32", - "R_AARCH64_P32_RELATIVE", - "R_AARCH64_P32_TLSDESC", - "R_AARCH64_P32_TLSDESC_ADD_LO12_NC", - "R_AARCH64_P32_TLSDESC_ADR_PAGE21", - "R_AARCH64_P32_TLSDESC_ADR_PREL21", - "R_AARCH64_P32_TLSDESC_CALL", - "R_AARCH64_P32_TLSDESC_LD32_LO12_NC", - "R_AARCH64_P32_TLSDESC_LD_PREL19", - "R_AARCH64_P32_TLSGD_ADD_LO12_NC", - "R_AARCH64_P32_TLSGD_ADR_PAGE21", - "R_AARCH64_P32_TLSIE_ADR_GOTTPREL_PAGE21", - "R_AARCH64_P32_TLSIE_LD32_GOTTPREL_LO12_NC", - "R_AARCH64_P32_TLSIE_LD_GOTTPREL_PREL19", - "R_AARCH64_P32_TLSLE_ADD_TPREL_HI12", - "R_AARCH64_P32_TLSLE_ADD_TPREL_LO12", - "R_AARCH64_P32_TLSLE_ADD_TPREL_LO12_NC", - "R_AARCH64_P32_TLSLE_MOVW_TPREL_G0", - "R_AARCH64_P32_TLSLE_MOVW_TPREL_G0_NC", - "R_AARCH64_P32_TLSLE_MOVW_TPREL_G1", - "R_AARCH64_P32_TLS_DTPMOD", - "R_AARCH64_P32_TLS_DTPREL", - "R_AARCH64_P32_TLS_TPREL", - "R_AARCH64_P32_TSTBR14", - "R_AARCH64_PREL16", - "R_AARCH64_PREL32", - "R_AARCH64_PREL64", - "R_AARCH64_RELATIVE", - "R_AARCH64_TLSDESC", - "R_AARCH64_TLSDESC_ADD", - "R_AARCH64_TLSDESC_ADD_LO12_NC", - "R_AARCH64_TLSDESC_ADR_PAGE21", - "R_AARCH64_TLSDESC_ADR_PREL21", - "R_AARCH64_TLSDESC_CALL", - "R_AARCH64_TLSDESC_LD64_LO12_NC", - "R_AARCH64_TLSDESC_LDR", - "R_AARCH64_TLSDESC_LD_PREL19", - "R_AARCH64_TLSDESC_OFF_G0_NC", - "R_AARCH64_TLSDESC_OFF_G1", - "R_AARCH64_TLSGD_ADD_LO12_NC", - "R_AARCH64_TLSGD_ADR_PAGE21", - "R_AARCH64_TLSGD_ADR_PREL21", - "R_AARCH64_TLSGD_MOVW_G0_NC", - "R_AARCH64_TLSGD_MOVW_G1", - "R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21", - "R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC", - "R_AARCH64_TLSIE_LD_GOTTPREL_PREL19", - "R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC", - "R_AARCH64_TLSIE_MOVW_GOTTPREL_G1", - "R_AARCH64_TLSLD_ADR_PAGE21", - "R_AARCH64_TLSLD_ADR_PREL21", - "R_AARCH64_TLSLD_LDST128_DTPREL_LO12", - "R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC", - "R_AARCH64_TLSLE_ADD_TPREL_HI12", - "R_AARCH64_TLSLE_ADD_TPREL_LO12", - "R_AARCH64_TLSLE_ADD_TPREL_LO12_NC", - "R_AARCH64_TLSLE_LDST128_TPREL_LO12", - "R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC", - "R_AARCH64_TLSLE_MOVW_TPREL_G0", - "R_AARCH64_TLSLE_MOVW_TPREL_G0_NC", - "R_AARCH64_TLSLE_MOVW_TPREL_G1", - "R_AARCH64_TLSLE_MOVW_TPREL_G1_NC", - "R_AARCH64_TLSLE_MOVW_TPREL_G2", - "R_AARCH64_TLS_DTPMOD64", - "R_AARCH64_TLS_DTPREL64", - "R_AARCH64_TLS_TPREL64", - "R_AARCH64_TSTBR14", - "R_ALPHA", - "R_ALPHA_BRADDR", - "R_ALPHA_COPY", - "R_ALPHA_GLOB_DAT", - "R_ALPHA_GPDISP", - "R_ALPHA_GPREL32", - "R_ALPHA_GPRELHIGH", - "R_ALPHA_GPRELLOW", - "R_ALPHA_GPVALUE", - "R_ALPHA_HINT", - "R_ALPHA_IMMED_BR_HI32", - "R_ALPHA_IMMED_GP_16", - "R_ALPHA_IMMED_GP_HI32", - "R_ALPHA_IMMED_LO32", - "R_ALPHA_IMMED_SCN_HI32", - "R_ALPHA_JMP_SLOT", - "R_ALPHA_LITERAL", - "R_ALPHA_LITUSE", - "R_ALPHA_NONE", - "R_ALPHA_OP_PRSHIFT", - "R_ALPHA_OP_PSUB", - "R_ALPHA_OP_PUSH", - "R_ALPHA_OP_STORE", - "R_ALPHA_REFLONG", - "R_ALPHA_REFQUAD", - "R_ALPHA_RELATIVE", - "R_ALPHA_SREL16", - "R_ALPHA_SREL32", - "R_ALPHA_SREL64", - "R_ARM", - "R_ARM_ABS12", - "R_ARM_ABS16", - "R_ARM_ABS32", - "R_ARM_ABS32_NOI", - "R_ARM_ABS8", - "R_ARM_ALU_PCREL_15_8", - "R_ARM_ALU_PCREL_23_15", - "R_ARM_ALU_PCREL_7_0", - "R_ARM_ALU_PC_G0", - "R_ARM_ALU_PC_G0_NC", - "R_ARM_ALU_PC_G1", - "R_ARM_ALU_PC_G1_NC", - "R_ARM_ALU_PC_G2", - "R_ARM_ALU_SBREL_19_12_NC", - "R_ARM_ALU_SBREL_27_20_CK", - "R_ARM_ALU_SB_G0", - "R_ARM_ALU_SB_G0_NC", - "R_ARM_ALU_SB_G1", - "R_ARM_ALU_SB_G1_NC", - "R_ARM_ALU_SB_G2", - "R_ARM_AMP_VCALL9", - "R_ARM_BASE_ABS", - "R_ARM_CALL", - "R_ARM_COPY", - "R_ARM_GLOB_DAT", - "R_ARM_GNU_VTENTRY", - "R_ARM_GNU_VTINHERIT", - "R_ARM_GOT32", - "R_ARM_GOTOFF", - "R_ARM_GOTOFF12", - "R_ARM_GOTPC", - "R_ARM_GOTRELAX", - "R_ARM_GOT_ABS", - "R_ARM_GOT_BREL12", - "R_ARM_GOT_PREL", - "R_ARM_IRELATIVE", - "R_ARM_JUMP24", - "R_ARM_JUMP_SLOT", - "R_ARM_LDC_PC_G0", - "R_ARM_LDC_PC_G1", - "R_ARM_LDC_PC_G2", - "R_ARM_LDC_SB_G0", - "R_ARM_LDC_SB_G1", - "R_ARM_LDC_SB_G2", - "R_ARM_LDRS_PC_G0", - "R_ARM_LDRS_PC_G1", - "R_ARM_LDRS_PC_G2", - "R_ARM_LDRS_SB_G0", - "R_ARM_LDRS_SB_G1", - "R_ARM_LDRS_SB_G2", - "R_ARM_LDR_PC_G1", - "R_ARM_LDR_PC_G2", - "R_ARM_LDR_SBREL_11_10_NC", - "R_ARM_LDR_SB_G0", - "R_ARM_LDR_SB_G1", - "R_ARM_LDR_SB_G2", - "R_ARM_ME_TOO", - "R_ARM_MOVT_ABS", - "R_ARM_MOVT_BREL", - "R_ARM_MOVT_PREL", - "R_ARM_MOVW_ABS_NC", - "R_ARM_MOVW_BREL", - "R_ARM_MOVW_BREL_NC", - "R_ARM_MOVW_PREL_NC", - "R_ARM_NONE", - "R_ARM_PC13", - "R_ARM_PC24", - "R_ARM_PLT32", - "R_ARM_PLT32_ABS", - "R_ARM_PREL31", - "R_ARM_PRIVATE_0", - "R_ARM_PRIVATE_1", - "R_ARM_PRIVATE_10", - "R_ARM_PRIVATE_11", - "R_ARM_PRIVATE_12", - "R_ARM_PRIVATE_13", - "R_ARM_PRIVATE_14", - "R_ARM_PRIVATE_15", - "R_ARM_PRIVATE_2", - "R_ARM_PRIVATE_3", - "R_ARM_PRIVATE_4", - "R_ARM_PRIVATE_5", - "R_ARM_PRIVATE_6", - "R_ARM_PRIVATE_7", - "R_ARM_PRIVATE_8", - "R_ARM_PRIVATE_9", - "R_ARM_RABS32", - "R_ARM_RBASE", - "R_ARM_REL32", - "R_ARM_REL32_NOI", - "R_ARM_RELATIVE", - "R_ARM_RPC24", - "R_ARM_RREL32", - "R_ARM_RSBREL32", - "R_ARM_RXPC25", - "R_ARM_SBREL31", - "R_ARM_SBREL32", - "R_ARM_SWI24", - "R_ARM_TARGET1", - "R_ARM_TARGET2", - "R_ARM_THM_ABS5", - "R_ARM_THM_ALU_ABS_G0_NC", - "R_ARM_THM_ALU_ABS_G1_NC", - "R_ARM_THM_ALU_ABS_G2_NC", - "R_ARM_THM_ALU_ABS_G3", - "R_ARM_THM_ALU_PREL_11_0", - "R_ARM_THM_GOT_BREL12", - "R_ARM_THM_JUMP11", - "R_ARM_THM_JUMP19", - "R_ARM_THM_JUMP24", - "R_ARM_THM_JUMP6", - "R_ARM_THM_JUMP8", - "R_ARM_THM_MOVT_ABS", - "R_ARM_THM_MOVT_BREL", - "R_ARM_THM_MOVT_PREL", - "R_ARM_THM_MOVW_ABS_NC", - "R_ARM_THM_MOVW_BREL", - "R_ARM_THM_MOVW_BREL_NC", - "R_ARM_THM_MOVW_PREL_NC", - "R_ARM_THM_PC12", - "R_ARM_THM_PC22", - "R_ARM_THM_PC8", - "R_ARM_THM_RPC22", - "R_ARM_THM_SWI8", - "R_ARM_THM_TLS_CALL", - "R_ARM_THM_TLS_DESCSEQ16", - "R_ARM_THM_TLS_DESCSEQ32", - "R_ARM_THM_XPC22", - "R_ARM_TLS_CALL", - "R_ARM_TLS_DESCSEQ", - "R_ARM_TLS_DTPMOD32", - "R_ARM_TLS_DTPOFF32", - "R_ARM_TLS_GD32", - "R_ARM_TLS_GOTDESC", - "R_ARM_TLS_IE12GP", - "R_ARM_TLS_IE32", - "R_ARM_TLS_LDM32", - "R_ARM_TLS_LDO12", - "R_ARM_TLS_LDO32", - "R_ARM_TLS_LE12", - "R_ARM_TLS_LE32", - "R_ARM_TLS_TPOFF32", - "R_ARM_V4BX", - "R_ARM_XPC25", - "R_INFO", - "R_INFO32", - "R_LARCH", - "R_LARCH_32", - "R_LARCH_32_PCREL", - "R_LARCH_64", - "R_LARCH_64_PCREL", - "R_LARCH_ABS64_HI12", - "R_LARCH_ABS64_LO20", - "R_LARCH_ABS_HI20", - "R_LARCH_ABS_LO12", - "R_LARCH_ADD16", - "R_LARCH_ADD24", - "R_LARCH_ADD32", - "R_LARCH_ADD6", - "R_LARCH_ADD64", - "R_LARCH_ADD8", - "R_LARCH_ADD_ULEB128", - "R_LARCH_ALIGN", - "R_LARCH_B16", - "R_LARCH_B21", - "R_LARCH_B26", - "R_LARCH_CFA", - "R_LARCH_COPY", - "R_LARCH_DELETE", - "R_LARCH_GNU_VTENTRY", - "R_LARCH_GNU_VTINHERIT", - "R_LARCH_GOT64_HI12", - "R_LARCH_GOT64_LO20", - "R_LARCH_GOT64_PC_HI12", - "R_LARCH_GOT64_PC_LO20", - "R_LARCH_GOT_HI20", - "R_LARCH_GOT_LO12", - "R_LARCH_GOT_PC_HI20", - "R_LARCH_GOT_PC_LO12", - "R_LARCH_IRELATIVE", - "R_LARCH_JUMP_SLOT", - "R_LARCH_MARK_LA", - "R_LARCH_MARK_PCREL", - "R_LARCH_NONE", - "R_LARCH_PCALA64_HI12", - "R_LARCH_PCALA64_LO20", - "R_LARCH_PCALA_HI20", - "R_LARCH_PCALA_LO12", - "R_LARCH_PCREL20_S2", - "R_LARCH_RELATIVE", - "R_LARCH_RELAX", - "R_LARCH_SOP_ADD", - "R_LARCH_SOP_AND", - "R_LARCH_SOP_ASSERT", - "R_LARCH_SOP_IF_ELSE", - "R_LARCH_SOP_NOT", - "R_LARCH_SOP_POP_32_S_0_10_10_16_S2", - "R_LARCH_SOP_POP_32_S_0_5_10_16_S2", - "R_LARCH_SOP_POP_32_S_10_12", - "R_LARCH_SOP_POP_32_S_10_16", - "R_LARCH_SOP_POP_32_S_10_16_S2", - "R_LARCH_SOP_POP_32_S_10_5", - "R_LARCH_SOP_POP_32_S_5_20", - "R_LARCH_SOP_POP_32_U", - "R_LARCH_SOP_POP_32_U_10_12", - "R_LARCH_SOP_PUSH_ABSOLUTE", - "R_LARCH_SOP_PUSH_DUP", - "R_LARCH_SOP_PUSH_GPREL", - "R_LARCH_SOP_PUSH_PCREL", - "R_LARCH_SOP_PUSH_PLT_PCREL", - "R_LARCH_SOP_PUSH_TLS_GD", - "R_LARCH_SOP_PUSH_TLS_GOT", - "R_LARCH_SOP_PUSH_TLS_TPREL", - "R_LARCH_SOP_SL", - "R_LARCH_SOP_SR", - "R_LARCH_SOP_SUB", - "R_LARCH_SUB16", - "R_LARCH_SUB24", - "R_LARCH_SUB32", - "R_LARCH_SUB6", - "R_LARCH_SUB64", - "R_LARCH_SUB8", - "R_LARCH_SUB_ULEB128", - "R_LARCH_TLS_DTPMOD32", - "R_LARCH_TLS_DTPMOD64", - "R_LARCH_TLS_DTPREL32", - "R_LARCH_TLS_DTPREL64", - "R_LARCH_TLS_GD_HI20", - "R_LARCH_TLS_GD_PC_HI20", - "R_LARCH_TLS_IE64_HI12", - "R_LARCH_TLS_IE64_LO20", - "R_LARCH_TLS_IE64_PC_HI12", - "R_LARCH_TLS_IE64_PC_LO20", - "R_LARCH_TLS_IE_HI20", - "R_LARCH_TLS_IE_LO12", - "R_LARCH_TLS_IE_PC_HI20", - "R_LARCH_TLS_IE_PC_LO12", - "R_LARCH_TLS_LD_HI20", - "R_LARCH_TLS_LD_PC_HI20", - "R_LARCH_TLS_LE64_HI12", - "R_LARCH_TLS_LE64_LO20", - "R_LARCH_TLS_LE_HI20", - "R_LARCH_TLS_LE_LO12", - "R_LARCH_TLS_TPREL32", - "R_LARCH_TLS_TPREL64", - "R_MIPS", - "R_MIPS_16", - "R_MIPS_26", - "R_MIPS_32", - "R_MIPS_64", - "R_MIPS_ADD_IMMEDIATE", - "R_MIPS_CALL16", - "R_MIPS_CALL_HI16", - "R_MIPS_CALL_LO16", - "R_MIPS_DELETE", - "R_MIPS_GOT16", - "R_MIPS_GOT_DISP", - "R_MIPS_GOT_HI16", - "R_MIPS_GOT_LO16", - "R_MIPS_GOT_OFST", - "R_MIPS_GOT_PAGE", - "R_MIPS_GPREL16", - "R_MIPS_GPREL32", - "R_MIPS_HI16", - "R_MIPS_HIGHER", - "R_MIPS_HIGHEST", - "R_MIPS_INSERT_A", - "R_MIPS_INSERT_B", - "R_MIPS_JALR", - "R_MIPS_LITERAL", - "R_MIPS_LO16", - "R_MIPS_NONE", - "R_MIPS_PC16", - "R_MIPS_PC32", - "R_MIPS_PJUMP", - "R_MIPS_REL16", - "R_MIPS_REL32", - "R_MIPS_RELGOT", - "R_MIPS_SCN_DISP", - "R_MIPS_SHIFT5", - "R_MIPS_SHIFT6", - "R_MIPS_SUB", - "R_MIPS_TLS_DTPMOD32", - "R_MIPS_TLS_DTPMOD64", - "R_MIPS_TLS_DTPREL32", - "R_MIPS_TLS_DTPREL64", - "R_MIPS_TLS_DTPREL_HI16", - "R_MIPS_TLS_DTPREL_LO16", - "R_MIPS_TLS_GD", - "R_MIPS_TLS_GOTTPREL", - "R_MIPS_TLS_LDM", - "R_MIPS_TLS_TPREL32", - "R_MIPS_TLS_TPREL64", - "R_MIPS_TLS_TPREL_HI16", - "R_MIPS_TLS_TPREL_LO16", - "R_PPC", - "R_PPC64", - "R_PPC64_ADDR14", - "R_PPC64_ADDR14_BRNTAKEN", - "R_PPC64_ADDR14_BRTAKEN", - "R_PPC64_ADDR16", - "R_PPC64_ADDR16_DS", - "R_PPC64_ADDR16_HA", - "R_PPC64_ADDR16_HI", - "R_PPC64_ADDR16_HIGH", - "R_PPC64_ADDR16_HIGHA", - "R_PPC64_ADDR16_HIGHER", - "R_PPC64_ADDR16_HIGHER34", - "R_PPC64_ADDR16_HIGHERA", - "R_PPC64_ADDR16_HIGHERA34", - "R_PPC64_ADDR16_HIGHEST", - "R_PPC64_ADDR16_HIGHEST34", - "R_PPC64_ADDR16_HIGHESTA", - "R_PPC64_ADDR16_HIGHESTA34", - "R_PPC64_ADDR16_LO", - "R_PPC64_ADDR16_LO_DS", - "R_PPC64_ADDR24", - "R_PPC64_ADDR32", - "R_PPC64_ADDR64", - "R_PPC64_ADDR64_LOCAL", - "R_PPC64_COPY", - "R_PPC64_D28", - "R_PPC64_D34", - "R_PPC64_D34_HA30", - "R_PPC64_D34_HI30", - "R_PPC64_D34_LO", - "R_PPC64_DTPMOD64", - "R_PPC64_DTPREL16", - "R_PPC64_DTPREL16_DS", - "R_PPC64_DTPREL16_HA", - "R_PPC64_DTPREL16_HI", - "R_PPC64_DTPREL16_HIGH", - "R_PPC64_DTPREL16_HIGHA", - "R_PPC64_DTPREL16_HIGHER", - "R_PPC64_DTPREL16_HIGHERA", - "R_PPC64_DTPREL16_HIGHEST", - "R_PPC64_DTPREL16_HIGHESTA", - "R_PPC64_DTPREL16_LO", - "R_PPC64_DTPREL16_LO_DS", - "R_PPC64_DTPREL34", - "R_PPC64_DTPREL64", - "R_PPC64_ENTRY", - "R_PPC64_GLOB_DAT", - "R_PPC64_GNU_VTENTRY", - "R_PPC64_GNU_VTINHERIT", - "R_PPC64_GOT16", - "R_PPC64_GOT16_DS", - "R_PPC64_GOT16_HA", - "R_PPC64_GOT16_HI", - "R_PPC64_GOT16_LO", - "R_PPC64_GOT16_LO_DS", - "R_PPC64_GOT_DTPREL16_DS", - "R_PPC64_GOT_DTPREL16_HA", - "R_PPC64_GOT_DTPREL16_HI", - "R_PPC64_GOT_DTPREL16_LO_DS", - "R_PPC64_GOT_DTPREL_PCREL34", - "R_PPC64_GOT_PCREL34", - "R_PPC64_GOT_TLSGD16", - "R_PPC64_GOT_TLSGD16_HA", - "R_PPC64_GOT_TLSGD16_HI", - "R_PPC64_GOT_TLSGD16_LO", - "R_PPC64_GOT_TLSGD_PCREL34", - "R_PPC64_GOT_TLSLD16", - "R_PPC64_GOT_TLSLD16_HA", - "R_PPC64_GOT_TLSLD16_HI", - "R_PPC64_GOT_TLSLD16_LO", - "R_PPC64_GOT_TLSLD_PCREL34", - "R_PPC64_GOT_TPREL16_DS", - "R_PPC64_GOT_TPREL16_HA", - "R_PPC64_GOT_TPREL16_HI", - "R_PPC64_GOT_TPREL16_LO_DS", - "R_PPC64_GOT_TPREL_PCREL34", - "R_PPC64_IRELATIVE", - "R_PPC64_JMP_IREL", - "R_PPC64_JMP_SLOT", - "R_PPC64_NONE", - "R_PPC64_PCREL28", - "R_PPC64_PCREL34", - "R_PPC64_PCREL_OPT", - "R_PPC64_PLT16_HA", - "R_PPC64_PLT16_HI", - "R_PPC64_PLT16_LO", - "R_PPC64_PLT16_LO_DS", - "R_PPC64_PLT32", - "R_PPC64_PLT64", - "R_PPC64_PLTCALL", - "R_PPC64_PLTCALL_NOTOC", - "R_PPC64_PLTGOT16", - "R_PPC64_PLTGOT16_DS", - "R_PPC64_PLTGOT16_HA", - "R_PPC64_PLTGOT16_HI", - "R_PPC64_PLTGOT16_LO", - "R_PPC64_PLTGOT_LO_DS", - "R_PPC64_PLTREL32", - "R_PPC64_PLTREL64", - "R_PPC64_PLTSEQ", - "R_PPC64_PLTSEQ_NOTOC", - "R_PPC64_PLT_PCREL34", - "R_PPC64_PLT_PCREL34_NOTOC", - "R_PPC64_REL14", - "R_PPC64_REL14_BRNTAKEN", - "R_PPC64_REL14_BRTAKEN", - "R_PPC64_REL16", - "R_PPC64_REL16DX_HA", - "R_PPC64_REL16_HA", - "R_PPC64_REL16_HI", - "R_PPC64_REL16_HIGH", - "R_PPC64_REL16_HIGHA", - "R_PPC64_REL16_HIGHER", - "R_PPC64_REL16_HIGHER34", - "R_PPC64_REL16_HIGHERA", - "R_PPC64_REL16_HIGHERA34", - "R_PPC64_REL16_HIGHEST", - "R_PPC64_REL16_HIGHEST34", - "R_PPC64_REL16_HIGHESTA", - "R_PPC64_REL16_HIGHESTA34", - "R_PPC64_REL16_LO", - "R_PPC64_REL24", - "R_PPC64_REL24_NOTOC", - "R_PPC64_REL24_P9NOTOC", - "R_PPC64_REL30", - "R_PPC64_REL32", - "R_PPC64_REL64", - "R_PPC64_RELATIVE", - "R_PPC64_SECTOFF", - "R_PPC64_SECTOFF_DS", - "R_PPC64_SECTOFF_HA", - "R_PPC64_SECTOFF_HI", - "R_PPC64_SECTOFF_LO", - "R_PPC64_SECTOFF_LO_DS", - "R_PPC64_TLS", - "R_PPC64_TLSGD", - "R_PPC64_TLSLD", - "R_PPC64_TOC", - "R_PPC64_TOC16", - "R_PPC64_TOC16_DS", - "R_PPC64_TOC16_HA", - "R_PPC64_TOC16_HI", - "R_PPC64_TOC16_LO", - "R_PPC64_TOC16_LO_DS", - "R_PPC64_TOCSAVE", - "R_PPC64_TPREL16", - "R_PPC64_TPREL16_DS", - "R_PPC64_TPREL16_HA", - "R_PPC64_TPREL16_HI", - "R_PPC64_TPREL16_HIGH", - "R_PPC64_TPREL16_HIGHA", - "R_PPC64_TPREL16_HIGHER", - "R_PPC64_TPREL16_HIGHERA", - "R_PPC64_TPREL16_HIGHEST", - "R_PPC64_TPREL16_HIGHESTA", - "R_PPC64_TPREL16_LO", - "R_PPC64_TPREL16_LO_DS", - "R_PPC64_TPREL34", - "R_PPC64_TPREL64", - "R_PPC64_UADDR16", - "R_PPC64_UADDR32", - "R_PPC64_UADDR64", - "R_PPC_ADDR14", - "R_PPC_ADDR14_BRNTAKEN", - "R_PPC_ADDR14_BRTAKEN", - "R_PPC_ADDR16", - "R_PPC_ADDR16_HA", - "R_PPC_ADDR16_HI", - "R_PPC_ADDR16_LO", - "R_PPC_ADDR24", - "R_PPC_ADDR32", - "R_PPC_COPY", - "R_PPC_DTPMOD32", - "R_PPC_DTPREL16", - "R_PPC_DTPREL16_HA", - "R_PPC_DTPREL16_HI", - "R_PPC_DTPREL16_LO", - "R_PPC_DTPREL32", - "R_PPC_EMB_BIT_FLD", - "R_PPC_EMB_MRKREF", - "R_PPC_EMB_NADDR16", - "R_PPC_EMB_NADDR16_HA", - "R_PPC_EMB_NADDR16_HI", - "R_PPC_EMB_NADDR16_LO", - "R_PPC_EMB_NADDR32", - "R_PPC_EMB_RELSDA", - "R_PPC_EMB_RELSEC16", - "R_PPC_EMB_RELST_HA", - "R_PPC_EMB_RELST_HI", - "R_PPC_EMB_RELST_LO", - "R_PPC_EMB_SDA21", - "R_PPC_EMB_SDA2I16", - "R_PPC_EMB_SDA2REL", - "R_PPC_EMB_SDAI16", - "R_PPC_GLOB_DAT", - "R_PPC_GOT16", - "R_PPC_GOT16_HA", - "R_PPC_GOT16_HI", - "R_PPC_GOT16_LO", - "R_PPC_GOT_TLSGD16", - "R_PPC_GOT_TLSGD16_HA", - "R_PPC_GOT_TLSGD16_HI", - "R_PPC_GOT_TLSGD16_LO", - "R_PPC_GOT_TLSLD16", - "R_PPC_GOT_TLSLD16_HA", - "R_PPC_GOT_TLSLD16_HI", - "R_PPC_GOT_TLSLD16_LO", - "R_PPC_GOT_TPREL16", - "R_PPC_GOT_TPREL16_HA", - "R_PPC_GOT_TPREL16_HI", - "R_PPC_GOT_TPREL16_LO", - "R_PPC_JMP_SLOT", - "R_PPC_LOCAL24PC", - "R_PPC_NONE", - "R_PPC_PLT16_HA", - "R_PPC_PLT16_HI", - "R_PPC_PLT16_LO", - "R_PPC_PLT32", - "R_PPC_PLTREL24", - "R_PPC_PLTREL32", - "R_PPC_REL14", - "R_PPC_REL14_BRNTAKEN", - "R_PPC_REL14_BRTAKEN", - "R_PPC_REL24", - "R_PPC_REL32", - "R_PPC_RELATIVE", - "R_PPC_SDAREL16", - "R_PPC_SECTOFF", - "R_PPC_SECTOFF_HA", - "R_PPC_SECTOFF_HI", - "R_PPC_SECTOFF_LO", - "R_PPC_TLS", - "R_PPC_TPREL16", - "R_PPC_TPREL16_HA", - "R_PPC_TPREL16_HI", - "R_PPC_TPREL16_LO", - "R_PPC_TPREL32", - "R_PPC_UADDR16", - "R_PPC_UADDR32", - "R_RISCV", - "R_RISCV_32", - "R_RISCV_32_PCREL", - "R_RISCV_64", - "R_RISCV_ADD16", - "R_RISCV_ADD32", - "R_RISCV_ADD64", - "R_RISCV_ADD8", - "R_RISCV_ALIGN", - "R_RISCV_BRANCH", - "R_RISCV_CALL", - "R_RISCV_CALL_PLT", - "R_RISCV_COPY", - "R_RISCV_GNU_VTENTRY", - "R_RISCV_GNU_VTINHERIT", - "R_RISCV_GOT_HI20", - "R_RISCV_GPREL_I", - "R_RISCV_GPREL_S", - "R_RISCV_HI20", - "R_RISCV_JAL", - "R_RISCV_JUMP_SLOT", - "R_RISCV_LO12_I", - "R_RISCV_LO12_S", - "R_RISCV_NONE", - "R_RISCV_PCREL_HI20", - "R_RISCV_PCREL_LO12_I", - "R_RISCV_PCREL_LO12_S", - "R_RISCV_RELATIVE", - "R_RISCV_RELAX", - "R_RISCV_RVC_BRANCH", - "R_RISCV_RVC_JUMP", - "R_RISCV_RVC_LUI", - "R_RISCV_SET16", - "R_RISCV_SET32", - "R_RISCV_SET6", - "R_RISCV_SET8", - "R_RISCV_SUB16", - "R_RISCV_SUB32", - "R_RISCV_SUB6", - "R_RISCV_SUB64", - "R_RISCV_SUB8", - "R_RISCV_TLS_DTPMOD32", - "R_RISCV_TLS_DTPMOD64", - "R_RISCV_TLS_DTPREL32", - "R_RISCV_TLS_DTPREL64", - "R_RISCV_TLS_GD_HI20", - "R_RISCV_TLS_GOT_HI20", - "R_RISCV_TLS_TPREL32", - "R_RISCV_TLS_TPREL64", - "R_RISCV_TPREL_ADD", - "R_RISCV_TPREL_HI20", - "R_RISCV_TPREL_I", - "R_RISCV_TPREL_LO12_I", - "R_RISCV_TPREL_LO12_S", - "R_RISCV_TPREL_S", - "R_SPARC", - "R_SPARC_10", - "R_SPARC_11", - "R_SPARC_13", - "R_SPARC_16", - "R_SPARC_22", - "R_SPARC_32", - "R_SPARC_5", - "R_SPARC_6", - "R_SPARC_64", - "R_SPARC_7", - "R_SPARC_8", - "R_SPARC_COPY", - "R_SPARC_DISP16", - "R_SPARC_DISP32", - "R_SPARC_DISP64", - "R_SPARC_DISP8", - "R_SPARC_GLOB_DAT", - "R_SPARC_GLOB_JMP", - "R_SPARC_GOT10", - "R_SPARC_GOT13", - "R_SPARC_GOT22", - "R_SPARC_H44", - "R_SPARC_HH22", - "R_SPARC_HI22", - "R_SPARC_HIPLT22", - "R_SPARC_HIX22", - "R_SPARC_HM10", - "R_SPARC_JMP_SLOT", - "R_SPARC_L44", - "R_SPARC_LM22", - "R_SPARC_LO10", - "R_SPARC_LOPLT10", - "R_SPARC_LOX10", - "R_SPARC_M44", - "R_SPARC_NONE", - "R_SPARC_OLO10", - "R_SPARC_PC10", - "R_SPARC_PC22", - "R_SPARC_PCPLT10", - "R_SPARC_PCPLT22", - "R_SPARC_PCPLT32", - "R_SPARC_PC_HH22", - "R_SPARC_PC_HM10", - "R_SPARC_PC_LM22", - "R_SPARC_PLT32", - "R_SPARC_PLT64", - "R_SPARC_REGISTER", - "R_SPARC_RELATIVE", - "R_SPARC_UA16", - "R_SPARC_UA32", - "R_SPARC_UA64", - "R_SPARC_WDISP16", - "R_SPARC_WDISP19", - "R_SPARC_WDISP22", - "R_SPARC_WDISP30", - "R_SPARC_WPLT30", - "R_SYM32", - "R_SYM64", - "R_TYPE32", - "R_TYPE64", - "R_X86_64", - "R_X86_64_16", - "R_X86_64_32", - "R_X86_64_32S", - "R_X86_64_64", - "R_X86_64_8", - "R_X86_64_COPY", - "R_X86_64_DTPMOD64", - "R_X86_64_DTPOFF32", - "R_X86_64_DTPOFF64", - "R_X86_64_GLOB_DAT", - "R_X86_64_GOT32", - "R_X86_64_GOT64", - "R_X86_64_GOTOFF64", - "R_X86_64_GOTPC32", - "R_X86_64_GOTPC32_TLSDESC", - "R_X86_64_GOTPC64", - "R_X86_64_GOTPCREL", - "R_X86_64_GOTPCREL64", - "R_X86_64_GOTPCRELX", - "R_X86_64_GOTPLT64", - "R_X86_64_GOTTPOFF", - "R_X86_64_IRELATIVE", - "R_X86_64_JMP_SLOT", - "R_X86_64_NONE", - "R_X86_64_PC16", - "R_X86_64_PC32", - "R_X86_64_PC32_BND", - "R_X86_64_PC64", - "R_X86_64_PC8", - "R_X86_64_PLT32", - "R_X86_64_PLT32_BND", - "R_X86_64_PLTOFF64", - "R_X86_64_RELATIVE", - "R_X86_64_RELATIVE64", - "R_X86_64_REX_GOTPCRELX", - "R_X86_64_SIZE32", - "R_X86_64_SIZE64", - "R_X86_64_TLSDESC", - "R_X86_64_TLSDESC_CALL", - "R_X86_64_TLSGD", - "R_X86_64_TLSLD", - "R_X86_64_TPOFF32", - "R_X86_64_TPOFF64", - "Rel32", - "Rel64", - "Rela32", - "Rela64", - "SHF_ALLOC", - "SHF_COMPRESSED", - "SHF_EXECINSTR", - "SHF_GROUP", - "SHF_INFO_LINK", - "SHF_LINK_ORDER", - "SHF_MASKOS", - "SHF_MASKPROC", - "SHF_MERGE", - "SHF_OS_NONCONFORMING", - "SHF_STRINGS", - "SHF_TLS", - "SHF_WRITE", - "SHN_ABS", - "SHN_COMMON", - "SHN_HIOS", - "SHN_HIPROC", - "SHN_HIRESERVE", - "SHN_LOOS", - "SHN_LOPROC", - "SHN_LORESERVE", - "SHN_UNDEF", - "SHN_XINDEX", - "SHT_DYNAMIC", - "SHT_DYNSYM", - "SHT_FINI_ARRAY", - "SHT_GNU_ATTRIBUTES", - "SHT_GNU_HASH", - "SHT_GNU_LIBLIST", - "SHT_GNU_VERDEF", - "SHT_GNU_VERNEED", - "SHT_GNU_VERSYM", - "SHT_GROUP", - "SHT_HASH", - "SHT_HIOS", - "SHT_HIPROC", - "SHT_HIUSER", - "SHT_INIT_ARRAY", - "SHT_LOOS", - "SHT_LOPROC", - "SHT_LOUSER", - "SHT_MIPS_ABIFLAGS", - "SHT_NOBITS", - "SHT_NOTE", - "SHT_NULL", - "SHT_PREINIT_ARRAY", - "SHT_PROGBITS", - "SHT_REL", - "SHT_RELA", - "SHT_SHLIB", - "SHT_STRTAB", - "SHT_SYMTAB", - "SHT_SYMTAB_SHNDX", - "STB_GLOBAL", - "STB_HIOS", - "STB_HIPROC", - "STB_LOCAL", - "STB_LOOS", - "STB_LOPROC", - "STB_WEAK", - "STT_COMMON", - "STT_FILE", - "STT_FUNC", - "STT_HIOS", - "STT_HIPROC", - "STT_LOOS", - "STT_LOPROC", - "STT_NOTYPE", - "STT_OBJECT", - "STT_SECTION", - "STT_TLS", - "STV_DEFAULT", - "STV_HIDDEN", - "STV_INTERNAL", - "STV_PROTECTED", - "ST_BIND", - "ST_INFO", - "ST_TYPE", - "ST_VISIBILITY", - "Section", - "Section32", - "Section64", - "SectionFlag", - "SectionHeader", - "SectionIndex", - "SectionType", - "Sym32", - "Sym32Size", - "Sym64", - "Sym64Size", - "SymBind", - "SymType", - "SymVis", - "Symbol", - "Type", - "Version", - }, - "debug/gosym": { - "DecodingError", - "Func", - "LineTable", - "NewLineTable", - "NewTable", - "Obj", - "Sym", - "Table", - "UnknownFileError", - "UnknownLineError", - }, - "debug/macho": { - "ARM64_RELOC_ADDEND", - "ARM64_RELOC_BRANCH26", - "ARM64_RELOC_GOT_LOAD_PAGE21", - "ARM64_RELOC_GOT_LOAD_PAGEOFF12", - "ARM64_RELOC_PAGE21", - "ARM64_RELOC_PAGEOFF12", - "ARM64_RELOC_POINTER_TO_GOT", - "ARM64_RELOC_SUBTRACTOR", - "ARM64_RELOC_TLVP_LOAD_PAGE21", - "ARM64_RELOC_TLVP_LOAD_PAGEOFF12", - "ARM64_RELOC_UNSIGNED", - "ARM_RELOC_BR24", - "ARM_RELOC_HALF", - "ARM_RELOC_HALF_SECTDIFF", - "ARM_RELOC_LOCAL_SECTDIFF", - "ARM_RELOC_PAIR", - "ARM_RELOC_PB_LA_PTR", - "ARM_RELOC_SECTDIFF", - "ARM_RELOC_VANILLA", - "ARM_THUMB_32BIT_BRANCH", - "ARM_THUMB_RELOC_BR22", - "Cpu", - "Cpu386", - "CpuAmd64", - "CpuArm", - "CpuArm64", - "CpuPpc", - "CpuPpc64", - "Dylib", - "DylibCmd", - "Dysymtab", - "DysymtabCmd", - "ErrNotFat", - "FatArch", - "FatArchHeader", - "FatFile", - "File", - "FileHeader", - "FlagAllModsBound", - "FlagAllowStackExecution", - "FlagAppExtensionSafe", - "FlagBindAtLoad", - "FlagBindsToWeak", - "FlagCanonical", - "FlagDeadStrippableDylib", - "FlagDyldLink", - "FlagForceFlat", - "FlagHasTLVDescriptors", - "FlagIncrLink", - "FlagLazyInit", - "FlagNoFixPrebinding", - "FlagNoHeapExecution", - "FlagNoMultiDefs", - "FlagNoReexportedDylibs", - "FlagNoUndefs", - "FlagPIE", - "FlagPrebindable", - "FlagPrebound", - "FlagRootSafe", - "FlagSetuidSafe", - "FlagSplitSegs", - "FlagSubsectionsViaSymbols", - "FlagTwoLevel", - "FlagWeakDefines", - "FormatError", - "GENERIC_RELOC_LOCAL_SECTDIFF", - "GENERIC_RELOC_PAIR", - "GENERIC_RELOC_PB_LA_PTR", - "GENERIC_RELOC_SECTDIFF", - "GENERIC_RELOC_TLV", - "GENERIC_RELOC_VANILLA", - "Load", - "LoadBytes", - "LoadCmd", - "LoadCmdDylib", - "LoadCmdDylinker", - "LoadCmdDysymtab", - "LoadCmdRpath", - "LoadCmdSegment", - "LoadCmdSegment64", - "LoadCmdSymtab", - "LoadCmdThread", - "LoadCmdUnixThread", - "Magic32", - "Magic64", - "MagicFat", - "NewFatFile", - "NewFile", - "Nlist32", - "Nlist64", - "Open", - "OpenFat", - "Regs386", - "RegsAMD64", - "Reloc", - "RelocTypeARM", - "RelocTypeARM64", - "RelocTypeGeneric", - "RelocTypeX86_64", - "Rpath", - "RpathCmd", - "Section", - "Section32", - "Section64", - "SectionHeader", - "Segment", - "Segment32", - "Segment64", - "SegmentHeader", - "Symbol", - "Symtab", - "SymtabCmd", - "Thread", - "Type", - "TypeBundle", - "TypeDylib", - "TypeExec", - "TypeObj", - "X86_64_RELOC_BRANCH", - "X86_64_RELOC_GOT", - "X86_64_RELOC_GOT_LOAD", - "X86_64_RELOC_SIGNED", - "X86_64_RELOC_SIGNED_1", - "X86_64_RELOC_SIGNED_2", - "X86_64_RELOC_SIGNED_4", - "X86_64_RELOC_SUBTRACTOR", - "X86_64_RELOC_TLV", - "X86_64_RELOC_UNSIGNED", - }, - "debug/pe": { - "COFFSymbol", - "COFFSymbolAuxFormat5", - "COFFSymbolSize", - "DataDirectory", - "File", - "FileHeader", - "FormatError", - "IMAGE_COMDAT_SELECT_ANY", - "IMAGE_COMDAT_SELECT_ASSOCIATIVE", - "IMAGE_COMDAT_SELECT_EXACT_MATCH", - "IMAGE_COMDAT_SELECT_LARGEST", - "IMAGE_COMDAT_SELECT_NODUPLICATES", - "IMAGE_COMDAT_SELECT_SAME_SIZE", - "IMAGE_DIRECTORY_ENTRY_ARCHITECTURE", - "IMAGE_DIRECTORY_ENTRY_BASERELOC", - "IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT", - "IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR", - "IMAGE_DIRECTORY_ENTRY_DEBUG", - "IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT", - "IMAGE_DIRECTORY_ENTRY_EXCEPTION", - "IMAGE_DIRECTORY_ENTRY_EXPORT", - "IMAGE_DIRECTORY_ENTRY_GLOBALPTR", - "IMAGE_DIRECTORY_ENTRY_IAT", - "IMAGE_DIRECTORY_ENTRY_IMPORT", - "IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG", - "IMAGE_DIRECTORY_ENTRY_RESOURCE", - "IMAGE_DIRECTORY_ENTRY_SECURITY", - "IMAGE_DIRECTORY_ENTRY_TLS", - "IMAGE_DLLCHARACTERISTICS_APPCONTAINER", - "IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE", - "IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY", - "IMAGE_DLLCHARACTERISTICS_GUARD_CF", - "IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA", - "IMAGE_DLLCHARACTERISTICS_NO_BIND", - "IMAGE_DLLCHARACTERISTICS_NO_ISOLATION", - "IMAGE_DLLCHARACTERISTICS_NO_SEH", - "IMAGE_DLLCHARACTERISTICS_NX_COMPAT", - "IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE", - "IMAGE_DLLCHARACTERISTICS_WDM_DRIVER", - "IMAGE_FILE_32BIT_MACHINE", - "IMAGE_FILE_AGGRESIVE_WS_TRIM", - "IMAGE_FILE_BYTES_REVERSED_HI", - "IMAGE_FILE_BYTES_REVERSED_LO", - "IMAGE_FILE_DEBUG_STRIPPED", - "IMAGE_FILE_DLL", - "IMAGE_FILE_EXECUTABLE_IMAGE", - "IMAGE_FILE_LARGE_ADDRESS_AWARE", - "IMAGE_FILE_LINE_NUMS_STRIPPED", - "IMAGE_FILE_LOCAL_SYMS_STRIPPED", - "IMAGE_FILE_MACHINE_AM33", - "IMAGE_FILE_MACHINE_AMD64", - "IMAGE_FILE_MACHINE_ARM", - "IMAGE_FILE_MACHINE_ARM64", - "IMAGE_FILE_MACHINE_ARMNT", - "IMAGE_FILE_MACHINE_EBC", - "IMAGE_FILE_MACHINE_I386", - "IMAGE_FILE_MACHINE_IA64", - "IMAGE_FILE_MACHINE_LOONGARCH32", - "IMAGE_FILE_MACHINE_LOONGARCH64", - "IMAGE_FILE_MACHINE_M32R", - "IMAGE_FILE_MACHINE_MIPS16", - "IMAGE_FILE_MACHINE_MIPSFPU", - "IMAGE_FILE_MACHINE_MIPSFPU16", - "IMAGE_FILE_MACHINE_POWERPC", - "IMAGE_FILE_MACHINE_POWERPCFP", - "IMAGE_FILE_MACHINE_R4000", - "IMAGE_FILE_MACHINE_RISCV128", - "IMAGE_FILE_MACHINE_RISCV32", - "IMAGE_FILE_MACHINE_RISCV64", - "IMAGE_FILE_MACHINE_SH3", - "IMAGE_FILE_MACHINE_SH3DSP", - "IMAGE_FILE_MACHINE_SH4", - "IMAGE_FILE_MACHINE_SH5", - "IMAGE_FILE_MACHINE_THUMB", - "IMAGE_FILE_MACHINE_UNKNOWN", - "IMAGE_FILE_MACHINE_WCEMIPSV2", - "IMAGE_FILE_NET_RUN_FROM_SWAP", - "IMAGE_FILE_RELOCS_STRIPPED", - "IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP", - "IMAGE_FILE_SYSTEM", - "IMAGE_FILE_UP_SYSTEM_ONLY", - "IMAGE_SCN_CNT_CODE", - "IMAGE_SCN_CNT_INITIALIZED_DATA", - "IMAGE_SCN_CNT_UNINITIALIZED_DATA", - "IMAGE_SCN_LNK_COMDAT", - "IMAGE_SCN_MEM_DISCARDABLE", - "IMAGE_SCN_MEM_EXECUTE", - "IMAGE_SCN_MEM_READ", - "IMAGE_SCN_MEM_WRITE", - "IMAGE_SUBSYSTEM_EFI_APPLICATION", - "IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER", - "IMAGE_SUBSYSTEM_EFI_ROM", - "IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER", - "IMAGE_SUBSYSTEM_NATIVE", - "IMAGE_SUBSYSTEM_NATIVE_WINDOWS", - "IMAGE_SUBSYSTEM_OS2_CUI", - "IMAGE_SUBSYSTEM_POSIX_CUI", - "IMAGE_SUBSYSTEM_UNKNOWN", - "IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION", - "IMAGE_SUBSYSTEM_WINDOWS_CE_GUI", - "IMAGE_SUBSYSTEM_WINDOWS_CUI", - "IMAGE_SUBSYSTEM_WINDOWS_GUI", - "IMAGE_SUBSYSTEM_XBOX", - "ImportDirectory", - "NewFile", - "Open", - "OptionalHeader32", - "OptionalHeader64", - "Reloc", - "Section", - "SectionHeader", - "SectionHeader32", - "StringTable", - "Symbol", - }, - "debug/plan9obj": { - "ErrNoSymbols", - "File", - "FileHeader", - "Magic386", - "Magic64", - "MagicAMD64", - "MagicARM", - "NewFile", - "Open", - "Section", - "SectionHeader", - "Sym", - }, - "embed": { - "FS", - }, - "encoding": { - "BinaryMarshaler", - "BinaryUnmarshaler", - "TextMarshaler", - "TextUnmarshaler", - }, - "encoding/ascii85": { - "CorruptInputError", - "Decode", - "Encode", - "MaxEncodedLen", - "NewDecoder", - "NewEncoder", - }, - "encoding/asn1": { - "BitString", - "ClassApplication", - "ClassContextSpecific", - "ClassPrivate", - "ClassUniversal", - "Enumerated", - "Flag", - "Marshal", - "MarshalWithParams", - "NullBytes", - "NullRawValue", - "ObjectIdentifier", - "RawContent", - "RawValue", - "StructuralError", - "SyntaxError", - "TagBMPString", - "TagBitString", - "TagBoolean", - "TagEnum", - "TagGeneralString", - "TagGeneralizedTime", - "TagIA5String", - "TagInteger", - "TagNull", - "TagNumericString", - "TagOID", - "TagOctetString", - "TagPrintableString", - "TagSequence", - "TagSet", - "TagT61String", - "TagUTCTime", - "TagUTF8String", - "Unmarshal", - "UnmarshalWithParams", - }, - "encoding/base32": { - "CorruptInputError", - "Encoding", - "HexEncoding", - "NewDecoder", - "NewEncoder", - "NewEncoding", - "NoPadding", - "StdEncoding", - "StdPadding", - }, - "encoding/base64": { - "CorruptInputError", - "Encoding", - "NewDecoder", - "NewEncoder", - "NewEncoding", - "NoPadding", - "RawStdEncoding", - "RawURLEncoding", - "StdEncoding", - "StdPadding", - "URLEncoding", - }, - "encoding/binary": { - "AppendByteOrder", - "AppendUvarint", - "AppendVarint", - "BigEndian", - "ByteOrder", - "LittleEndian", - "MaxVarintLen16", - "MaxVarintLen32", - "MaxVarintLen64", - "NativeEndian", - "PutUvarint", - "PutVarint", - "Read", - "ReadUvarint", - "ReadVarint", - "Size", - "Uvarint", - "Varint", - "Write", - }, - "encoding/csv": { - "ErrBareQuote", - "ErrFieldCount", - "ErrQuote", - "ErrTrailingComma", - "NewReader", - "NewWriter", - "ParseError", - "Reader", - "Writer", - }, - "encoding/gob": { - "CommonType", - "Decoder", - "Encoder", - "GobDecoder", - "GobEncoder", - "NewDecoder", - "NewEncoder", - "Register", - "RegisterName", - }, - "encoding/hex": { - "AppendDecode", - "AppendEncode", - "Decode", - "DecodeString", - "DecodedLen", - "Dump", - "Dumper", - "Encode", - "EncodeToString", - "EncodedLen", - "ErrLength", - "InvalidByteError", - "NewDecoder", - "NewEncoder", - }, - "encoding/json": { - "Compact", - "Decoder", - "Delim", - "Encoder", - "HTMLEscape", - "Indent", - "InvalidUTF8Error", - "InvalidUnmarshalError", - "Marshal", - "MarshalIndent", - "Marshaler", - "MarshalerError", - "NewDecoder", - "NewEncoder", - "Number", - "RawMessage", - "SyntaxError", - "Token", - "Unmarshal", - "UnmarshalFieldError", - "UnmarshalTypeError", - "Unmarshaler", - "UnsupportedTypeError", - "UnsupportedValueError", - "Valid", - }, - "encoding/pem": { - "Block", - "Decode", - "Encode", - "EncodeToMemory", - }, - "encoding/xml": { - "Attr", - "CharData", - "Comment", - "CopyToken", - "Decoder", - "Directive", - "Encoder", - "EndElement", - "Escape", - "EscapeText", - "HTMLAutoClose", - "HTMLEntity", - "Header", - "Marshal", - "MarshalIndent", - "Marshaler", - "MarshalerAttr", - "Name", - "NewDecoder", - "NewEncoder", - "NewTokenDecoder", - "ProcInst", - "StartElement", - "SyntaxError", - "TagPathError", - "Token", - "TokenReader", - "Unmarshal", - "UnmarshalError", - "Unmarshaler", - "UnmarshalerAttr", - "UnsupportedTypeError", - }, - "errors": { - "As", - "ErrUnsupported", - "Is", - "Join", - "New", - "Unwrap", - }, - "expvar": { - "Do", - "Float", - "Func", - "Get", - "Handler", - "Int", - "KeyValue", - "Map", - "NewFloat", - "NewInt", - "NewMap", - "NewString", - "Publish", - "String", - "Var", - }, - "flag": { - "Arg", - "Args", - "Bool", - "BoolFunc", - "BoolVar", - "CommandLine", - "ContinueOnError", - "Duration", - "DurationVar", - "ErrHelp", - "ErrorHandling", - "ExitOnError", - "Flag", - "FlagSet", - "Float64", - "Float64Var", - "Func", - "Getter", - "Int", - "Int64", - "Int64Var", - "IntVar", - "Lookup", - "NArg", - "NFlag", - "NewFlagSet", - "PanicOnError", - "Parse", - "Parsed", - "PrintDefaults", - "Set", - "String", - "StringVar", - "TextVar", - "Uint", - "Uint64", - "Uint64Var", - "UintVar", - "UnquoteUsage", - "Usage", - "Value", - "Var", - "Visit", - "VisitAll", - }, - "fmt": { - "Append", - "Appendf", - "Appendln", - "Errorf", - "FormatString", - "Formatter", - "Fprint", - "Fprintf", - "Fprintln", - "Fscan", - "Fscanf", - "Fscanln", - "GoStringer", - "Print", - "Printf", - "Println", - "Scan", - "ScanState", - "Scanf", - "Scanln", - "Scanner", - "Sprint", - "Sprintf", - "Sprintln", - "Sscan", - "Sscanf", - "Sscanln", - "State", - "Stringer", - }, - "go/ast": { - "ArrayType", - "AssignStmt", - "Bad", - "BadDecl", - "BadExpr", - "BadStmt", - "BasicLit", - "BinaryExpr", - "BlockStmt", - "BranchStmt", - "CallExpr", - "CaseClause", - "ChanDir", - "ChanType", - "CommClause", - "Comment", - "CommentGroup", - "CommentMap", - "CompositeLit", - "Con", - "Decl", - "DeclStmt", - "DeferStmt", - "Ellipsis", - "EmptyStmt", - "Expr", - "ExprStmt", - "Field", - "FieldFilter", - "FieldList", - "File", - "FileExports", - "Filter", - "FilterDecl", - "FilterFile", - "FilterFuncDuplicates", - "FilterImportDuplicates", - "FilterPackage", - "FilterUnassociatedComments", - "ForStmt", - "Fprint", - "Fun", - "FuncDecl", - "FuncLit", - "FuncType", - "GenDecl", - "GoStmt", - "Ident", - "IfStmt", - "ImportSpec", - "Importer", - "IncDecStmt", - "IndexExpr", - "IndexListExpr", - "Inspect", - "InterfaceType", - "IsExported", - "IsGenerated", - "KeyValueExpr", - "LabeledStmt", - "Lbl", - "MapType", - "MergeMode", - "MergePackageFiles", - "NewCommentMap", - "NewIdent", - "NewObj", - "NewPackage", - "NewScope", - "Node", - "NotNilFilter", - "ObjKind", - "Object", - "Package", - "PackageExports", - "ParenExpr", - "Pkg", - "Print", - "RECV", - "RangeStmt", - "ReturnStmt", - "SEND", - "Scope", - "SelectStmt", - "SelectorExpr", - "SendStmt", - "SliceExpr", - "SortImports", - "Spec", - "StarExpr", - "Stmt", - "StructType", - "SwitchStmt", - "Typ", - "TypeAssertExpr", - "TypeSpec", - "TypeSwitchStmt", - "UnaryExpr", - "Unparen", - "ValueSpec", - "Var", - "Visitor", - "Walk", - }, - "go/build": { - "AllowBinary", - "ArchChar", - "Context", - "Default", - "Directive", - "FindOnly", - "IgnoreVendor", - "Import", - "ImportComment", - "ImportDir", - "ImportMode", - "IsLocalImport", - "MultiplePackageError", - "NoGoError", - "Package", - "ToolDir", - }, - "go/build/constraint": { - "AndExpr", - "Expr", - "GoVersion", - "IsGoBuild", - "IsPlusBuild", - "NotExpr", - "OrExpr", - "Parse", - "PlusBuildLines", - "SyntaxError", - "TagExpr", - }, - "go/constant": { - "BinaryOp", - "BitLen", - "Bool", - "BoolVal", - "Bytes", - "Compare", - "Complex", - "Denom", - "Float", - "Float32Val", - "Float64Val", - "Imag", - "Int", - "Int64Val", - "Kind", - "Make", - "MakeBool", - "MakeFloat64", - "MakeFromBytes", - "MakeFromLiteral", - "MakeImag", - "MakeInt64", - "MakeString", - "MakeUint64", - "MakeUnknown", - "Num", - "Real", - "Shift", - "Sign", - "String", - "StringVal", - "ToComplex", - "ToFloat", - "ToInt", - "Uint64Val", - "UnaryOp", - "Unknown", - "Val", - "Value", - }, - "go/doc": { - "AllDecls", - "AllMethods", - "Example", - "Examples", - "Filter", - "Func", - "IllegalPrefixes", - "IsPredeclared", - "Mode", - "New", - "NewFromFiles", - "Note", - "Package", - "PreserveAST", - "Synopsis", - "ToHTML", - "ToText", - "Type", - "Value", - }, - "go/doc/comment": { - "Block", - "Code", - "DefaultLookupPackage", - "Doc", - "DocLink", - "Heading", - "Italic", - "Link", - "LinkDef", - "List", - "ListItem", - "Paragraph", - "Parser", - "Plain", - "Printer", - "Text", - }, - "go/format": { - "Node", - "Source", - }, - "go/importer": { - "Default", - "For", - "ForCompiler", - "Lookup", - }, - "go/parser": { - "AllErrors", - "DeclarationErrors", - "ImportsOnly", - "Mode", - "PackageClauseOnly", - "ParseComments", - "ParseDir", - "ParseExpr", - "ParseExprFrom", - "ParseFile", - "SkipObjectResolution", - "SpuriousErrors", - "Trace", - }, - "go/printer": { - "CommentedNode", - "Config", - "Fprint", - "Mode", - "RawFormat", - "SourcePos", - "TabIndent", - "UseSpaces", - }, - "go/scanner": { - "Error", - "ErrorHandler", - "ErrorList", - "Mode", - "PrintError", - "ScanComments", - "Scanner", - }, - "go/token": { - "ADD", - "ADD_ASSIGN", - "AND", - "AND_ASSIGN", - "AND_NOT", - "AND_NOT_ASSIGN", - "ARROW", - "ASSIGN", - "BREAK", - "CASE", - "CHAN", - "CHAR", - "COLON", - "COMMA", - "COMMENT", - "CONST", - "CONTINUE", - "DEC", - "DEFAULT", - "DEFER", - "DEFINE", - "ELLIPSIS", - "ELSE", - "EOF", - "EQL", - "FALLTHROUGH", - "FLOAT", - "FOR", - "FUNC", - "File", - "FileSet", - "GEQ", - "GO", - "GOTO", - "GTR", - "HighestPrec", - "IDENT", - "IF", - "ILLEGAL", - "IMAG", - "IMPORT", - "INC", - "INT", - "INTERFACE", - "IsExported", - "IsIdentifier", - "IsKeyword", - "LAND", - "LBRACE", - "LBRACK", - "LEQ", - "LOR", - "LPAREN", - "LSS", - "Lookup", - "LowestPrec", - "MAP", - "MUL", - "MUL_ASSIGN", - "NEQ", - "NOT", - "NewFileSet", - "NoPos", - "OR", - "OR_ASSIGN", - "PACKAGE", - "PERIOD", - "Pos", - "Position", - "QUO", - "QUO_ASSIGN", - "RANGE", - "RBRACE", - "RBRACK", - "REM", - "REM_ASSIGN", - "RETURN", - "RPAREN", - "SELECT", - "SEMICOLON", - "SHL", - "SHL_ASSIGN", - "SHR", - "SHR_ASSIGN", - "STRING", - "STRUCT", - "SUB", - "SUB_ASSIGN", - "SWITCH", - "TILDE", - "TYPE", - "Token", - "UnaryPrec", - "VAR", - "XOR", - "XOR_ASSIGN", - }, - "go/types": { - "Alias", - "ArgumentError", - "Array", - "AssertableTo", - "AssignableTo", - "Basic", - "BasicInfo", - "BasicKind", - "Bool", - "Builtin", - "Byte", - "Chan", - "ChanDir", - "CheckExpr", - "Checker", - "Comparable", - "Complex128", - "Complex64", - "Config", - "Const", - "Context", - "ConvertibleTo", - "DefPredeclaredTestFuncs", - "Default", - "Error", - "Eval", - "ExprString", - "FieldVal", - "Float32", - "Float64", - "Func", - "Id", - "Identical", - "IdenticalIgnoreTags", - "Implements", - "ImportMode", - "Importer", - "ImporterFrom", - "Info", - "Initializer", - "Instance", - "Instantiate", - "Int", - "Int16", - "Int32", - "Int64", - "Int8", - "Interface", - "Invalid", - "IsBoolean", - "IsComplex", - "IsConstType", - "IsFloat", - "IsInteger", - "IsInterface", - "IsNumeric", - "IsOrdered", - "IsString", - "IsUnsigned", - "IsUntyped", - "Label", - "LookupFieldOrMethod", - "Map", - "MethodExpr", - "MethodSet", - "MethodVal", - "MissingMethod", - "Named", - "NewAlias", - "NewArray", - "NewChan", - "NewChecker", - "NewConst", - "NewContext", - "NewField", - "NewFunc", - "NewInterface", - "NewInterfaceType", - "NewLabel", - "NewMap", - "NewMethodSet", - "NewNamed", - "NewPackage", - "NewParam", - "NewPkgName", - "NewPointer", - "NewScope", - "NewSignature", - "NewSignatureType", - "NewSlice", - "NewStruct", - "NewTerm", - "NewTuple", - "NewTypeName", - "NewTypeParam", - "NewUnion", - "NewVar", - "Nil", - "Object", - "ObjectString", - "Package", - "PkgName", - "Pointer", - "Qualifier", - "RecvOnly", - "RelativeTo", - "Rune", - "Satisfies", - "Scope", - "Selection", - "SelectionKind", - "SelectionString", - "SendOnly", - "SendRecv", - "Signature", - "Sizes", - "SizesFor", - "Slice", - "StdSizes", - "String", - "Struct", - "Term", - "Tuple", - "Typ", - "Type", - "TypeAndValue", - "TypeList", - "TypeName", - "TypeParam", - "TypeParamList", - "TypeString", - "Uint", - "Uint16", - "Uint32", - "Uint64", - "Uint8", - "Uintptr", - "Unalias", - "Union", - "Universe", - "Unsafe", - "UnsafePointer", - "UntypedBool", - "UntypedComplex", - "UntypedFloat", - "UntypedInt", - "UntypedNil", - "UntypedRune", - "UntypedString", - "Var", - "WriteExpr", - "WriteSignature", - "WriteType", - }, - "go/version": { - "Compare", - "IsValid", - "Lang", - }, - "hash": { - "Hash", - "Hash32", - "Hash64", - }, - "hash/adler32": { - "Checksum", - "New", - "Size", - }, - "hash/crc32": { - "Castagnoli", - "Checksum", - "ChecksumIEEE", - "IEEE", - "IEEETable", - "Koopman", - "MakeTable", - "New", - "NewIEEE", - "Size", - "Table", - "Update", - }, - "hash/crc64": { - "Checksum", - "ECMA", - "ISO", - "MakeTable", - "New", - "Size", - "Table", - "Update", - }, - "hash/fnv": { - "New128", - "New128a", - "New32", - "New32a", - "New64", - "New64a", - }, - "hash/maphash": { - "Bytes", - "Hash", - "MakeSeed", - "Seed", - "String", - }, - "html": { - "EscapeString", - "UnescapeString", - }, - "html/template": { - "CSS", - "ErrAmbigContext", - "ErrBadHTML", - "ErrBranchEnd", - "ErrEndContext", - "ErrJSTemplate", - "ErrNoSuchTemplate", - "ErrOutputContext", - "ErrPartialCharset", - "ErrPartialEscape", - "ErrPredefinedEscaper", - "ErrRangeLoopReentry", - "ErrSlashAmbig", - "Error", - "ErrorCode", - "FuncMap", - "HTML", - "HTMLAttr", - "HTMLEscape", - "HTMLEscapeString", - "HTMLEscaper", - "IsTrue", - "JS", - "JSEscape", - "JSEscapeString", - "JSEscaper", - "JSStr", - "Must", - "New", - "OK", - "ParseFS", - "ParseFiles", - "ParseGlob", - "Srcset", - "Template", - "URL", - "URLQueryEscaper", - }, - "image": { - "Alpha", - "Alpha16", - "Black", - "CMYK", - "Config", - "Decode", - "DecodeConfig", - "ErrFormat", - "Gray", - "Gray16", - "Image", - "NRGBA", - "NRGBA64", - "NYCbCrA", - "NewAlpha", - "NewAlpha16", - "NewCMYK", - "NewGray", - "NewGray16", - "NewNRGBA", - "NewNRGBA64", - "NewNYCbCrA", - "NewPaletted", - "NewRGBA", - "NewRGBA64", - "NewUniform", - "NewYCbCr", - "Opaque", - "Paletted", - "PalettedImage", - "Point", - "Pt", - "RGBA", - "RGBA64", - "RGBA64Image", - "Rect", - "Rectangle", - "RegisterFormat", - "Transparent", - "Uniform", - "White", - "YCbCr", - "YCbCrSubsampleRatio", - "YCbCrSubsampleRatio410", - "YCbCrSubsampleRatio411", - "YCbCrSubsampleRatio420", - "YCbCrSubsampleRatio422", - "YCbCrSubsampleRatio440", - "YCbCrSubsampleRatio444", - "ZP", - "ZR", - }, - "image/color": { - "Alpha", - "Alpha16", - "Alpha16Model", - "AlphaModel", - "Black", - "CMYK", - "CMYKModel", - "CMYKToRGB", - "Color", - "Gray", - "Gray16", - "Gray16Model", - "GrayModel", - "Model", - "ModelFunc", - "NRGBA", - "NRGBA64", - "NRGBA64Model", - "NRGBAModel", - "NYCbCrA", - "NYCbCrAModel", - "Opaque", - "Palette", - "RGBA", - "RGBA64", - "RGBA64Model", - "RGBAModel", - "RGBToCMYK", - "RGBToYCbCr", - "Transparent", - "White", - "YCbCr", - "YCbCrModel", - "YCbCrToRGB", - }, - "image/color/palette": { - "Plan9", - "WebSafe", - }, - "image/draw": { - "Draw", - "DrawMask", - "Drawer", - "FloydSteinberg", - "Image", - "Op", - "Over", - "Quantizer", - "RGBA64Image", - "Src", - }, - "image/gif": { - "Decode", - "DecodeAll", - "DecodeConfig", - "DisposalBackground", - "DisposalNone", - "DisposalPrevious", - "Encode", - "EncodeAll", - "GIF", - "Options", - }, - "image/jpeg": { - "Decode", - "DecodeConfig", - "DefaultQuality", - "Encode", - "FormatError", - "Options", - "Reader", - "UnsupportedError", - }, - "image/png": { - "BestCompression", - "BestSpeed", - "CompressionLevel", - "Decode", - "DecodeConfig", - "DefaultCompression", - "Encode", - "Encoder", - "EncoderBuffer", - "EncoderBufferPool", - "FormatError", - "NoCompression", - "UnsupportedError", - }, - "index/suffixarray": { - "Index", - "New", - }, - "io": { - "ByteReader", - "ByteScanner", - "ByteWriter", - "Closer", - "Copy", - "CopyBuffer", - "CopyN", - "Discard", - "EOF", - "ErrClosedPipe", - "ErrNoProgress", - "ErrShortBuffer", - "ErrShortWrite", - "ErrUnexpectedEOF", - "LimitReader", - "LimitedReader", - "MultiReader", - "MultiWriter", - "NewOffsetWriter", - "NewSectionReader", - "NopCloser", - "OffsetWriter", - "Pipe", - "PipeReader", - "PipeWriter", - "ReadAll", - "ReadAtLeast", - "ReadCloser", - "ReadFull", - "ReadSeekCloser", - "ReadSeeker", - "ReadWriteCloser", - "ReadWriteSeeker", - "ReadWriter", - "Reader", - "ReaderAt", - "ReaderFrom", - "RuneReader", - "RuneScanner", - "SectionReader", - "SeekCurrent", - "SeekEnd", - "SeekStart", - "Seeker", - "StringWriter", - "TeeReader", - "WriteCloser", - "WriteSeeker", - "WriteString", - "Writer", - "WriterAt", - "WriterTo", - }, - "io/fs": { - "DirEntry", - "ErrClosed", - "ErrExist", - "ErrInvalid", - "ErrNotExist", - "ErrPermission", - "FS", - "File", - "FileInfo", - "FileInfoToDirEntry", - "FileMode", - "FormatDirEntry", - "FormatFileInfo", - "Glob", - "GlobFS", - "ModeAppend", - "ModeCharDevice", - "ModeDevice", - "ModeDir", - "ModeExclusive", - "ModeIrregular", - "ModeNamedPipe", - "ModePerm", - "ModeSetgid", - "ModeSetuid", - "ModeSocket", - "ModeSticky", - "ModeSymlink", - "ModeTemporary", - "ModeType", - "PathError", - "ReadDir", - "ReadDirFS", - "ReadDirFile", - "ReadFile", - "ReadFileFS", - "SkipAll", - "SkipDir", - "Stat", - "StatFS", - "Sub", - "SubFS", - "ValidPath", - "WalkDir", - "WalkDirFunc", - }, - "io/ioutil": { - "Discard", - "NopCloser", - "ReadAll", - "ReadDir", - "ReadFile", - "TempDir", - "TempFile", - "WriteFile", - }, - "log": { - "Default", - "Fatal", - "Fatalf", - "Fatalln", - "Flags", - "LUTC", - "Ldate", - "Llongfile", - "Lmicroseconds", - "Lmsgprefix", - "Logger", - "Lshortfile", - "LstdFlags", - "Ltime", - "New", - "Output", - "Panic", - "Panicf", - "Panicln", - "Prefix", - "Print", - "Printf", - "Println", - "SetFlags", - "SetOutput", - "SetPrefix", - "Writer", - }, - "log/slog": { - "Any", - "AnyValue", - "Attr", - "Bool", - "BoolValue", - "Debug", - "DebugContext", - "Default", - "Duration", - "DurationValue", - "Error", - "ErrorContext", - "Float64", - "Float64Value", - "Group", - "GroupValue", - "Handler", - "HandlerOptions", - "Info", - "InfoContext", - "Int", - "Int64", - "Int64Value", - "IntValue", - "JSONHandler", - "Kind", - "KindAny", - "KindBool", - "KindDuration", - "KindFloat64", - "KindGroup", - "KindInt64", - "KindLogValuer", - "KindString", - "KindTime", - "KindUint64", - "Level", - "LevelDebug", - "LevelError", - "LevelInfo", - "LevelKey", - "LevelVar", - "LevelWarn", - "Leveler", - "Log", - "LogAttrs", - "LogValuer", - "Logger", - "MessageKey", - "New", - "NewJSONHandler", - "NewLogLogger", - "NewRecord", - "NewTextHandler", - "Record", - "SetDefault", - "SetLogLoggerLevel", - "Source", - "SourceKey", - "String", - "StringValue", - "TextHandler", - "Time", - "TimeKey", - "TimeValue", - "Uint64", - "Uint64Value", - "Value", - "Warn", - "WarnContext", - "With", - }, - "log/syslog": { - "Dial", - "LOG_ALERT", - "LOG_AUTH", - "LOG_AUTHPRIV", - "LOG_CRIT", - "LOG_CRON", - "LOG_DAEMON", - "LOG_DEBUG", - "LOG_EMERG", - "LOG_ERR", - "LOG_FTP", - "LOG_INFO", - "LOG_KERN", - "LOG_LOCAL0", - "LOG_LOCAL1", - "LOG_LOCAL2", - "LOG_LOCAL3", - "LOG_LOCAL4", - "LOG_LOCAL5", - "LOG_LOCAL6", - "LOG_LOCAL7", - "LOG_LPR", - "LOG_MAIL", - "LOG_NEWS", - "LOG_NOTICE", - "LOG_SYSLOG", - "LOG_USER", - "LOG_UUCP", - "LOG_WARNING", - "New", - "NewLogger", - "Priority", - "Writer", - }, - "maps": { - "Clone", - "Copy", - "DeleteFunc", - "Equal", - "EqualFunc", - }, - "math": { - "Abs", - "Acos", - "Acosh", - "Asin", - "Asinh", - "Atan", - "Atan2", - "Atanh", - "Cbrt", - "Ceil", - "Copysign", - "Cos", - "Cosh", - "Dim", - "E", - "Erf", - "Erfc", - "Erfcinv", - "Erfinv", - "Exp", - "Exp2", - "Expm1", - "FMA", - "Float32bits", - "Float32frombits", - "Float64bits", - "Float64frombits", - "Floor", - "Frexp", - "Gamma", - "Hypot", - "Ilogb", - "Inf", - "IsInf", - "IsNaN", - "J0", - "J1", - "Jn", - "Ldexp", - "Lgamma", - "Ln10", - "Ln2", - "Log", - "Log10", - "Log10E", - "Log1p", - "Log2", - "Log2E", - "Logb", - "Max", - "MaxFloat32", - "MaxFloat64", - "MaxInt", - "MaxInt16", - "MaxInt32", - "MaxInt64", - "MaxInt8", - "MaxUint", - "MaxUint16", - "MaxUint32", - "MaxUint64", - "MaxUint8", - "Min", - "MinInt", - "MinInt16", - "MinInt32", - "MinInt64", - "MinInt8", - "Mod", - "Modf", - "NaN", - "Nextafter", - "Nextafter32", - "Phi", - "Pi", - "Pow", - "Pow10", - "Remainder", - "Round", - "RoundToEven", - "Signbit", - "Sin", - "Sincos", - "Sinh", - "SmallestNonzeroFloat32", - "SmallestNonzeroFloat64", - "Sqrt", - "Sqrt2", - "SqrtE", - "SqrtPhi", - "SqrtPi", - "Tan", - "Tanh", - "Trunc", - "Y0", - "Y1", - "Yn", - }, - "math/big": { - "Above", - "Accuracy", - "AwayFromZero", - "Below", - "ErrNaN", - "Exact", - "Float", - "Int", - "Jacobi", - "MaxBase", - "MaxExp", - "MaxPrec", - "MinExp", - "NewFloat", - "NewInt", - "NewRat", - "ParseFloat", - "Rat", - "RoundingMode", - "ToNearestAway", - "ToNearestEven", - "ToNegativeInf", - "ToPositiveInf", - "ToZero", - "Word", - }, - "math/bits": { - "Add", - "Add32", - "Add64", - "Div", - "Div32", - "Div64", - "LeadingZeros", - "LeadingZeros16", - "LeadingZeros32", - "LeadingZeros64", - "LeadingZeros8", - "Len", - "Len16", - "Len32", - "Len64", - "Len8", - "Mul", - "Mul32", - "Mul64", - "OnesCount", - "OnesCount16", - "OnesCount32", - "OnesCount64", - "OnesCount8", - "Rem", - "Rem32", - "Rem64", - "Reverse", - "Reverse16", - "Reverse32", - "Reverse64", - "Reverse8", - "ReverseBytes", - "ReverseBytes16", - "ReverseBytes32", - "ReverseBytes64", - "RotateLeft", - "RotateLeft16", - "RotateLeft32", - "RotateLeft64", - "RotateLeft8", - "Sub", - "Sub32", - "Sub64", - "TrailingZeros", - "TrailingZeros16", - "TrailingZeros32", - "TrailingZeros64", - "TrailingZeros8", - "UintSize", - }, - "math/cmplx": { - "Abs", - "Acos", - "Acosh", - "Asin", - "Asinh", - "Atan", - "Atanh", - "Conj", - "Cos", - "Cosh", - "Cot", - "Exp", - "Inf", - "IsInf", - "IsNaN", - "Log", - "Log10", - "NaN", - "Phase", - "Polar", - "Pow", - "Rect", - "Sin", - "Sinh", - "Sqrt", - "Tan", - "Tanh", - }, - "math/rand": { - "ExpFloat64", - "Float32", - "Float64", - "Int", - "Int31", - "Int31n", - "Int63", - "Int63n", - "Intn", - "New", - "NewSource", - "NewZipf", - "NormFloat64", - "Perm", - "Rand", - "Read", - "Seed", - "Shuffle", - "Source", - "Source64", - "Uint32", - "Uint64", - "Zipf", - }, - "math/rand/v2": { - "ChaCha8", - "ExpFloat64", - "Float32", - "Float64", - "Int", - "Int32", - "Int32N", - "Int64", - "Int64N", - "IntN", - "N", - "New", - "NewChaCha8", - "NewPCG", - "NewZipf", - "NormFloat64", - "PCG", - "Perm", - "Rand", - "Shuffle", - "Source", - "Uint32", - "Uint32N", - "Uint64", - "Uint64N", - "UintN", - "Zipf", - }, - "mime": { - "AddExtensionType", - "BEncoding", - "ErrInvalidMediaParameter", - "ExtensionsByType", - "FormatMediaType", - "ParseMediaType", - "QEncoding", - "TypeByExtension", - "WordDecoder", - "WordEncoder", - }, - "mime/multipart": { - "ErrMessageTooLarge", - "File", - "FileHeader", - "Form", - "NewReader", - "NewWriter", - "Part", - "Reader", - "Writer", - }, - "mime/quotedprintable": { - "NewReader", - "NewWriter", - "Reader", - "Writer", - }, - "net": { - "Addr", - "AddrError", - "Buffers", - "CIDRMask", - "Conn", - "DNSConfigError", - "DNSError", - "DefaultResolver", - "Dial", - "DialIP", - "DialTCP", - "DialTimeout", - "DialUDP", - "DialUnix", - "Dialer", - "ErrClosed", - "ErrWriteToConnected", - "Error", - "FileConn", - "FileListener", - "FilePacketConn", - "FlagBroadcast", - "FlagLoopback", - "FlagMulticast", - "FlagPointToPoint", - "FlagRunning", - "FlagUp", - "Flags", - "HardwareAddr", - "IP", - "IPAddr", - "IPConn", - "IPMask", - "IPNet", - "IPv4", - "IPv4Mask", - "IPv4allrouter", - "IPv4allsys", - "IPv4bcast", - "IPv4len", - "IPv4zero", - "IPv6interfacelocalallnodes", - "IPv6len", - "IPv6linklocalallnodes", - "IPv6linklocalallrouters", - "IPv6loopback", - "IPv6unspecified", - "IPv6zero", - "Interface", - "InterfaceAddrs", - "InterfaceByIndex", - "InterfaceByName", - "Interfaces", - "InvalidAddrError", - "JoinHostPort", - "Listen", - "ListenConfig", - "ListenIP", - "ListenMulticastUDP", - "ListenPacket", - "ListenTCP", - "ListenUDP", - "ListenUnix", - "ListenUnixgram", - "Listener", - "LookupAddr", - "LookupCNAME", - "LookupHost", - "LookupIP", - "LookupMX", - "LookupNS", - "LookupPort", - "LookupSRV", - "LookupTXT", - "MX", - "NS", - "OpError", - "PacketConn", - "ParseCIDR", - "ParseError", - "ParseIP", - "ParseMAC", - "Pipe", - "ResolveIPAddr", - "ResolveTCPAddr", - "ResolveUDPAddr", - "ResolveUnixAddr", - "Resolver", - "SRV", - "SplitHostPort", - "TCPAddr", - "TCPAddrFromAddrPort", - "TCPConn", - "TCPListener", - "UDPAddr", - "UDPAddrFromAddrPort", - "UDPConn", - "UnixAddr", - "UnixConn", - "UnixListener", - "UnknownNetworkError", - }, - "net/http": { - "AllowQuerySemicolons", - "CanonicalHeaderKey", - "Client", - "CloseNotifier", - "ConnState", - "Cookie", - "CookieJar", - "DefaultClient", - "DefaultMaxHeaderBytes", - "DefaultMaxIdleConnsPerHost", - "DefaultServeMux", - "DefaultTransport", - "DetectContentType", - "Dir", - "ErrAbortHandler", - "ErrBodyNotAllowed", - "ErrBodyReadAfterClose", - "ErrContentLength", - "ErrHandlerTimeout", - "ErrHeaderTooLong", - "ErrHijacked", - "ErrLineTooLong", - "ErrMissingBoundary", - "ErrMissingContentLength", - "ErrMissingFile", - "ErrNoCookie", - "ErrNoLocation", - "ErrNotMultipart", - "ErrNotSupported", - "ErrSchemeMismatch", - "ErrServerClosed", - "ErrShortBody", - "ErrSkipAltProtocol", - "ErrUnexpectedTrailer", - "ErrUseLastResponse", - "ErrWriteAfterFlush", - "Error", - "FS", - "File", - "FileServer", - "FileServerFS", - "FileSystem", - "Flusher", - "Get", - "Handle", - "HandleFunc", - "Handler", - "HandlerFunc", - "Head", - "Header", - "Hijacker", - "ListenAndServe", - "ListenAndServeTLS", - "LocalAddrContextKey", - "MaxBytesError", - "MaxBytesHandler", - "MaxBytesReader", - "MethodConnect", - "MethodDelete", - "MethodGet", - "MethodHead", - "MethodOptions", - "MethodPatch", - "MethodPost", - "MethodPut", - "MethodTrace", - "NewFileTransport", - "NewFileTransportFS", - "NewRequest", - "NewRequestWithContext", - "NewResponseController", - "NewServeMux", - "NoBody", - "NotFound", - "NotFoundHandler", - "ParseHTTPVersion", - "ParseTime", - "Post", - "PostForm", - "ProtocolError", - "ProxyFromEnvironment", - "ProxyURL", - "PushOptions", - "Pusher", - "ReadRequest", - "ReadResponse", - "Redirect", - "RedirectHandler", - "Request", - "Response", - "ResponseController", - "ResponseWriter", - "RoundTripper", - "SameSite", - "SameSiteDefaultMode", - "SameSiteLaxMode", - "SameSiteNoneMode", - "SameSiteStrictMode", - "Serve", - "ServeContent", - "ServeFile", - "ServeFileFS", - "ServeMux", - "ServeTLS", - "Server", - "ServerContextKey", - "SetCookie", - "StateActive", - "StateClosed", - "StateHijacked", - "StateIdle", - "StateNew", - "StatusAccepted", - "StatusAlreadyReported", - "StatusBadGateway", - "StatusBadRequest", - "StatusConflict", - "StatusContinue", - "StatusCreated", - "StatusEarlyHints", - "StatusExpectationFailed", - "StatusFailedDependency", - "StatusForbidden", - "StatusFound", - "StatusGatewayTimeout", - "StatusGone", - "StatusHTTPVersionNotSupported", - "StatusIMUsed", - "StatusInsufficientStorage", - "StatusInternalServerError", - "StatusLengthRequired", - "StatusLocked", - "StatusLoopDetected", - "StatusMethodNotAllowed", - "StatusMisdirectedRequest", - "StatusMovedPermanently", - "StatusMultiStatus", - "StatusMultipleChoices", - "StatusNetworkAuthenticationRequired", - "StatusNoContent", - "StatusNonAuthoritativeInfo", - "StatusNotAcceptable", - "StatusNotExtended", - "StatusNotFound", - "StatusNotImplemented", - "StatusNotModified", - "StatusOK", - "StatusPartialContent", - "StatusPaymentRequired", - "StatusPermanentRedirect", - "StatusPreconditionFailed", - "StatusPreconditionRequired", - "StatusProcessing", - "StatusProxyAuthRequired", - "StatusRequestEntityTooLarge", - "StatusRequestHeaderFieldsTooLarge", - "StatusRequestTimeout", - "StatusRequestURITooLong", - "StatusRequestedRangeNotSatisfiable", - "StatusResetContent", - "StatusSeeOther", - "StatusServiceUnavailable", - "StatusSwitchingProtocols", - "StatusTeapot", - "StatusTemporaryRedirect", - "StatusText", - "StatusTooEarly", - "StatusTooManyRequests", - "StatusUnauthorized", - "StatusUnavailableForLegalReasons", - "StatusUnprocessableEntity", - "StatusUnsupportedMediaType", - "StatusUpgradeRequired", - "StatusUseProxy", - "StatusVariantAlsoNegotiates", - "StripPrefix", - "TimeFormat", - "TimeoutHandler", - "TrailerPrefix", - "Transport", - }, - "net/http/cgi": { - "Handler", - "Request", - "RequestFromMap", - "Serve", - }, - "net/http/cookiejar": { - "Jar", - "New", - "Options", - "PublicSuffixList", - }, - "net/http/fcgi": { - "ErrConnClosed", - "ErrRequestAborted", - "ProcessEnv", - "Serve", - }, - "net/http/httptest": { - "DefaultRemoteAddr", - "NewRecorder", - "NewRequest", - "NewServer", - "NewTLSServer", - "NewUnstartedServer", - "ResponseRecorder", - "Server", - }, - "net/http/httptrace": { - "ClientTrace", - "ContextClientTrace", - "DNSDoneInfo", - "DNSStartInfo", - "GotConnInfo", - "WithClientTrace", - "WroteRequestInfo", - }, - "net/http/httputil": { - "BufferPool", - "ClientConn", - "DumpRequest", - "DumpRequestOut", - "DumpResponse", - "ErrClosed", - "ErrLineTooLong", - "ErrPersistEOF", - "ErrPipeline", - "NewChunkedReader", - "NewChunkedWriter", - "NewClientConn", - "NewProxyClientConn", - "NewServerConn", - "NewSingleHostReverseProxy", - "ProxyRequest", - "ReverseProxy", - "ServerConn", - }, - "net/http/pprof": { - "Cmdline", - "Handler", - "Index", - "Profile", - "Symbol", - "Trace", - }, - "net/mail": { - "Address", - "AddressParser", - "ErrHeaderNotPresent", - "Header", - "Message", - "ParseAddress", - "ParseAddressList", - "ParseDate", - "ReadMessage", - }, - "net/netip": { - "Addr", - "AddrFrom16", - "AddrFrom4", - "AddrFromSlice", - "AddrPort", - "AddrPortFrom", - "IPv4Unspecified", - "IPv6LinkLocalAllNodes", - "IPv6LinkLocalAllRouters", - "IPv6Loopback", - "IPv6Unspecified", - "MustParseAddr", - "MustParseAddrPort", - "MustParsePrefix", - "ParseAddr", - "ParseAddrPort", - "ParsePrefix", - "Prefix", - "PrefixFrom", - }, - "net/rpc": { - "Accept", - "Call", - "Client", - "ClientCodec", - "DefaultDebugPath", - "DefaultRPCPath", - "DefaultServer", - "Dial", - "DialHTTP", - "DialHTTPPath", - "ErrShutdown", - "HandleHTTP", - "NewClient", - "NewClientWithCodec", - "NewServer", - "Register", - "RegisterName", - "Request", - "Response", - "ServeCodec", - "ServeConn", - "ServeRequest", - "Server", - "ServerCodec", - "ServerError", - }, - "net/rpc/jsonrpc": { - "Dial", - "NewClient", - "NewClientCodec", - "NewServerCodec", - "ServeConn", - }, - "net/smtp": { - "Auth", - "CRAMMD5Auth", - "Client", - "Dial", - "NewClient", - "PlainAuth", - "SendMail", - "ServerInfo", - }, - "net/textproto": { - "CanonicalMIMEHeaderKey", - "Conn", - "Dial", - "Error", - "MIMEHeader", - "NewConn", - "NewReader", - "NewWriter", - "Pipeline", - "ProtocolError", - "Reader", - "TrimBytes", - "TrimString", - "Writer", - }, - "net/url": { - "Error", - "EscapeError", - "InvalidHostError", - "JoinPath", - "Parse", - "ParseQuery", - "ParseRequestURI", - "PathEscape", - "PathUnescape", - "QueryEscape", - "QueryUnescape", - "URL", - "User", - "UserPassword", - "Userinfo", - "Values", - }, - "os": { - "Args", - "Chdir", - "Chmod", - "Chown", - "Chtimes", - "Clearenv", - "Create", - "CreateTemp", - "DevNull", - "DirEntry", - "DirFS", - "Environ", - "ErrClosed", - "ErrDeadlineExceeded", - "ErrExist", - "ErrInvalid", - "ErrNoDeadline", - "ErrNotExist", - "ErrPermission", - "ErrProcessDone", - "Executable", - "Exit", - "Expand", - "ExpandEnv", - "File", - "FileInfo", - "FileMode", - "FindProcess", - "Getegid", - "Getenv", - "Geteuid", - "Getgid", - "Getgroups", - "Getpagesize", - "Getpid", - "Getppid", - "Getuid", - "Getwd", - "Hostname", - "Interrupt", - "IsExist", - "IsNotExist", - "IsPathSeparator", - "IsPermission", - "IsTimeout", - "Kill", - "Lchown", - "Link", - "LinkError", - "LookupEnv", - "Lstat", - "Mkdir", - "MkdirAll", - "MkdirTemp", - "ModeAppend", - "ModeCharDevice", - "ModeDevice", - "ModeDir", - "ModeExclusive", - "ModeIrregular", - "ModeNamedPipe", - "ModePerm", - "ModeSetgid", - "ModeSetuid", - "ModeSocket", - "ModeSticky", - "ModeSymlink", - "ModeTemporary", - "ModeType", - "NewFile", - "NewSyscallError", - "O_APPEND", - "O_CREATE", - "O_EXCL", - "O_RDONLY", - "O_RDWR", - "O_SYNC", - "O_TRUNC", - "O_WRONLY", - "Open", - "OpenFile", - "PathError", - "PathListSeparator", - "PathSeparator", - "Pipe", - "ProcAttr", - "Process", - "ProcessState", - "ReadDir", - "ReadFile", - "Readlink", - "Remove", - "RemoveAll", - "Rename", - "SEEK_CUR", - "SEEK_END", - "SEEK_SET", - "SameFile", - "Setenv", - "Signal", - "StartProcess", - "Stat", - "Stderr", - "Stdin", - "Stdout", - "Symlink", - "SyscallError", - "TempDir", - "Truncate", - "Unsetenv", - "UserCacheDir", - "UserConfigDir", - "UserHomeDir", - "WriteFile", - }, - "os/exec": { - "Cmd", - "Command", - "CommandContext", - "ErrDot", - "ErrNotFound", - "ErrWaitDelay", - "Error", - "ExitError", - "LookPath", - }, - "os/signal": { - "Ignore", - "Ignored", - "Notify", - "NotifyContext", - "Reset", - "Stop", - }, - "os/user": { - "Current", - "Group", - "Lookup", - "LookupGroup", - "LookupGroupId", - "LookupId", - "UnknownGroupError", - "UnknownGroupIdError", - "UnknownUserError", - "UnknownUserIdError", - "User", - }, - "path": { - "Base", - "Clean", - "Dir", - "ErrBadPattern", - "Ext", - "IsAbs", - "Join", - "Match", - "Split", - }, - "path/filepath": { - "Abs", - "Base", - "Clean", - "Dir", - "ErrBadPattern", - "EvalSymlinks", - "Ext", - "FromSlash", - "Glob", - "HasPrefix", - "IsAbs", - "IsLocal", - "Join", - "ListSeparator", - "Match", - "Rel", - "Separator", - "SkipAll", - "SkipDir", - "Split", - "SplitList", - "ToSlash", - "VolumeName", - "Walk", - "WalkDir", - "WalkFunc", - }, - "plugin": { - "Open", - "Plugin", - "Symbol", - }, - "reflect": { - "Append", - "AppendSlice", - "Array", - "ArrayOf", - "Bool", - "BothDir", - "Chan", - "ChanDir", - "ChanOf", - "Complex128", - "Complex64", - "Copy", - "DeepEqual", - "Float32", - "Float64", - "Func", - "FuncOf", - "Indirect", - "Int", - "Int16", - "Int32", - "Int64", - "Int8", - "Interface", - "Invalid", - "Kind", - "MakeChan", - "MakeFunc", - "MakeMap", - "MakeMapWithSize", - "MakeSlice", - "Map", - "MapIter", - "MapOf", - "Method", - "New", - "NewAt", - "Pointer", - "PointerTo", - "Ptr", - "PtrTo", - "RecvDir", - "Select", - "SelectCase", - "SelectDefault", - "SelectDir", - "SelectRecv", - "SelectSend", - "SendDir", - "Slice", - "SliceHeader", - "SliceOf", - "String", - "StringHeader", - "Struct", - "StructField", - "StructOf", - "StructTag", - "Swapper", - "Type", - "TypeFor", - "TypeOf", - "Uint", - "Uint16", - "Uint32", - "Uint64", - "Uint8", - "Uintptr", - "UnsafePointer", - "Value", - "ValueError", - "ValueOf", - "VisibleFields", - "Zero", - }, - "regexp": { - "Compile", - "CompilePOSIX", - "Match", - "MatchReader", - "MatchString", - "MustCompile", - "MustCompilePOSIX", - "QuoteMeta", - "Regexp", - }, - "regexp/syntax": { - "ClassNL", - "Compile", - "DotNL", - "EmptyBeginLine", - "EmptyBeginText", - "EmptyEndLine", - "EmptyEndText", - "EmptyNoWordBoundary", - "EmptyOp", - "EmptyOpContext", - "EmptyWordBoundary", - "ErrInternalError", - "ErrInvalidCharClass", - "ErrInvalidCharRange", - "ErrInvalidEscape", - "ErrInvalidNamedCapture", - "ErrInvalidPerlOp", - "ErrInvalidRepeatOp", - "ErrInvalidRepeatSize", - "ErrInvalidUTF8", - "ErrLarge", - "ErrMissingBracket", - "ErrMissingParen", - "ErrMissingRepeatArgument", - "ErrNestingDepth", - "ErrTrailingBackslash", - "ErrUnexpectedParen", - "Error", - "ErrorCode", - "Flags", - "FoldCase", - "Inst", - "InstAlt", - "InstAltMatch", - "InstCapture", - "InstEmptyWidth", - "InstFail", - "InstMatch", - "InstNop", - "InstOp", - "InstRune", - "InstRune1", - "InstRuneAny", - "InstRuneAnyNotNL", - "IsWordChar", - "Literal", - "MatchNL", - "NonGreedy", - "OneLine", - "Op", - "OpAlternate", - "OpAnyChar", - "OpAnyCharNotNL", - "OpBeginLine", - "OpBeginText", - "OpCapture", - "OpCharClass", - "OpConcat", - "OpEmptyMatch", - "OpEndLine", - "OpEndText", - "OpLiteral", - "OpNoMatch", - "OpNoWordBoundary", - "OpPlus", - "OpQuest", - "OpRepeat", - "OpStar", - "OpWordBoundary", - "POSIX", - "Parse", - "Perl", - "PerlX", - "Prog", - "Regexp", - "Simple", - "UnicodeGroups", - "WasDollar", - }, - "runtime": { - "BlockProfile", - "BlockProfileRecord", - "Breakpoint", - "CPUProfile", - "Caller", - "Callers", - "CallersFrames", - "Compiler", - "Error", - "Frame", - "Frames", - "Func", - "FuncForPC", - "GC", - "GOARCH", - "GOMAXPROCS", - "GOOS", - "GOROOT", - "Goexit", - "GoroutineProfile", - "Gosched", - "KeepAlive", - "LockOSThread", - "MemProfile", - "MemProfileRate", - "MemProfileRecord", - "MemStats", - "MutexProfile", - "NumCPU", - "NumCgoCall", - "NumGoroutine", - "PanicNilError", - "Pinner", - "ReadMemStats", - "ReadTrace", - "SetBlockProfileRate", - "SetCPUProfileRate", - "SetCgoTraceback", - "SetFinalizer", - "SetMutexProfileFraction", - "Stack", - "StackRecord", - "StartTrace", - "StopTrace", - "ThreadCreateProfile", - "TypeAssertionError", - "UnlockOSThread", - "Version", - }, - "runtime/cgo": { - "Handle", - "Incomplete", - "NewHandle", - }, - "runtime/coverage": { - "ClearCounters", - "WriteCounters", - "WriteCountersDir", - "WriteMeta", - "WriteMetaDir", - }, - "runtime/debug": { - "BuildInfo", - "BuildSetting", - "FreeOSMemory", - "GCStats", - "Module", - "ParseBuildInfo", - "PrintStack", - "ReadBuildInfo", - "ReadGCStats", - "SetGCPercent", - "SetMaxStack", - "SetMaxThreads", - "SetMemoryLimit", - "SetPanicOnFault", - "SetTraceback", - "Stack", - "WriteHeapDump", - }, - "runtime/metrics": { - "All", - "Description", - "Float64Histogram", - "KindBad", - "KindFloat64", - "KindFloat64Histogram", - "KindUint64", - "Read", - "Sample", - "Value", - "ValueKind", - }, - "runtime/pprof": { - "Do", - "ForLabels", - "Label", - "LabelSet", - "Labels", - "Lookup", - "NewProfile", - "Profile", - "Profiles", - "SetGoroutineLabels", - "StartCPUProfile", - "StopCPUProfile", - "WithLabels", - "WriteHeapProfile", - }, - "runtime/trace": { - "IsEnabled", - "Log", - "Logf", - "NewTask", - "Region", - "Start", - "StartRegion", - "Stop", - "Task", - "WithRegion", - }, - "slices": { - "BinarySearch", - "BinarySearchFunc", - "Clip", - "Clone", - "Compact", - "CompactFunc", - "Compare", - "CompareFunc", - "Concat", - "Contains", - "ContainsFunc", - "Delete", - "DeleteFunc", - "Equal", - "EqualFunc", - "Grow", - "Index", - "IndexFunc", - "Insert", - "IsSorted", - "IsSortedFunc", - "Max", - "MaxFunc", - "Min", - "MinFunc", - "Replace", - "Reverse", - "Sort", - "SortFunc", - "SortStableFunc", - }, - "sort": { - "Find", - "Float64Slice", - "Float64s", - "Float64sAreSorted", - "IntSlice", - "Interface", - "Ints", - "IntsAreSorted", - "IsSorted", - "Reverse", - "Search", - "SearchFloat64s", - "SearchInts", - "SearchStrings", - "Slice", - "SliceIsSorted", - "SliceStable", - "Sort", - "Stable", - "StringSlice", - "Strings", - "StringsAreSorted", - }, - "strconv": { - "AppendBool", - "AppendFloat", - "AppendInt", - "AppendQuote", - "AppendQuoteRune", - "AppendQuoteRuneToASCII", - "AppendQuoteRuneToGraphic", - "AppendQuoteToASCII", - "AppendQuoteToGraphic", - "AppendUint", - "Atoi", - "CanBackquote", - "ErrRange", - "ErrSyntax", - "FormatBool", - "FormatComplex", - "FormatFloat", - "FormatInt", - "FormatUint", - "IntSize", - "IsGraphic", - "IsPrint", - "Itoa", - "NumError", - "ParseBool", - "ParseComplex", - "ParseFloat", - "ParseInt", - "ParseUint", - "Quote", - "QuoteRune", - "QuoteRuneToASCII", - "QuoteRuneToGraphic", - "QuoteToASCII", - "QuoteToGraphic", - "QuotedPrefix", - "Unquote", - "UnquoteChar", - }, - "strings": { - "Builder", - "Clone", - "Compare", - "Contains", - "ContainsAny", - "ContainsFunc", - "ContainsRune", - "Count", - "Cut", - "CutPrefix", - "CutSuffix", - "EqualFold", - "Fields", - "FieldsFunc", - "HasPrefix", - "HasSuffix", - "Index", - "IndexAny", - "IndexByte", - "IndexFunc", - "IndexRune", - "Join", - "LastIndex", - "LastIndexAny", - "LastIndexByte", - "LastIndexFunc", - "Map", - "NewReader", - "NewReplacer", - "Reader", - "Repeat", - "Replace", - "ReplaceAll", - "Replacer", - "Split", - "SplitAfter", - "SplitAfterN", - "SplitN", - "Title", - "ToLower", - "ToLowerSpecial", - "ToTitle", - "ToTitleSpecial", - "ToUpper", - "ToUpperSpecial", - "ToValidUTF8", - "Trim", - "TrimFunc", - "TrimLeft", - "TrimLeftFunc", - "TrimPrefix", - "TrimRight", - "TrimRightFunc", - "TrimSpace", - "TrimSuffix", - }, - "sync": { - "Cond", - "Locker", - "Map", - "Mutex", - "NewCond", - "Once", - "OnceFunc", - "OnceValue", - "OnceValues", - "Pool", - "RWMutex", - "WaitGroup", - }, - "sync/atomic": { - "AddInt32", - "AddInt64", - "AddUint32", - "AddUint64", - "AddUintptr", - "Bool", - "CompareAndSwapInt32", - "CompareAndSwapInt64", - "CompareAndSwapPointer", - "CompareAndSwapUint32", - "CompareAndSwapUint64", - "CompareAndSwapUintptr", - "Int32", - "Int64", - "LoadInt32", - "LoadInt64", - "LoadPointer", - "LoadUint32", - "LoadUint64", - "LoadUintptr", - "Pointer", - "StoreInt32", - "StoreInt64", - "StorePointer", - "StoreUint32", - "StoreUint64", - "StoreUintptr", - "SwapInt32", - "SwapInt64", - "SwapPointer", - "SwapUint32", - "SwapUint64", - "SwapUintptr", - "Uint32", - "Uint64", - "Uintptr", - "Value", - }, - "syscall": { - "AF_ALG", - "AF_APPLETALK", - "AF_ARP", - "AF_ASH", - "AF_ATM", - "AF_ATMPVC", - "AF_ATMSVC", - "AF_AX25", - "AF_BLUETOOTH", - "AF_BRIDGE", - "AF_CAIF", - "AF_CAN", - "AF_CCITT", - "AF_CHAOS", - "AF_CNT", - "AF_COIP", - "AF_DATAKIT", - "AF_DECnet", - "AF_DLI", - "AF_E164", - "AF_ECMA", - "AF_ECONET", - "AF_ENCAP", - "AF_FILE", - "AF_HYLINK", - "AF_IEEE80211", - "AF_IEEE802154", - "AF_IMPLINK", - "AF_INET", - "AF_INET6", - "AF_INET6_SDP", - "AF_INET_SDP", - "AF_IPX", - "AF_IRDA", - "AF_ISDN", - "AF_ISO", - "AF_IUCV", - "AF_KEY", - "AF_LAT", - "AF_LINK", - "AF_LLC", - "AF_LOCAL", - "AF_MAX", - "AF_MPLS", - "AF_NATM", - "AF_NDRV", - "AF_NETBEUI", - "AF_NETBIOS", - "AF_NETGRAPH", - "AF_NETLINK", - "AF_NETROM", - "AF_NS", - "AF_OROUTE", - "AF_OSI", - "AF_PACKET", - "AF_PHONET", - "AF_PPP", - "AF_PPPOX", - "AF_PUP", - "AF_RDS", - "AF_RESERVED_36", - "AF_ROSE", - "AF_ROUTE", - "AF_RXRPC", - "AF_SCLUSTER", - "AF_SECURITY", - "AF_SIP", - "AF_SLOW", - "AF_SNA", - "AF_SYSTEM", - "AF_TIPC", - "AF_UNIX", - "AF_UNSPEC", - "AF_UTUN", - "AF_VENDOR00", - "AF_VENDOR01", - "AF_VENDOR02", - "AF_VENDOR03", - "AF_VENDOR04", - "AF_VENDOR05", - "AF_VENDOR06", - "AF_VENDOR07", - "AF_VENDOR08", - "AF_VENDOR09", - "AF_VENDOR10", - "AF_VENDOR11", - "AF_VENDOR12", - "AF_VENDOR13", - "AF_VENDOR14", - "AF_VENDOR15", - "AF_VENDOR16", - "AF_VENDOR17", - "AF_VENDOR18", - "AF_VENDOR19", - "AF_VENDOR20", - "AF_VENDOR21", - "AF_VENDOR22", - "AF_VENDOR23", - "AF_VENDOR24", - "AF_VENDOR25", - "AF_VENDOR26", - "AF_VENDOR27", - "AF_VENDOR28", - "AF_VENDOR29", - "AF_VENDOR30", - "AF_VENDOR31", - "AF_VENDOR32", - "AF_VENDOR33", - "AF_VENDOR34", - "AF_VENDOR35", - "AF_VENDOR36", - "AF_VENDOR37", - "AF_VENDOR38", - "AF_VENDOR39", - "AF_VENDOR40", - "AF_VENDOR41", - "AF_VENDOR42", - "AF_VENDOR43", - "AF_VENDOR44", - "AF_VENDOR45", - "AF_VENDOR46", - "AF_VENDOR47", - "AF_WANPIPE", - "AF_X25", - "AI_CANONNAME", - "AI_NUMERICHOST", - "AI_PASSIVE", - "APPLICATION_ERROR", - "ARPHRD_ADAPT", - "ARPHRD_APPLETLK", - "ARPHRD_ARCNET", - "ARPHRD_ASH", - "ARPHRD_ATM", - "ARPHRD_AX25", - "ARPHRD_BIF", - "ARPHRD_CHAOS", - "ARPHRD_CISCO", - "ARPHRD_CSLIP", - "ARPHRD_CSLIP6", - "ARPHRD_DDCMP", - "ARPHRD_DLCI", - "ARPHRD_ECONET", - "ARPHRD_EETHER", - "ARPHRD_ETHER", - "ARPHRD_EUI64", - "ARPHRD_FCAL", - "ARPHRD_FCFABRIC", - "ARPHRD_FCPL", - "ARPHRD_FCPP", - "ARPHRD_FDDI", - "ARPHRD_FRAD", - "ARPHRD_FRELAY", - "ARPHRD_HDLC", - "ARPHRD_HIPPI", - "ARPHRD_HWX25", - "ARPHRD_IEEE1394", - "ARPHRD_IEEE802", - "ARPHRD_IEEE80211", - "ARPHRD_IEEE80211_PRISM", - "ARPHRD_IEEE80211_RADIOTAP", - "ARPHRD_IEEE802154", - "ARPHRD_IEEE802154_PHY", - "ARPHRD_IEEE802_TR", - "ARPHRD_INFINIBAND", - "ARPHRD_IPDDP", - "ARPHRD_IPGRE", - "ARPHRD_IRDA", - "ARPHRD_LAPB", - "ARPHRD_LOCALTLK", - "ARPHRD_LOOPBACK", - "ARPHRD_METRICOM", - "ARPHRD_NETROM", - "ARPHRD_NONE", - "ARPHRD_PIMREG", - "ARPHRD_PPP", - "ARPHRD_PRONET", - "ARPHRD_RAWHDLC", - "ARPHRD_ROSE", - "ARPHRD_RSRVD", - "ARPHRD_SIT", - "ARPHRD_SKIP", - "ARPHRD_SLIP", - "ARPHRD_SLIP6", - "ARPHRD_STRIP", - "ARPHRD_TUNNEL", - "ARPHRD_TUNNEL6", - "ARPHRD_VOID", - "ARPHRD_X25", - "AUTHTYPE_CLIENT", - "AUTHTYPE_SERVER", - "Accept", - "Accept4", - "AcceptEx", - "Access", - "Acct", - "AddrinfoW", - "Adjtime", - "Adjtimex", - "AllThreadsSyscall", - "AllThreadsSyscall6", - "AttachLsf", - "B0", - "B1000000", - "B110", - "B115200", - "B1152000", - "B1200", - "B134", - "B14400", - "B150", - "B1500000", - "B1800", - "B19200", - "B200", - "B2000000", - "B230400", - "B2400", - "B2500000", - "B28800", - "B300", - "B3000000", - "B3500000", - "B38400", - "B4000000", - "B460800", - "B4800", - "B50", - "B500000", - "B57600", - "B576000", - "B600", - "B7200", - "B75", - "B76800", - "B921600", - "B9600", - "BASE_PROTOCOL", - "BIOCFEEDBACK", - "BIOCFLUSH", - "BIOCGBLEN", - "BIOCGDIRECTION", - "BIOCGDIRFILT", - "BIOCGDLT", - "BIOCGDLTLIST", - "BIOCGETBUFMODE", - "BIOCGETIF", - "BIOCGETZMAX", - "BIOCGFEEDBACK", - "BIOCGFILDROP", - "BIOCGHDRCMPLT", - "BIOCGRSIG", - "BIOCGRTIMEOUT", - "BIOCGSEESENT", - "BIOCGSTATS", - "BIOCGSTATSOLD", - "BIOCGTSTAMP", - "BIOCIMMEDIATE", - "BIOCLOCK", - "BIOCPROMISC", - "BIOCROTZBUF", - "BIOCSBLEN", - "BIOCSDIRECTION", - "BIOCSDIRFILT", - "BIOCSDLT", - "BIOCSETBUFMODE", - "BIOCSETF", - "BIOCSETFNR", - "BIOCSETIF", - "BIOCSETWF", - "BIOCSETZBUF", - "BIOCSFEEDBACK", - "BIOCSFILDROP", - "BIOCSHDRCMPLT", - "BIOCSRSIG", - "BIOCSRTIMEOUT", - "BIOCSSEESENT", - "BIOCSTCPF", - "BIOCSTSTAMP", - "BIOCSUDPF", - "BIOCVERSION", - "BPF_A", - "BPF_ABS", - "BPF_ADD", - "BPF_ALIGNMENT", - "BPF_ALIGNMENT32", - "BPF_ALU", - "BPF_AND", - "BPF_B", - "BPF_BUFMODE_BUFFER", - "BPF_BUFMODE_ZBUF", - "BPF_DFLTBUFSIZE", - "BPF_DIRECTION_IN", - "BPF_DIRECTION_OUT", - "BPF_DIV", - "BPF_H", - "BPF_IMM", - "BPF_IND", - "BPF_JA", - "BPF_JEQ", - "BPF_JGE", - "BPF_JGT", - "BPF_JMP", - "BPF_JSET", - "BPF_K", - "BPF_LD", - "BPF_LDX", - "BPF_LEN", - "BPF_LSH", - "BPF_MAJOR_VERSION", - "BPF_MAXBUFSIZE", - "BPF_MAXINSNS", - "BPF_MEM", - "BPF_MEMWORDS", - "BPF_MINBUFSIZE", - "BPF_MINOR_VERSION", - "BPF_MISC", - "BPF_MSH", - "BPF_MUL", - "BPF_NEG", - "BPF_OR", - "BPF_RELEASE", - "BPF_RET", - "BPF_RSH", - "BPF_ST", - "BPF_STX", - "BPF_SUB", - "BPF_TAX", - "BPF_TXA", - "BPF_T_BINTIME", - "BPF_T_BINTIME_FAST", - "BPF_T_BINTIME_MONOTONIC", - "BPF_T_BINTIME_MONOTONIC_FAST", - "BPF_T_FAST", - "BPF_T_FLAG_MASK", - "BPF_T_FORMAT_MASK", - "BPF_T_MICROTIME", - "BPF_T_MICROTIME_FAST", - "BPF_T_MICROTIME_MONOTONIC", - "BPF_T_MICROTIME_MONOTONIC_FAST", - "BPF_T_MONOTONIC", - "BPF_T_MONOTONIC_FAST", - "BPF_T_NANOTIME", - "BPF_T_NANOTIME_FAST", - "BPF_T_NANOTIME_MONOTONIC", - "BPF_T_NANOTIME_MONOTONIC_FAST", - "BPF_T_NONE", - "BPF_T_NORMAL", - "BPF_W", - "BPF_X", - "BRKINT", - "Bind", - "BindToDevice", - "BpfBuflen", - "BpfDatalink", - "BpfHdr", - "BpfHeadercmpl", - "BpfInsn", - "BpfInterface", - "BpfJump", - "BpfProgram", - "BpfStat", - "BpfStats", - "BpfStmt", - "BpfTimeout", - "BpfTimeval", - "BpfVersion", - "BpfZbuf", - "BpfZbufHeader", - "ByHandleFileInformation", - "BytePtrFromString", - "ByteSliceFromString", - "CCR0_FLUSH", - "CERT_CHAIN_POLICY_AUTHENTICODE", - "CERT_CHAIN_POLICY_AUTHENTICODE_TS", - "CERT_CHAIN_POLICY_BASE", - "CERT_CHAIN_POLICY_BASIC_CONSTRAINTS", - "CERT_CHAIN_POLICY_EV", - "CERT_CHAIN_POLICY_MICROSOFT_ROOT", - "CERT_CHAIN_POLICY_NT_AUTH", - "CERT_CHAIN_POLICY_SSL", - "CERT_E_CN_NO_MATCH", - "CERT_E_EXPIRED", - "CERT_E_PURPOSE", - "CERT_E_ROLE", - "CERT_E_UNTRUSTEDROOT", - "CERT_STORE_ADD_ALWAYS", - "CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG", - "CERT_STORE_PROV_MEMORY", - "CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT", - "CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT", - "CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT", - "CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT", - "CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT", - "CERT_TRUST_INVALID_BASIC_CONSTRAINTS", - "CERT_TRUST_INVALID_EXTENSION", - "CERT_TRUST_INVALID_NAME_CONSTRAINTS", - "CERT_TRUST_INVALID_POLICY_CONSTRAINTS", - "CERT_TRUST_IS_CYCLIC", - "CERT_TRUST_IS_EXPLICIT_DISTRUST", - "CERT_TRUST_IS_NOT_SIGNATURE_VALID", - "CERT_TRUST_IS_NOT_TIME_VALID", - "CERT_TRUST_IS_NOT_VALID_FOR_USAGE", - "CERT_TRUST_IS_OFFLINE_REVOCATION", - "CERT_TRUST_IS_REVOKED", - "CERT_TRUST_IS_UNTRUSTED_ROOT", - "CERT_TRUST_NO_ERROR", - "CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY", - "CERT_TRUST_REVOCATION_STATUS_UNKNOWN", - "CFLUSH", - "CLOCAL", - "CLONE_CHILD_CLEARTID", - "CLONE_CHILD_SETTID", - "CLONE_CLEAR_SIGHAND", - "CLONE_CSIGNAL", - "CLONE_DETACHED", - "CLONE_FILES", - "CLONE_FS", - "CLONE_INTO_CGROUP", - "CLONE_IO", - "CLONE_NEWCGROUP", - "CLONE_NEWIPC", - "CLONE_NEWNET", - "CLONE_NEWNS", - "CLONE_NEWPID", - "CLONE_NEWTIME", - "CLONE_NEWUSER", - "CLONE_NEWUTS", - "CLONE_PARENT", - "CLONE_PARENT_SETTID", - "CLONE_PID", - "CLONE_PIDFD", - "CLONE_PTRACE", - "CLONE_SETTLS", - "CLONE_SIGHAND", - "CLONE_SYSVSEM", - "CLONE_THREAD", - "CLONE_UNTRACED", - "CLONE_VFORK", - "CLONE_VM", - "CPUID_CFLUSH", - "CREAD", - "CREATE_ALWAYS", - "CREATE_NEW", - "CREATE_NEW_PROCESS_GROUP", - "CREATE_UNICODE_ENVIRONMENT", - "CRYPT_DEFAULT_CONTAINER_OPTIONAL", - "CRYPT_DELETEKEYSET", - "CRYPT_MACHINE_KEYSET", - "CRYPT_NEWKEYSET", - "CRYPT_SILENT", - "CRYPT_VERIFYCONTEXT", - "CS5", - "CS6", - "CS7", - "CS8", - "CSIZE", - "CSTART", - "CSTATUS", - "CSTOP", - "CSTOPB", - "CSUSP", - "CTL_MAXNAME", - "CTL_NET", - "CTL_QUERY", - "CTRL_BREAK_EVENT", - "CTRL_CLOSE_EVENT", - "CTRL_C_EVENT", - "CTRL_LOGOFF_EVENT", - "CTRL_SHUTDOWN_EVENT", - "CancelIo", - "CancelIoEx", - "CertAddCertificateContextToStore", - "CertChainContext", - "CertChainElement", - "CertChainPara", - "CertChainPolicyPara", - "CertChainPolicyStatus", - "CertCloseStore", - "CertContext", - "CertCreateCertificateContext", - "CertEnhKeyUsage", - "CertEnumCertificatesInStore", - "CertFreeCertificateChain", - "CertFreeCertificateContext", - "CertGetCertificateChain", - "CertInfo", - "CertOpenStore", - "CertOpenSystemStore", - "CertRevocationCrlInfo", - "CertRevocationInfo", - "CertSimpleChain", - "CertTrustListInfo", - "CertTrustStatus", - "CertUsageMatch", - "CertVerifyCertificateChainPolicy", - "Chdir", - "CheckBpfVersion", - "Chflags", - "Chmod", - "Chown", - "Chroot", - "Clearenv", - "Close", - "CloseHandle", - "CloseOnExec", - "Closesocket", - "CmsgLen", - "CmsgSpace", - "Cmsghdr", - "CommandLineToArgv", - "ComputerName", - "Conn", - "Connect", - "ConnectEx", - "ConvertSidToStringSid", - "ConvertStringSidToSid", - "CopySid", - "Creat", - "CreateDirectory", - "CreateFile", - "CreateFileMapping", - "CreateHardLink", - "CreateIoCompletionPort", - "CreatePipe", - "CreateProcess", - "CreateProcessAsUser", - "CreateSymbolicLink", - "CreateToolhelp32Snapshot", - "Credential", - "CryptAcquireContext", - "CryptGenRandom", - "CryptReleaseContext", - "DIOCBSFLUSH", - "DIOCOSFPFLUSH", - "DLL", - "DLLError", - "DLT_A429", - "DLT_A653_ICM", - "DLT_AIRONET_HEADER", - "DLT_AOS", - "DLT_APPLE_IP_OVER_IEEE1394", - "DLT_ARCNET", - "DLT_ARCNET_LINUX", - "DLT_ATM_CLIP", - "DLT_ATM_RFC1483", - "DLT_AURORA", - "DLT_AX25", - "DLT_AX25_KISS", - "DLT_BACNET_MS_TP", - "DLT_BLUETOOTH_HCI_H4", - "DLT_BLUETOOTH_HCI_H4_WITH_PHDR", - "DLT_CAN20B", - "DLT_CAN_SOCKETCAN", - "DLT_CHAOS", - "DLT_CHDLC", - "DLT_CISCO_IOS", - "DLT_C_HDLC", - "DLT_C_HDLC_WITH_DIR", - "DLT_DBUS", - "DLT_DECT", - "DLT_DOCSIS", - "DLT_DVB_CI", - "DLT_ECONET", - "DLT_EN10MB", - "DLT_EN3MB", - "DLT_ENC", - "DLT_ERF", - "DLT_ERF_ETH", - "DLT_ERF_POS", - "DLT_FC_2", - "DLT_FC_2_WITH_FRAME_DELIMS", - "DLT_FDDI", - "DLT_FLEXRAY", - "DLT_FRELAY", - "DLT_FRELAY_WITH_DIR", - "DLT_GCOM_SERIAL", - "DLT_GCOM_T1E1", - "DLT_GPF_F", - "DLT_GPF_T", - "DLT_GPRS_LLC", - "DLT_GSMTAP_ABIS", - "DLT_GSMTAP_UM", - "DLT_HDLC", - "DLT_HHDLC", - "DLT_HIPPI", - "DLT_IBM_SN", - "DLT_IBM_SP", - "DLT_IEEE802", - "DLT_IEEE802_11", - "DLT_IEEE802_11_RADIO", - "DLT_IEEE802_11_RADIO_AVS", - "DLT_IEEE802_15_4", - "DLT_IEEE802_15_4_LINUX", - "DLT_IEEE802_15_4_NOFCS", - "DLT_IEEE802_15_4_NONASK_PHY", - "DLT_IEEE802_16_MAC_CPS", - "DLT_IEEE802_16_MAC_CPS_RADIO", - "DLT_IPFILTER", - "DLT_IPMB", - "DLT_IPMB_LINUX", - "DLT_IPNET", - "DLT_IPOIB", - "DLT_IPV4", - "DLT_IPV6", - "DLT_IP_OVER_FC", - "DLT_JUNIPER_ATM1", - "DLT_JUNIPER_ATM2", - "DLT_JUNIPER_ATM_CEMIC", - "DLT_JUNIPER_CHDLC", - "DLT_JUNIPER_ES", - "DLT_JUNIPER_ETHER", - "DLT_JUNIPER_FIBRECHANNEL", - "DLT_JUNIPER_FRELAY", - "DLT_JUNIPER_GGSN", - "DLT_JUNIPER_ISM", - "DLT_JUNIPER_MFR", - "DLT_JUNIPER_MLFR", - "DLT_JUNIPER_MLPPP", - "DLT_JUNIPER_MONITOR", - "DLT_JUNIPER_PIC_PEER", - "DLT_JUNIPER_PPP", - "DLT_JUNIPER_PPPOE", - "DLT_JUNIPER_PPPOE_ATM", - "DLT_JUNIPER_SERVICES", - "DLT_JUNIPER_SRX_E2E", - "DLT_JUNIPER_ST", - "DLT_JUNIPER_VP", - "DLT_JUNIPER_VS", - "DLT_LAPB_WITH_DIR", - "DLT_LAPD", - "DLT_LIN", - "DLT_LINUX_EVDEV", - "DLT_LINUX_IRDA", - "DLT_LINUX_LAPD", - "DLT_LINUX_PPP_WITHDIRECTION", - "DLT_LINUX_SLL", - "DLT_LOOP", - "DLT_LTALK", - "DLT_MATCHING_MAX", - "DLT_MATCHING_MIN", - "DLT_MFR", - "DLT_MOST", - "DLT_MPEG_2_TS", - "DLT_MPLS", - "DLT_MTP2", - "DLT_MTP2_WITH_PHDR", - "DLT_MTP3", - "DLT_MUX27010", - "DLT_NETANALYZER", - "DLT_NETANALYZER_TRANSPARENT", - "DLT_NFC_LLCP", - "DLT_NFLOG", - "DLT_NG40", - "DLT_NULL", - "DLT_PCI_EXP", - "DLT_PFLOG", - "DLT_PFSYNC", - "DLT_PPI", - "DLT_PPP", - "DLT_PPP_BSDOS", - "DLT_PPP_ETHER", - "DLT_PPP_PPPD", - "DLT_PPP_SERIAL", - "DLT_PPP_WITH_DIR", - "DLT_PPP_WITH_DIRECTION", - "DLT_PRISM_HEADER", - "DLT_PRONET", - "DLT_RAIF1", - "DLT_RAW", - "DLT_RAWAF_MASK", - "DLT_RIO", - "DLT_SCCP", - "DLT_SITA", - "DLT_SLIP", - "DLT_SLIP_BSDOS", - "DLT_STANAG_5066_D_PDU", - "DLT_SUNATM", - "DLT_SYMANTEC_FIREWALL", - "DLT_TZSP", - "DLT_USB", - "DLT_USB_LINUX", - "DLT_USB_LINUX_MMAPPED", - "DLT_USER0", - "DLT_USER1", - "DLT_USER10", - "DLT_USER11", - "DLT_USER12", - "DLT_USER13", - "DLT_USER14", - "DLT_USER15", - "DLT_USER2", - "DLT_USER3", - "DLT_USER4", - "DLT_USER5", - "DLT_USER6", - "DLT_USER7", - "DLT_USER8", - "DLT_USER9", - "DLT_WIHART", - "DLT_X2E_SERIAL", - "DLT_X2E_XORAYA", - "DNSMXData", - "DNSPTRData", - "DNSRecord", - "DNSSRVData", - "DNSTXTData", - "DNS_INFO_NO_RECORDS", - "DNS_TYPE_A", - "DNS_TYPE_A6", - "DNS_TYPE_AAAA", - "DNS_TYPE_ADDRS", - "DNS_TYPE_AFSDB", - "DNS_TYPE_ALL", - "DNS_TYPE_ANY", - "DNS_TYPE_ATMA", - "DNS_TYPE_AXFR", - "DNS_TYPE_CERT", - "DNS_TYPE_CNAME", - "DNS_TYPE_DHCID", - "DNS_TYPE_DNAME", - "DNS_TYPE_DNSKEY", - "DNS_TYPE_DS", - "DNS_TYPE_EID", - "DNS_TYPE_GID", - "DNS_TYPE_GPOS", - "DNS_TYPE_HINFO", - "DNS_TYPE_ISDN", - "DNS_TYPE_IXFR", - "DNS_TYPE_KEY", - "DNS_TYPE_KX", - "DNS_TYPE_LOC", - "DNS_TYPE_MAILA", - "DNS_TYPE_MAILB", - "DNS_TYPE_MB", - "DNS_TYPE_MD", - "DNS_TYPE_MF", - "DNS_TYPE_MG", - "DNS_TYPE_MINFO", - "DNS_TYPE_MR", - "DNS_TYPE_MX", - "DNS_TYPE_NAPTR", - "DNS_TYPE_NBSTAT", - "DNS_TYPE_NIMLOC", - "DNS_TYPE_NS", - "DNS_TYPE_NSAP", - "DNS_TYPE_NSAPPTR", - "DNS_TYPE_NSEC", - "DNS_TYPE_NULL", - "DNS_TYPE_NXT", - "DNS_TYPE_OPT", - "DNS_TYPE_PTR", - "DNS_TYPE_PX", - "DNS_TYPE_RP", - "DNS_TYPE_RRSIG", - "DNS_TYPE_RT", - "DNS_TYPE_SIG", - "DNS_TYPE_SINK", - "DNS_TYPE_SOA", - "DNS_TYPE_SRV", - "DNS_TYPE_TEXT", - "DNS_TYPE_TKEY", - "DNS_TYPE_TSIG", - "DNS_TYPE_UID", - "DNS_TYPE_UINFO", - "DNS_TYPE_UNSPEC", - "DNS_TYPE_WINS", - "DNS_TYPE_WINSR", - "DNS_TYPE_WKS", - "DNS_TYPE_X25", - "DT_BLK", - "DT_CHR", - "DT_DIR", - "DT_FIFO", - "DT_LNK", - "DT_REG", - "DT_SOCK", - "DT_UNKNOWN", - "DT_WHT", - "DUPLICATE_CLOSE_SOURCE", - "DUPLICATE_SAME_ACCESS", - "DeleteFile", - "DetachLsf", - "DeviceIoControl", - "Dirent", - "DnsNameCompare", - "DnsQuery", - "DnsRecordListFree", - "DnsSectionAdditional", - "DnsSectionAnswer", - "DnsSectionAuthority", - "DnsSectionQuestion", - "Dup", - "Dup2", - "Dup3", - "DuplicateHandle", - "E2BIG", - "EACCES", - "EADDRINUSE", - "EADDRNOTAVAIL", - "EADV", - "EAFNOSUPPORT", - "EAGAIN", - "EALREADY", - "EAUTH", - "EBADARCH", - "EBADE", - "EBADEXEC", - "EBADF", - "EBADFD", - "EBADMACHO", - "EBADMSG", - "EBADR", - "EBADRPC", - "EBADRQC", - "EBADSLT", - "EBFONT", - "EBUSY", - "ECANCELED", - "ECAPMODE", - "ECHILD", - "ECHO", - "ECHOCTL", - "ECHOE", - "ECHOK", - "ECHOKE", - "ECHONL", - "ECHOPRT", - "ECHRNG", - "ECOMM", - "ECONNABORTED", - "ECONNREFUSED", - "ECONNRESET", - "EDEADLK", - "EDEADLOCK", - "EDESTADDRREQ", - "EDEVERR", - "EDOM", - "EDOOFUS", - "EDOTDOT", - "EDQUOT", - "EEXIST", - "EFAULT", - "EFBIG", - "EFER_LMA", - "EFER_LME", - "EFER_NXE", - "EFER_SCE", - "EFTYPE", - "EHOSTDOWN", - "EHOSTUNREACH", - "EHWPOISON", - "EIDRM", - "EILSEQ", - "EINPROGRESS", - "EINTR", - "EINVAL", - "EIO", - "EIPSEC", - "EISCONN", - "EISDIR", - "EISNAM", - "EKEYEXPIRED", - "EKEYREJECTED", - "EKEYREVOKED", - "EL2HLT", - "EL2NSYNC", - "EL3HLT", - "EL3RST", - "ELAST", - "ELF_NGREG", - "ELF_PRARGSZ", - "ELIBACC", - "ELIBBAD", - "ELIBEXEC", - "ELIBMAX", - "ELIBSCN", - "ELNRNG", - "ELOOP", - "EMEDIUMTYPE", - "EMFILE", - "EMLINK", - "EMSGSIZE", - "EMT_TAGOVF", - "EMULTIHOP", - "EMUL_ENABLED", - "EMUL_LINUX", - "EMUL_LINUX32", - "EMUL_MAXID", - "EMUL_NATIVE", - "ENAMETOOLONG", - "ENAVAIL", - "ENDRUNDISC", - "ENEEDAUTH", - "ENETDOWN", - "ENETRESET", - "ENETUNREACH", - "ENFILE", - "ENOANO", - "ENOATTR", - "ENOBUFS", - "ENOCSI", - "ENODATA", - "ENODEV", - "ENOENT", - "ENOEXEC", - "ENOKEY", - "ENOLCK", - "ENOLINK", - "ENOMEDIUM", - "ENOMEM", - "ENOMSG", - "ENONET", - "ENOPKG", - "ENOPOLICY", - "ENOPROTOOPT", - "ENOSPC", - "ENOSR", - "ENOSTR", - "ENOSYS", - "ENOTBLK", - "ENOTCAPABLE", - "ENOTCONN", - "ENOTDIR", - "ENOTEMPTY", - "ENOTNAM", - "ENOTRECOVERABLE", - "ENOTSOCK", - "ENOTSUP", - "ENOTTY", - "ENOTUNIQ", - "ENXIO", - "EN_SW_CTL_INF", - "EN_SW_CTL_PREC", - "EN_SW_CTL_ROUND", - "EN_SW_DATACHAIN", - "EN_SW_DENORM", - "EN_SW_INVOP", - "EN_SW_OVERFLOW", - "EN_SW_PRECLOSS", - "EN_SW_UNDERFLOW", - "EN_SW_ZERODIV", - "EOPNOTSUPP", - "EOVERFLOW", - "EOWNERDEAD", - "EPERM", - "EPFNOSUPPORT", - "EPIPE", - "EPOLLERR", - "EPOLLET", - "EPOLLHUP", - "EPOLLIN", - "EPOLLMSG", - "EPOLLONESHOT", - "EPOLLOUT", - "EPOLLPRI", - "EPOLLRDBAND", - "EPOLLRDHUP", - "EPOLLRDNORM", - "EPOLLWRBAND", - "EPOLLWRNORM", - "EPOLL_CLOEXEC", - "EPOLL_CTL_ADD", - "EPOLL_CTL_DEL", - "EPOLL_CTL_MOD", - "EPOLL_NONBLOCK", - "EPROCLIM", - "EPROCUNAVAIL", - "EPROGMISMATCH", - "EPROGUNAVAIL", - "EPROTO", - "EPROTONOSUPPORT", - "EPROTOTYPE", - "EPWROFF", - "EQFULL", - "ERANGE", - "EREMCHG", - "EREMOTE", - "EREMOTEIO", - "ERESTART", - "ERFKILL", - "EROFS", - "ERPCMISMATCH", - "ERROR_ACCESS_DENIED", - "ERROR_ALREADY_EXISTS", - "ERROR_BROKEN_PIPE", - "ERROR_BUFFER_OVERFLOW", - "ERROR_DIR_NOT_EMPTY", - "ERROR_ENVVAR_NOT_FOUND", - "ERROR_FILE_EXISTS", - "ERROR_FILE_NOT_FOUND", - "ERROR_HANDLE_EOF", - "ERROR_INSUFFICIENT_BUFFER", - "ERROR_IO_PENDING", - "ERROR_MOD_NOT_FOUND", - "ERROR_MORE_DATA", - "ERROR_NETNAME_DELETED", - "ERROR_NOT_FOUND", - "ERROR_NO_MORE_FILES", - "ERROR_OPERATION_ABORTED", - "ERROR_PATH_NOT_FOUND", - "ERROR_PRIVILEGE_NOT_HELD", - "ERROR_PROC_NOT_FOUND", - "ESHLIBVERS", - "ESHUTDOWN", - "ESOCKTNOSUPPORT", - "ESPIPE", - "ESRCH", - "ESRMNT", - "ESTALE", - "ESTRPIPE", - "ETHERCAP_JUMBO_MTU", - "ETHERCAP_VLAN_HWTAGGING", - "ETHERCAP_VLAN_MTU", - "ETHERMIN", - "ETHERMTU", - "ETHERMTU_JUMBO", - "ETHERTYPE_8023", - "ETHERTYPE_AARP", - "ETHERTYPE_ACCTON", - "ETHERTYPE_AEONIC", - "ETHERTYPE_ALPHA", - "ETHERTYPE_AMBER", - "ETHERTYPE_AMOEBA", - "ETHERTYPE_AOE", - "ETHERTYPE_APOLLO", - "ETHERTYPE_APOLLODOMAIN", - "ETHERTYPE_APPLETALK", - "ETHERTYPE_APPLITEK", - "ETHERTYPE_ARGONAUT", - "ETHERTYPE_ARP", - "ETHERTYPE_AT", - "ETHERTYPE_ATALK", - "ETHERTYPE_ATOMIC", - "ETHERTYPE_ATT", - "ETHERTYPE_ATTSTANFORD", - "ETHERTYPE_AUTOPHON", - "ETHERTYPE_AXIS", - "ETHERTYPE_BCLOOP", - "ETHERTYPE_BOFL", - "ETHERTYPE_CABLETRON", - "ETHERTYPE_CHAOS", - "ETHERTYPE_COMDESIGN", - "ETHERTYPE_COMPUGRAPHIC", - "ETHERTYPE_COUNTERPOINT", - "ETHERTYPE_CRONUS", - "ETHERTYPE_CRONUSVLN", - "ETHERTYPE_DCA", - "ETHERTYPE_DDE", - "ETHERTYPE_DEBNI", - "ETHERTYPE_DECAM", - "ETHERTYPE_DECCUST", - "ETHERTYPE_DECDIAG", - "ETHERTYPE_DECDNS", - "ETHERTYPE_DECDTS", - "ETHERTYPE_DECEXPER", - "ETHERTYPE_DECLAST", - "ETHERTYPE_DECLTM", - "ETHERTYPE_DECMUMPS", - "ETHERTYPE_DECNETBIOS", - "ETHERTYPE_DELTACON", - "ETHERTYPE_DIDDLE", - "ETHERTYPE_DLOG1", - "ETHERTYPE_DLOG2", - "ETHERTYPE_DN", - "ETHERTYPE_DOGFIGHT", - "ETHERTYPE_DSMD", - "ETHERTYPE_ECMA", - "ETHERTYPE_ENCRYPT", - "ETHERTYPE_ES", - "ETHERTYPE_EXCELAN", - "ETHERTYPE_EXPERDATA", - "ETHERTYPE_FLIP", - "ETHERTYPE_FLOWCONTROL", - "ETHERTYPE_FRARP", - "ETHERTYPE_GENDYN", - "ETHERTYPE_HAYES", - "ETHERTYPE_HIPPI_FP", - "ETHERTYPE_HITACHI", - "ETHERTYPE_HP", - "ETHERTYPE_IEEEPUP", - "ETHERTYPE_IEEEPUPAT", - "ETHERTYPE_IMLBL", - "ETHERTYPE_IMLBLDIAG", - "ETHERTYPE_IP", - "ETHERTYPE_IPAS", - "ETHERTYPE_IPV6", - "ETHERTYPE_IPX", - "ETHERTYPE_IPXNEW", - "ETHERTYPE_KALPANA", - "ETHERTYPE_LANBRIDGE", - "ETHERTYPE_LANPROBE", - "ETHERTYPE_LAT", - "ETHERTYPE_LBACK", - "ETHERTYPE_LITTLE", - "ETHERTYPE_LLDP", - "ETHERTYPE_LOGICRAFT", - "ETHERTYPE_LOOPBACK", - "ETHERTYPE_MATRA", - "ETHERTYPE_MAX", - "ETHERTYPE_MERIT", - "ETHERTYPE_MICP", - "ETHERTYPE_MOPDL", - "ETHERTYPE_MOPRC", - "ETHERTYPE_MOTOROLA", - "ETHERTYPE_MPLS", - "ETHERTYPE_MPLS_MCAST", - "ETHERTYPE_MUMPS", - "ETHERTYPE_NBPCC", - "ETHERTYPE_NBPCLAIM", - "ETHERTYPE_NBPCLREQ", - "ETHERTYPE_NBPCLRSP", - "ETHERTYPE_NBPCREQ", - "ETHERTYPE_NBPCRSP", - "ETHERTYPE_NBPDG", - "ETHERTYPE_NBPDGB", - "ETHERTYPE_NBPDLTE", - "ETHERTYPE_NBPRAR", - "ETHERTYPE_NBPRAS", - "ETHERTYPE_NBPRST", - "ETHERTYPE_NBPSCD", - "ETHERTYPE_NBPVCD", - "ETHERTYPE_NBS", - "ETHERTYPE_NCD", - "ETHERTYPE_NESTAR", - "ETHERTYPE_NETBEUI", - "ETHERTYPE_NOVELL", - "ETHERTYPE_NS", - "ETHERTYPE_NSAT", - "ETHERTYPE_NSCOMPAT", - "ETHERTYPE_NTRAILER", - "ETHERTYPE_OS9", - "ETHERTYPE_OS9NET", - "ETHERTYPE_PACER", - "ETHERTYPE_PAE", - "ETHERTYPE_PCS", - "ETHERTYPE_PLANNING", - "ETHERTYPE_PPP", - "ETHERTYPE_PPPOE", - "ETHERTYPE_PPPOEDISC", - "ETHERTYPE_PRIMENTS", - "ETHERTYPE_PUP", - "ETHERTYPE_PUPAT", - "ETHERTYPE_QINQ", - "ETHERTYPE_RACAL", - "ETHERTYPE_RATIONAL", - "ETHERTYPE_RAWFR", - "ETHERTYPE_RCL", - "ETHERTYPE_RDP", - "ETHERTYPE_RETIX", - "ETHERTYPE_REVARP", - "ETHERTYPE_SCA", - "ETHERTYPE_SECTRA", - "ETHERTYPE_SECUREDATA", - "ETHERTYPE_SGITW", - "ETHERTYPE_SG_BOUNCE", - "ETHERTYPE_SG_DIAG", - "ETHERTYPE_SG_NETGAMES", - "ETHERTYPE_SG_RESV", - "ETHERTYPE_SIMNET", - "ETHERTYPE_SLOW", - "ETHERTYPE_SLOWPROTOCOLS", - "ETHERTYPE_SNA", - "ETHERTYPE_SNMP", - "ETHERTYPE_SONIX", - "ETHERTYPE_SPIDER", - "ETHERTYPE_SPRITE", - "ETHERTYPE_STP", - "ETHERTYPE_TALARIS", - "ETHERTYPE_TALARISMC", - "ETHERTYPE_TCPCOMP", - "ETHERTYPE_TCPSM", - "ETHERTYPE_TEC", - "ETHERTYPE_TIGAN", - "ETHERTYPE_TRAIL", - "ETHERTYPE_TRANSETHER", - "ETHERTYPE_TYMSHARE", - "ETHERTYPE_UBBST", - "ETHERTYPE_UBDEBUG", - "ETHERTYPE_UBDIAGLOOP", - "ETHERTYPE_UBDL", - "ETHERTYPE_UBNIU", - "ETHERTYPE_UBNMC", - "ETHERTYPE_VALID", - "ETHERTYPE_VARIAN", - "ETHERTYPE_VAXELN", - "ETHERTYPE_VEECO", - "ETHERTYPE_VEXP", - "ETHERTYPE_VGLAB", - "ETHERTYPE_VINES", - "ETHERTYPE_VINESECHO", - "ETHERTYPE_VINESLOOP", - "ETHERTYPE_VITAL", - "ETHERTYPE_VLAN", - "ETHERTYPE_VLTLMAN", - "ETHERTYPE_VPROD", - "ETHERTYPE_VURESERVED", - "ETHERTYPE_WATERLOO", - "ETHERTYPE_WELLFLEET", - "ETHERTYPE_X25", - "ETHERTYPE_X75", - "ETHERTYPE_XNSSM", - "ETHERTYPE_XTP", - "ETHER_ADDR_LEN", - "ETHER_ALIGN", - "ETHER_CRC_LEN", - "ETHER_CRC_POLY_BE", - "ETHER_CRC_POLY_LE", - "ETHER_HDR_LEN", - "ETHER_MAX_DIX_LEN", - "ETHER_MAX_LEN", - "ETHER_MAX_LEN_JUMBO", - "ETHER_MIN_LEN", - "ETHER_PPPOE_ENCAP_LEN", - "ETHER_TYPE_LEN", - "ETHER_VLAN_ENCAP_LEN", - "ETH_P_1588", - "ETH_P_8021Q", - "ETH_P_802_2", - "ETH_P_802_3", - "ETH_P_AARP", - "ETH_P_ALL", - "ETH_P_AOE", - "ETH_P_ARCNET", - "ETH_P_ARP", - "ETH_P_ATALK", - "ETH_P_ATMFATE", - "ETH_P_ATMMPOA", - "ETH_P_AX25", - "ETH_P_BPQ", - "ETH_P_CAIF", - "ETH_P_CAN", - "ETH_P_CONTROL", - "ETH_P_CUST", - "ETH_P_DDCMP", - "ETH_P_DEC", - "ETH_P_DIAG", - "ETH_P_DNA_DL", - "ETH_P_DNA_RC", - "ETH_P_DNA_RT", - "ETH_P_DSA", - "ETH_P_ECONET", - "ETH_P_EDSA", - "ETH_P_FCOE", - "ETH_P_FIP", - "ETH_P_HDLC", - "ETH_P_IEEE802154", - "ETH_P_IEEEPUP", - "ETH_P_IEEEPUPAT", - "ETH_P_IP", - "ETH_P_IPV6", - "ETH_P_IPX", - "ETH_P_IRDA", - "ETH_P_LAT", - "ETH_P_LINK_CTL", - "ETH_P_LOCALTALK", - "ETH_P_LOOP", - "ETH_P_MOBITEX", - "ETH_P_MPLS_MC", - "ETH_P_MPLS_UC", - "ETH_P_PAE", - "ETH_P_PAUSE", - "ETH_P_PHONET", - "ETH_P_PPPTALK", - "ETH_P_PPP_DISC", - "ETH_P_PPP_MP", - "ETH_P_PPP_SES", - "ETH_P_PUP", - "ETH_P_PUPAT", - "ETH_P_RARP", - "ETH_P_SCA", - "ETH_P_SLOW", - "ETH_P_SNAP", - "ETH_P_TEB", - "ETH_P_TIPC", - "ETH_P_TRAILER", - "ETH_P_TR_802_2", - "ETH_P_WAN_PPP", - "ETH_P_WCCP", - "ETH_P_X25", - "ETIME", - "ETIMEDOUT", - "ETOOMANYREFS", - "ETXTBSY", - "EUCLEAN", - "EUNATCH", - "EUSERS", - "EVFILT_AIO", - "EVFILT_FS", - "EVFILT_LIO", - "EVFILT_MACHPORT", - "EVFILT_PROC", - "EVFILT_READ", - "EVFILT_SIGNAL", - "EVFILT_SYSCOUNT", - "EVFILT_THREADMARKER", - "EVFILT_TIMER", - "EVFILT_USER", - "EVFILT_VM", - "EVFILT_VNODE", - "EVFILT_WRITE", - "EV_ADD", - "EV_CLEAR", - "EV_DELETE", - "EV_DISABLE", - "EV_DISPATCH", - "EV_DROP", - "EV_ENABLE", - "EV_EOF", - "EV_ERROR", - "EV_FLAG0", - "EV_FLAG1", - "EV_ONESHOT", - "EV_OOBAND", - "EV_POLL", - "EV_RECEIPT", - "EV_SYSFLAGS", - "EWINDOWS", - "EWOULDBLOCK", - "EXDEV", - "EXFULL", - "EXTA", - "EXTB", - "EXTPROC", - "Environ", - "EpollCreate", - "EpollCreate1", - "EpollCtl", - "EpollEvent", - "EpollWait", - "Errno", - "EscapeArg", - "Exchangedata", - "Exec", - "Exit", - "ExitProcess", - "FD_CLOEXEC", - "FD_SETSIZE", - "FILE_ACTION_ADDED", - "FILE_ACTION_MODIFIED", - "FILE_ACTION_REMOVED", - "FILE_ACTION_RENAMED_NEW_NAME", - "FILE_ACTION_RENAMED_OLD_NAME", - "FILE_APPEND_DATA", - "FILE_ATTRIBUTE_ARCHIVE", - "FILE_ATTRIBUTE_DIRECTORY", - "FILE_ATTRIBUTE_HIDDEN", - "FILE_ATTRIBUTE_NORMAL", - "FILE_ATTRIBUTE_READONLY", - "FILE_ATTRIBUTE_REPARSE_POINT", - "FILE_ATTRIBUTE_SYSTEM", - "FILE_BEGIN", - "FILE_CURRENT", - "FILE_END", - "FILE_FLAG_BACKUP_SEMANTICS", - "FILE_FLAG_OPEN_REPARSE_POINT", - "FILE_FLAG_OVERLAPPED", - "FILE_LIST_DIRECTORY", - "FILE_MAP_COPY", - "FILE_MAP_EXECUTE", - "FILE_MAP_READ", - "FILE_MAP_WRITE", - "FILE_NOTIFY_CHANGE_ATTRIBUTES", - "FILE_NOTIFY_CHANGE_CREATION", - "FILE_NOTIFY_CHANGE_DIR_NAME", - "FILE_NOTIFY_CHANGE_FILE_NAME", - "FILE_NOTIFY_CHANGE_LAST_ACCESS", - "FILE_NOTIFY_CHANGE_LAST_WRITE", - "FILE_NOTIFY_CHANGE_SIZE", - "FILE_SHARE_DELETE", - "FILE_SHARE_READ", - "FILE_SHARE_WRITE", - "FILE_SKIP_COMPLETION_PORT_ON_SUCCESS", - "FILE_SKIP_SET_EVENT_ON_HANDLE", - "FILE_TYPE_CHAR", - "FILE_TYPE_DISK", - "FILE_TYPE_PIPE", - "FILE_TYPE_REMOTE", - "FILE_TYPE_UNKNOWN", - "FILE_WRITE_ATTRIBUTES", - "FLUSHO", - "FORMAT_MESSAGE_ALLOCATE_BUFFER", - "FORMAT_MESSAGE_ARGUMENT_ARRAY", - "FORMAT_MESSAGE_FROM_HMODULE", - "FORMAT_MESSAGE_FROM_STRING", - "FORMAT_MESSAGE_FROM_SYSTEM", - "FORMAT_MESSAGE_IGNORE_INSERTS", - "FORMAT_MESSAGE_MAX_WIDTH_MASK", - "FSCTL_GET_REPARSE_POINT", - "F_ADDFILESIGS", - "F_ADDSIGS", - "F_ALLOCATEALL", - "F_ALLOCATECONTIG", - "F_CANCEL", - "F_CHKCLEAN", - "F_CLOSEM", - "F_DUP2FD", - "F_DUP2FD_CLOEXEC", - "F_DUPFD", - "F_DUPFD_CLOEXEC", - "F_EXLCK", - "F_FINDSIGS", - "F_FLUSH_DATA", - "F_FREEZE_FS", - "F_FSCTL", - "F_FSDIRMASK", - "F_FSIN", - "F_FSINOUT", - "F_FSOUT", - "F_FSPRIV", - "F_FSVOID", - "F_FULLFSYNC", - "F_GETCODEDIR", - "F_GETFD", - "F_GETFL", - "F_GETLEASE", - "F_GETLK", - "F_GETLK64", - "F_GETLKPID", - "F_GETNOSIGPIPE", - "F_GETOWN", - "F_GETOWN_EX", - "F_GETPATH", - "F_GETPATH_MTMINFO", - "F_GETPIPE_SZ", - "F_GETPROTECTIONCLASS", - "F_GETPROTECTIONLEVEL", - "F_GETSIG", - "F_GLOBAL_NOCACHE", - "F_LOCK", - "F_LOG2PHYS", - "F_LOG2PHYS_EXT", - "F_MARKDEPENDENCY", - "F_MAXFD", - "F_NOCACHE", - "F_NODIRECT", - "F_NOTIFY", - "F_OGETLK", - "F_OK", - "F_OSETLK", - "F_OSETLKW", - "F_PARAM_MASK", - "F_PARAM_MAX", - "F_PATHPKG_CHECK", - "F_PEOFPOSMODE", - "F_PREALLOCATE", - "F_RDADVISE", - "F_RDAHEAD", - "F_RDLCK", - "F_READAHEAD", - "F_READBOOTSTRAP", - "F_SETBACKINGSTORE", - "F_SETFD", - "F_SETFL", - "F_SETLEASE", - "F_SETLK", - "F_SETLK64", - "F_SETLKW", - "F_SETLKW64", - "F_SETLKWTIMEOUT", - "F_SETLK_REMOTE", - "F_SETNOSIGPIPE", - "F_SETOWN", - "F_SETOWN_EX", - "F_SETPIPE_SZ", - "F_SETPROTECTIONCLASS", - "F_SETSIG", - "F_SETSIZE", - "F_SHLCK", - "F_SINGLE_WRITER", - "F_TEST", - "F_THAW_FS", - "F_TLOCK", - "F_TRANSCODEKEY", - "F_ULOCK", - "F_UNLCK", - "F_UNLCKSYS", - "F_VOLPOSMODE", - "F_WRITEBOOTSTRAP", - "F_WRLCK", - "Faccessat", - "Fallocate", - "Fbootstraptransfer_t", - "Fchdir", - "Fchflags", - "Fchmod", - "Fchmodat", - "Fchown", - "Fchownat", - "FcntlFlock", - "FdSet", - "Fdatasync", - "FileNotifyInformation", - "Filetime", - "FindClose", - "FindFirstFile", - "FindNextFile", - "Flock", - "Flock_t", - "FlushBpf", - "FlushFileBuffers", - "FlushViewOfFile", - "ForkExec", - "ForkLock", - "FormatMessage", - "Fpathconf", - "FreeAddrInfoW", - "FreeEnvironmentStrings", - "FreeLibrary", - "Fsid", - "Fstat", - "Fstatat", - "Fstatfs", - "Fstore_t", - "Fsync", - "Ftruncate", - "FullPath", - "Futimes", - "Futimesat", - "GENERIC_ALL", - "GENERIC_EXECUTE", - "GENERIC_READ", - "GENERIC_WRITE", - "GUID", - "GetAcceptExSockaddrs", - "GetAdaptersInfo", - "GetAddrInfoW", - "GetCommandLine", - "GetComputerName", - "GetConsoleMode", - "GetCurrentDirectory", - "GetCurrentProcess", - "GetEnvironmentStrings", - "GetEnvironmentVariable", - "GetExitCodeProcess", - "GetFileAttributes", - "GetFileAttributesEx", - "GetFileExInfoStandard", - "GetFileExMaxInfoLevel", - "GetFileInformationByHandle", - "GetFileType", - "GetFullPathName", - "GetHostByName", - "GetIfEntry", - "GetLastError", - "GetLengthSid", - "GetLongPathName", - "GetProcAddress", - "GetProcessTimes", - "GetProtoByName", - "GetQueuedCompletionStatus", - "GetServByName", - "GetShortPathName", - "GetStartupInfo", - "GetStdHandle", - "GetSystemTimeAsFileTime", - "GetTempPath", - "GetTimeZoneInformation", - "GetTokenInformation", - "GetUserNameEx", - "GetUserProfileDirectory", - "GetVersion", - "Getcwd", - "Getdents", - "Getdirentries", - "Getdtablesize", - "Getegid", - "Getenv", - "Geteuid", - "Getfsstat", - "Getgid", - "Getgroups", - "Getpagesize", - "Getpeername", - "Getpgid", - "Getpgrp", - "Getpid", - "Getppid", - "Getpriority", - "Getrlimit", - "Getrusage", - "Getsid", - "Getsockname", - "Getsockopt", - "GetsockoptByte", - "GetsockoptICMPv6Filter", - "GetsockoptIPMreq", - "GetsockoptIPMreqn", - "GetsockoptIPv6MTUInfo", - "GetsockoptIPv6Mreq", - "GetsockoptInet4Addr", - "GetsockoptInt", - "GetsockoptUcred", - "Gettid", - "Gettimeofday", - "Getuid", - "Getwd", - "Getxattr", - "HANDLE_FLAG_INHERIT", - "HKEY_CLASSES_ROOT", - "HKEY_CURRENT_CONFIG", - "HKEY_CURRENT_USER", - "HKEY_DYN_DATA", - "HKEY_LOCAL_MACHINE", - "HKEY_PERFORMANCE_DATA", - "HKEY_USERS", - "HUPCL", - "Handle", - "Hostent", - "ICANON", - "ICMP6_FILTER", - "ICMPV6_FILTER", - "ICMPv6Filter", - "ICRNL", - "IEXTEN", - "IFAN_ARRIVAL", - "IFAN_DEPARTURE", - "IFA_ADDRESS", - "IFA_ANYCAST", - "IFA_BROADCAST", - "IFA_CACHEINFO", - "IFA_F_DADFAILED", - "IFA_F_DEPRECATED", - "IFA_F_HOMEADDRESS", - "IFA_F_NODAD", - "IFA_F_OPTIMISTIC", - "IFA_F_PERMANENT", - "IFA_F_SECONDARY", - "IFA_F_TEMPORARY", - "IFA_F_TENTATIVE", - "IFA_LABEL", - "IFA_LOCAL", - "IFA_MAX", - "IFA_MULTICAST", - "IFA_ROUTE", - "IFA_UNSPEC", - "IFF_ALLMULTI", - "IFF_ALTPHYS", - "IFF_AUTOMEDIA", - "IFF_BROADCAST", - "IFF_CANTCHANGE", - "IFF_CANTCONFIG", - "IFF_DEBUG", - "IFF_DRV_OACTIVE", - "IFF_DRV_RUNNING", - "IFF_DYING", - "IFF_DYNAMIC", - "IFF_LINK0", - "IFF_LINK1", - "IFF_LINK2", - "IFF_LOOPBACK", - "IFF_MASTER", - "IFF_MONITOR", - "IFF_MULTICAST", - "IFF_NOARP", - "IFF_NOTRAILERS", - "IFF_NO_PI", - "IFF_OACTIVE", - "IFF_ONE_QUEUE", - "IFF_POINTOPOINT", - "IFF_POINTTOPOINT", - "IFF_PORTSEL", - "IFF_PPROMISC", - "IFF_PROMISC", - "IFF_RENAMING", - "IFF_RUNNING", - "IFF_SIMPLEX", - "IFF_SLAVE", - "IFF_SMART", - "IFF_STATICARP", - "IFF_TAP", - "IFF_TUN", - "IFF_TUN_EXCL", - "IFF_UP", - "IFF_VNET_HDR", - "IFLA_ADDRESS", - "IFLA_BROADCAST", - "IFLA_COST", - "IFLA_IFALIAS", - "IFLA_IFNAME", - "IFLA_LINK", - "IFLA_LINKINFO", - "IFLA_LINKMODE", - "IFLA_MAP", - "IFLA_MASTER", - "IFLA_MAX", - "IFLA_MTU", - "IFLA_NET_NS_PID", - "IFLA_OPERSTATE", - "IFLA_PRIORITY", - "IFLA_PROTINFO", - "IFLA_QDISC", - "IFLA_STATS", - "IFLA_TXQLEN", - "IFLA_UNSPEC", - "IFLA_WEIGHT", - "IFLA_WIRELESS", - "IFNAMSIZ", - "IFT_1822", - "IFT_A12MPPSWITCH", - "IFT_AAL2", - "IFT_AAL5", - "IFT_ADSL", - "IFT_AFLANE8023", - "IFT_AFLANE8025", - "IFT_ARAP", - "IFT_ARCNET", - "IFT_ARCNETPLUS", - "IFT_ASYNC", - "IFT_ATM", - "IFT_ATMDXI", - "IFT_ATMFUNI", - "IFT_ATMIMA", - "IFT_ATMLOGICAL", - "IFT_ATMRADIO", - "IFT_ATMSUBINTERFACE", - "IFT_ATMVCIENDPT", - "IFT_ATMVIRTUAL", - "IFT_BGPPOLICYACCOUNTING", - "IFT_BLUETOOTH", - "IFT_BRIDGE", - "IFT_BSC", - "IFT_CARP", - "IFT_CCTEMUL", - "IFT_CELLULAR", - "IFT_CEPT", - "IFT_CES", - "IFT_CHANNEL", - "IFT_CNR", - "IFT_COFFEE", - "IFT_COMPOSITELINK", - "IFT_DCN", - "IFT_DIGITALPOWERLINE", - "IFT_DIGITALWRAPPEROVERHEADCHANNEL", - "IFT_DLSW", - "IFT_DOCSCABLEDOWNSTREAM", - "IFT_DOCSCABLEMACLAYER", - "IFT_DOCSCABLEUPSTREAM", - "IFT_DOCSCABLEUPSTREAMCHANNEL", - "IFT_DS0", - "IFT_DS0BUNDLE", - "IFT_DS1FDL", - "IFT_DS3", - "IFT_DTM", - "IFT_DUMMY", - "IFT_DVBASILN", - "IFT_DVBASIOUT", - "IFT_DVBRCCDOWNSTREAM", - "IFT_DVBRCCMACLAYER", - "IFT_DVBRCCUPSTREAM", - "IFT_ECONET", - "IFT_ENC", - "IFT_EON", - "IFT_EPLRS", - "IFT_ESCON", - "IFT_ETHER", - "IFT_FAITH", - "IFT_FAST", - "IFT_FASTETHER", - "IFT_FASTETHERFX", - "IFT_FDDI", - "IFT_FIBRECHANNEL", - "IFT_FRAMERELAYINTERCONNECT", - "IFT_FRAMERELAYMPI", - "IFT_FRDLCIENDPT", - "IFT_FRELAY", - "IFT_FRELAYDCE", - "IFT_FRF16MFRBUNDLE", - "IFT_FRFORWARD", - "IFT_G703AT2MB", - "IFT_G703AT64K", - "IFT_GIF", - "IFT_GIGABITETHERNET", - "IFT_GR303IDT", - "IFT_GR303RDT", - "IFT_H323GATEKEEPER", - "IFT_H323PROXY", - "IFT_HDH1822", - "IFT_HDLC", - "IFT_HDSL2", - "IFT_HIPERLAN2", - "IFT_HIPPI", - "IFT_HIPPIINTERFACE", - "IFT_HOSTPAD", - "IFT_HSSI", - "IFT_HY", - "IFT_IBM370PARCHAN", - "IFT_IDSL", - "IFT_IEEE1394", - "IFT_IEEE80211", - "IFT_IEEE80212", - "IFT_IEEE8023ADLAG", - "IFT_IFGSN", - "IFT_IMT", - "IFT_INFINIBAND", - "IFT_INTERLEAVE", - "IFT_IP", - "IFT_IPFORWARD", - "IFT_IPOVERATM", - "IFT_IPOVERCDLC", - "IFT_IPOVERCLAW", - "IFT_IPSWITCH", - "IFT_IPXIP", - "IFT_ISDN", - "IFT_ISDNBASIC", - "IFT_ISDNPRIMARY", - "IFT_ISDNS", - "IFT_ISDNU", - "IFT_ISO88022LLC", - "IFT_ISO88023", - "IFT_ISO88024", - "IFT_ISO88025", - "IFT_ISO88025CRFPINT", - "IFT_ISO88025DTR", - "IFT_ISO88025FIBER", - "IFT_ISO88026", - "IFT_ISUP", - "IFT_L2VLAN", - "IFT_L3IPVLAN", - "IFT_L3IPXVLAN", - "IFT_LAPB", - "IFT_LAPD", - "IFT_LAPF", - "IFT_LINEGROUP", - "IFT_LOCALTALK", - "IFT_LOOP", - "IFT_MEDIAMAILOVERIP", - "IFT_MFSIGLINK", - "IFT_MIOX25", - "IFT_MODEM", - "IFT_MPC", - "IFT_MPLS", - "IFT_MPLSTUNNEL", - "IFT_MSDSL", - "IFT_MVL", - "IFT_MYRINET", - "IFT_NFAS", - "IFT_NSIP", - "IFT_OPTICALCHANNEL", - "IFT_OPTICALTRANSPORT", - "IFT_OTHER", - "IFT_P10", - "IFT_P80", - "IFT_PARA", - "IFT_PDP", - "IFT_PFLOG", - "IFT_PFLOW", - "IFT_PFSYNC", - "IFT_PLC", - "IFT_PON155", - "IFT_PON622", - "IFT_POS", - "IFT_PPP", - "IFT_PPPMULTILINKBUNDLE", - "IFT_PROPATM", - "IFT_PROPBWAP2MP", - "IFT_PROPCNLS", - "IFT_PROPDOCSWIRELESSDOWNSTREAM", - "IFT_PROPDOCSWIRELESSMACLAYER", - "IFT_PROPDOCSWIRELESSUPSTREAM", - "IFT_PROPMUX", - "IFT_PROPVIRTUAL", - "IFT_PROPWIRELESSP2P", - "IFT_PTPSERIAL", - "IFT_PVC", - "IFT_Q2931", - "IFT_QLLC", - "IFT_RADIOMAC", - "IFT_RADSL", - "IFT_REACHDSL", - "IFT_RFC1483", - "IFT_RS232", - "IFT_RSRB", - "IFT_SDLC", - "IFT_SDSL", - "IFT_SHDSL", - "IFT_SIP", - "IFT_SIPSIG", - "IFT_SIPTG", - "IFT_SLIP", - "IFT_SMDSDXI", - "IFT_SMDSICIP", - "IFT_SONET", - "IFT_SONETOVERHEADCHANNEL", - "IFT_SONETPATH", - "IFT_SONETVT", - "IFT_SRP", - "IFT_SS7SIGLINK", - "IFT_STACKTOSTACK", - "IFT_STARLAN", - "IFT_STF", - "IFT_T1", - "IFT_TDLC", - "IFT_TELINK", - "IFT_TERMPAD", - "IFT_TR008", - "IFT_TRANSPHDLC", - "IFT_TUNNEL", - "IFT_ULTRA", - "IFT_USB", - "IFT_V11", - "IFT_V35", - "IFT_V36", - "IFT_V37", - "IFT_VDSL", - "IFT_VIRTUALIPADDRESS", - "IFT_VIRTUALTG", - "IFT_VOICEDID", - "IFT_VOICEEM", - "IFT_VOICEEMFGD", - "IFT_VOICEENCAP", - "IFT_VOICEFGDEANA", - "IFT_VOICEFXO", - "IFT_VOICEFXS", - "IFT_VOICEOVERATM", - "IFT_VOICEOVERCABLE", - "IFT_VOICEOVERFRAMERELAY", - "IFT_VOICEOVERIP", - "IFT_X213", - "IFT_X25", - "IFT_X25DDN", - "IFT_X25HUNTGROUP", - "IFT_X25MLP", - "IFT_X25PLE", - "IFT_XETHER", - "IGNBRK", - "IGNCR", - "IGNORE", - "IGNPAR", - "IMAXBEL", - "INFINITE", - "INLCR", - "INPCK", - "INVALID_FILE_ATTRIBUTES", - "IN_ACCESS", - "IN_ALL_EVENTS", - "IN_ATTRIB", - "IN_CLASSA_HOST", - "IN_CLASSA_MAX", - "IN_CLASSA_NET", - "IN_CLASSA_NSHIFT", - "IN_CLASSB_HOST", - "IN_CLASSB_MAX", - "IN_CLASSB_NET", - "IN_CLASSB_NSHIFT", - "IN_CLASSC_HOST", - "IN_CLASSC_NET", - "IN_CLASSC_NSHIFT", - "IN_CLASSD_HOST", - "IN_CLASSD_NET", - "IN_CLASSD_NSHIFT", - "IN_CLOEXEC", - "IN_CLOSE", - "IN_CLOSE_NOWRITE", - "IN_CLOSE_WRITE", - "IN_CREATE", - "IN_DELETE", - "IN_DELETE_SELF", - "IN_DONT_FOLLOW", - "IN_EXCL_UNLINK", - "IN_IGNORED", - "IN_ISDIR", - "IN_LINKLOCALNETNUM", - "IN_LOOPBACKNET", - "IN_MASK_ADD", - "IN_MODIFY", - "IN_MOVE", - "IN_MOVED_FROM", - "IN_MOVED_TO", - "IN_MOVE_SELF", - "IN_NONBLOCK", - "IN_ONESHOT", - "IN_ONLYDIR", - "IN_OPEN", - "IN_Q_OVERFLOW", - "IN_RFC3021_HOST", - "IN_RFC3021_MASK", - "IN_RFC3021_NET", - "IN_RFC3021_NSHIFT", - "IN_UNMOUNT", - "IOC_IN", - "IOC_INOUT", - "IOC_OUT", - "IOC_VENDOR", - "IOC_WS2", - "IO_REPARSE_TAG_SYMLINK", - "IPMreq", - "IPMreqn", - "IPPROTO_3PC", - "IPPROTO_ADFS", - "IPPROTO_AH", - "IPPROTO_AHIP", - "IPPROTO_APES", - "IPPROTO_ARGUS", - "IPPROTO_AX25", - "IPPROTO_BHA", - "IPPROTO_BLT", - "IPPROTO_BRSATMON", - "IPPROTO_CARP", - "IPPROTO_CFTP", - "IPPROTO_CHAOS", - "IPPROTO_CMTP", - "IPPROTO_COMP", - "IPPROTO_CPHB", - "IPPROTO_CPNX", - "IPPROTO_DCCP", - "IPPROTO_DDP", - "IPPROTO_DGP", - "IPPROTO_DIVERT", - "IPPROTO_DIVERT_INIT", - "IPPROTO_DIVERT_RESP", - "IPPROTO_DONE", - "IPPROTO_DSTOPTS", - "IPPROTO_EGP", - "IPPROTO_EMCON", - "IPPROTO_ENCAP", - "IPPROTO_EON", - "IPPROTO_ESP", - "IPPROTO_ETHERIP", - "IPPROTO_FRAGMENT", - "IPPROTO_GGP", - "IPPROTO_GMTP", - "IPPROTO_GRE", - "IPPROTO_HELLO", - "IPPROTO_HMP", - "IPPROTO_HOPOPTS", - "IPPROTO_ICMP", - "IPPROTO_ICMPV6", - "IPPROTO_IDP", - "IPPROTO_IDPR", - "IPPROTO_IDRP", - "IPPROTO_IGMP", - "IPPROTO_IGP", - "IPPROTO_IGRP", - "IPPROTO_IL", - "IPPROTO_INLSP", - "IPPROTO_INP", - "IPPROTO_IP", - "IPPROTO_IPCOMP", - "IPPROTO_IPCV", - "IPPROTO_IPEIP", - "IPPROTO_IPIP", - "IPPROTO_IPPC", - "IPPROTO_IPV4", - "IPPROTO_IPV6", - "IPPROTO_IPV6_ICMP", - "IPPROTO_IRTP", - "IPPROTO_KRYPTOLAN", - "IPPROTO_LARP", - "IPPROTO_LEAF1", - "IPPROTO_LEAF2", - "IPPROTO_MAX", - "IPPROTO_MAXID", - "IPPROTO_MEAS", - "IPPROTO_MH", - "IPPROTO_MHRP", - "IPPROTO_MICP", - "IPPROTO_MOBILE", - "IPPROTO_MPLS", - "IPPROTO_MTP", - "IPPROTO_MUX", - "IPPROTO_ND", - "IPPROTO_NHRP", - "IPPROTO_NONE", - "IPPROTO_NSP", - "IPPROTO_NVPII", - "IPPROTO_OLD_DIVERT", - "IPPROTO_OSPFIGP", - "IPPROTO_PFSYNC", - "IPPROTO_PGM", - "IPPROTO_PIGP", - "IPPROTO_PIM", - "IPPROTO_PRM", - "IPPROTO_PUP", - "IPPROTO_PVP", - "IPPROTO_RAW", - "IPPROTO_RCCMON", - "IPPROTO_RDP", - "IPPROTO_ROUTING", - "IPPROTO_RSVP", - "IPPROTO_RVD", - "IPPROTO_SATEXPAK", - "IPPROTO_SATMON", - "IPPROTO_SCCSP", - "IPPROTO_SCTP", - "IPPROTO_SDRP", - "IPPROTO_SEND", - "IPPROTO_SEP", - "IPPROTO_SKIP", - "IPPROTO_SPACER", - "IPPROTO_SRPC", - "IPPROTO_ST", - "IPPROTO_SVMTP", - "IPPROTO_SWIPE", - "IPPROTO_TCF", - "IPPROTO_TCP", - "IPPROTO_TLSP", - "IPPROTO_TP", - "IPPROTO_TPXX", - "IPPROTO_TRUNK1", - "IPPROTO_TRUNK2", - "IPPROTO_TTP", - "IPPROTO_UDP", - "IPPROTO_UDPLITE", - "IPPROTO_VINES", - "IPPROTO_VISA", - "IPPROTO_VMTP", - "IPPROTO_VRRP", - "IPPROTO_WBEXPAK", - "IPPROTO_WBMON", - "IPPROTO_WSN", - "IPPROTO_XNET", - "IPPROTO_XTP", - "IPV6_2292DSTOPTS", - "IPV6_2292HOPLIMIT", - "IPV6_2292HOPOPTS", - "IPV6_2292NEXTHOP", - "IPV6_2292PKTINFO", - "IPV6_2292PKTOPTIONS", - "IPV6_2292RTHDR", - "IPV6_ADDRFORM", - "IPV6_ADD_MEMBERSHIP", - "IPV6_AUTHHDR", - "IPV6_AUTH_LEVEL", - "IPV6_AUTOFLOWLABEL", - "IPV6_BINDANY", - "IPV6_BINDV6ONLY", - "IPV6_BOUND_IF", - "IPV6_CHECKSUM", - "IPV6_DEFAULT_MULTICAST_HOPS", - "IPV6_DEFAULT_MULTICAST_LOOP", - "IPV6_DEFHLIM", - "IPV6_DONTFRAG", - "IPV6_DROP_MEMBERSHIP", - "IPV6_DSTOPTS", - "IPV6_ESP_NETWORK_LEVEL", - "IPV6_ESP_TRANS_LEVEL", - "IPV6_FAITH", - "IPV6_FLOWINFO_MASK", - "IPV6_FLOWLABEL_MASK", - "IPV6_FRAGTTL", - "IPV6_FW_ADD", - "IPV6_FW_DEL", - "IPV6_FW_FLUSH", - "IPV6_FW_GET", - "IPV6_FW_ZERO", - "IPV6_HLIMDEC", - "IPV6_HOPLIMIT", - "IPV6_HOPOPTS", - "IPV6_IPCOMP_LEVEL", - "IPV6_IPSEC_POLICY", - "IPV6_JOIN_ANYCAST", - "IPV6_JOIN_GROUP", - "IPV6_LEAVE_ANYCAST", - "IPV6_LEAVE_GROUP", - "IPV6_MAXHLIM", - "IPV6_MAXOPTHDR", - "IPV6_MAXPACKET", - "IPV6_MAX_GROUP_SRC_FILTER", - "IPV6_MAX_MEMBERSHIPS", - "IPV6_MAX_SOCK_SRC_FILTER", - "IPV6_MIN_MEMBERSHIPS", - "IPV6_MMTU", - "IPV6_MSFILTER", - "IPV6_MTU", - "IPV6_MTU_DISCOVER", - "IPV6_MULTICAST_HOPS", - "IPV6_MULTICAST_IF", - "IPV6_MULTICAST_LOOP", - "IPV6_NEXTHOP", - "IPV6_OPTIONS", - "IPV6_PATHMTU", - "IPV6_PIPEX", - "IPV6_PKTINFO", - "IPV6_PMTUDISC_DO", - "IPV6_PMTUDISC_DONT", - "IPV6_PMTUDISC_PROBE", - "IPV6_PMTUDISC_WANT", - "IPV6_PORTRANGE", - "IPV6_PORTRANGE_DEFAULT", - "IPV6_PORTRANGE_HIGH", - "IPV6_PORTRANGE_LOW", - "IPV6_PREFER_TEMPADDR", - "IPV6_RECVDSTOPTS", - "IPV6_RECVDSTPORT", - "IPV6_RECVERR", - "IPV6_RECVHOPLIMIT", - "IPV6_RECVHOPOPTS", - "IPV6_RECVPATHMTU", - "IPV6_RECVPKTINFO", - "IPV6_RECVRTHDR", - "IPV6_RECVTCLASS", - "IPV6_ROUTER_ALERT", - "IPV6_RTABLE", - "IPV6_RTHDR", - "IPV6_RTHDRDSTOPTS", - "IPV6_RTHDR_LOOSE", - "IPV6_RTHDR_STRICT", - "IPV6_RTHDR_TYPE_0", - "IPV6_RXDSTOPTS", - "IPV6_RXHOPOPTS", - "IPV6_SOCKOPT_RESERVED1", - "IPV6_TCLASS", - "IPV6_UNICAST_HOPS", - "IPV6_USE_MIN_MTU", - "IPV6_V6ONLY", - "IPV6_VERSION", - "IPV6_VERSION_MASK", - "IPV6_XFRM_POLICY", - "IP_ADD_MEMBERSHIP", - "IP_ADD_SOURCE_MEMBERSHIP", - "IP_AUTH_LEVEL", - "IP_BINDANY", - "IP_BLOCK_SOURCE", - "IP_BOUND_IF", - "IP_DEFAULT_MULTICAST_LOOP", - "IP_DEFAULT_MULTICAST_TTL", - "IP_DF", - "IP_DIVERTFL", - "IP_DONTFRAG", - "IP_DROP_MEMBERSHIP", - "IP_DROP_SOURCE_MEMBERSHIP", - "IP_DUMMYNET3", - "IP_DUMMYNET_CONFIGURE", - "IP_DUMMYNET_DEL", - "IP_DUMMYNET_FLUSH", - "IP_DUMMYNET_GET", - "IP_EF", - "IP_ERRORMTU", - "IP_ESP_NETWORK_LEVEL", - "IP_ESP_TRANS_LEVEL", - "IP_FAITH", - "IP_FREEBIND", - "IP_FW3", - "IP_FW_ADD", - "IP_FW_DEL", - "IP_FW_FLUSH", - "IP_FW_GET", - "IP_FW_NAT_CFG", - "IP_FW_NAT_DEL", - "IP_FW_NAT_GET_CONFIG", - "IP_FW_NAT_GET_LOG", - "IP_FW_RESETLOG", - "IP_FW_TABLE_ADD", - "IP_FW_TABLE_DEL", - "IP_FW_TABLE_FLUSH", - "IP_FW_TABLE_GETSIZE", - "IP_FW_TABLE_LIST", - "IP_FW_ZERO", - "IP_HDRINCL", - "IP_IPCOMP_LEVEL", - "IP_IPSECFLOWINFO", - "IP_IPSEC_LOCAL_AUTH", - "IP_IPSEC_LOCAL_CRED", - "IP_IPSEC_LOCAL_ID", - "IP_IPSEC_POLICY", - "IP_IPSEC_REMOTE_AUTH", - "IP_IPSEC_REMOTE_CRED", - "IP_IPSEC_REMOTE_ID", - "IP_MAXPACKET", - "IP_MAX_GROUP_SRC_FILTER", - "IP_MAX_MEMBERSHIPS", - "IP_MAX_SOCK_MUTE_FILTER", - "IP_MAX_SOCK_SRC_FILTER", - "IP_MAX_SOURCE_FILTER", - "IP_MF", - "IP_MINFRAGSIZE", - "IP_MINTTL", - "IP_MIN_MEMBERSHIPS", - "IP_MSFILTER", - "IP_MSS", - "IP_MTU", - "IP_MTU_DISCOVER", - "IP_MULTICAST_IF", - "IP_MULTICAST_IFINDEX", - "IP_MULTICAST_LOOP", - "IP_MULTICAST_TTL", - "IP_MULTICAST_VIF", - "IP_NAT__XXX", - "IP_OFFMASK", - "IP_OLD_FW_ADD", - "IP_OLD_FW_DEL", - "IP_OLD_FW_FLUSH", - "IP_OLD_FW_GET", - "IP_OLD_FW_RESETLOG", - "IP_OLD_FW_ZERO", - "IP_ONESBCAST", - "IP_OPTIONS", - "IP_ORIGDSTADDR", - "IP_PASSSEC", - "IP_PIPEX", - "IP_PKTINFO", - "IP_PKTOPTIONS", - "IP_PMTUDISC", - "IP_PMTUDISC_DO", - "IP_PMTUDISC_DONT", - "IP_PMTUDISC_PROBE", - "IP_PMTUDISC_WANT", - "IP_PORTRANGE", - "IP_PORTRANGE_DEFAULT", - "IP_PORTRANGE_HIGH", - "IP_PORTRANGE_LOW", - "IP_RECVDSTADDR", - "IP_RECVDSTPORT", - "IP_RECVERR", - "IP_RECVIF", - "IP_RECVOPTS", - "IP_RECVORIGDSTADDR", - "IP_RECVPKTINFO", - "IP_RECVRETOPTS", - "IP_RECVRTABLE", - "IP_RECVTOS", - "IP_RECVTTL", - "IP_RETOPTS", - "IP_RF", - "IP_ROUTER_ALERT", - "IP_RSVP_OFF", - "IP_RSVP_ON", - "IP_RSVP_VIF_OFF", - "IP_RSVP_VIF_ON", - "IP_RTABLE", - "IP_SENDSRCADDR", - "IP_STRIPHDR", - "IP_TOS", - "IP_TRAFFIC_MGT_BACKGROUND", - "IP_TRANSPARENT", - "IP_TTL", - "IP_UNBLOCK_SOURCE", - "IP_XFRM_POLICY", - "IPv6MTUInfo", - "IPv6Mreq", - "ISIG", - "ISTRIP", - "IUCLC", - "IUTF8", - "IXANY", - "IXOFF", - "IXON", - "IfAddrmsg", - "IfAnnounceMsghdr", - "IfData", - "IfInfomsg", - "IfMsghdr", - "IfaMsghdr", - "IfmaMsghdr", - "IfmaMsghdr2", - "ImplementsGetwd", - "Inet4Pktinfo", - "Inet6Pktinfo", - "InotifyAddWatch", - "InotifyEvent", - "InotifyInit", - "InotifyInit1", - "InotifyRmWatch", - "InterfaceAddrMessage", - "InterfaceAnnounceMessage", - "InterfaceInfo", - "InterfaceMessage", - "InterfaceMulticastAddrMessage", - "InvalidHandle", - "Ioperm", - "Iopl", - "Iovec", - "IpAdapterInfo", - "IpAddrString", - "IpAddressString", - "IpMaskString", - "Issetugid", - "KEY_ALL_ACCESS", - "KEY_CREATE_LINK", - "KEY_CREATE_SUB_KEY", - "KEY_ENUMERATE_SUB_KEYS", - "KEY_EXECUTE", - "KEY_NOTIFY", - "KEY_QUERY_VALUE", - "KEY_READ", - "KEY_SET_VALUE", - "KEY_WOW64_32KEY", - "KEY_WOW64_64KEY", - "KEY_WRITE", - "Kevent", - "Kevent_t", - "Kill", - "Klogctl", - "Kqueue", - "LANG_ENGLISH", - "LAYERED_PROTOCOL", - "LCNT_OVERLOAD_FLUSH", - "LINUX_REBOOT_CMD_CAD_OFF", - "LINUX_REBOOT_CMD_CAD_ON", - "LINUX_REBOOT_CMD_HALT", - "LINUX_REBOOT_CMD_KEXEC", - "LINUX_REBOOT_CMD_POWER_OFF", - "LINUX_REBOOT_CMD_RESTART", - "LINUX_REBOOT_CMD_RESTART2", - "LINUX_REBOOT_CMD_SW_SUSPEND", - "LINUX_REBOOT_MAGIC1", - "LINUX_REBOOT_MAGIC2", - "LOCK_EX", - "LOCK_NB", - "LOCK_SH", - "LOCK_UN", - "LazyDLL", - "LazyProc", - "Lchown", - "Linger", - "Link", - "Listen", - "Listxattr", - "LoadCancelIoEx", - "LoadConnectEx", - "LoadCreateSymbolicLink", - "LoadDLL", - "LoadGetAddrInfo", - "LoadLibrary", - "LoadSetFileCompletionNotificationModes", - "LocalFree", - "Log2phys_t", - "LookupAccountName", - "LookupAccountSid", - "LookupSID", - "LsfJump", - "LsfSocket", - "LsfStmt", - "Lstat", - "MADV_AUTOSYNC", - "MADV_CAN_REUSE", - "MADV_CORE", - "MADV_DOFORK", - "MADV_DONTFORK", - "MADV_DONTNEED", - "MADV_FREE", - "MADV_FREE_REUSABLE", - "MADV_FREE_REUSE", - "MADV_HUGEPAGE", - "MADV_HWPOISON", - "MADV_MERGEABLE", - "MADV_NOCORE", - "MADV_NOHUGEPAGE", - "MADV_NORMAL", - "MADV_NOSYNC", - "MADV_PROTECT", - "MADV_RANDOM", - "MADV_REMOVE", - "MADV_SEQUENTIAL", - "MADV_SPACEAVAIL", - "MADV_UNMERGEABLE", - "MADV_WILLNEED", - "MADV_ZERO_WIRED_PAGES", - "MAP_32BIT", - "MAP_ALIGNED_SUPER", - "MAP_ALIGNMENT_16MB", - "MAP_ALIGNMENT_1TB", - "MAP_ALIGNMENT_256TB", - "MAP_ALIGNMENT_4GB", - "MAP_ALIGNMENT_64KB", - "MAP_ALIGNMENT_64PB", - "MAP_ALIGNMENT_MASK", - "MAP_ALIGNMENT_SHIFT", - "MAP_ANON", - "MAP_ANONYMOUS", - "MAP_COPY", - "MAP_DENYWRITE", - "MAP_EXECUTABLE", - "MAP_FILE", - "MAP_FIXED", - "MAP_FLAGMASK", - "MAP_GROWSDOWN", - "MAP_HASSEMAPHORE", - "MAP_HUGETLB", - "MAP_INHERIT", - "MAP_INHERIT_COPY", - "MAP_INHERIT_DEFAULT", - "MAP_INHERIT_DONATE_COPY", - "MAP_INHERIT_NONE", - "MAP_INHERIT_SHARE", - "MAP_JIT", - "MAP_LOCKED", - "MAP_NOCACHE", - "MAP_NOCORE", - "MAP_NOEXTEND", - "MAP_NONBLOCK", - "MAP_NORESERVE", - "MAP_NOSYNC", - "MAP_POPULATE", - "MAP_PREFAULT_READ", - "MAP_PRIVATE", - "MAP_RENAME", - "MAP_RESERVED0080", - "MAP_RESERVED0100", - "MAP_SHARED", - "MAP_STACK", - "MAP_TRYFIXED", - "MAP_TYPE", - "MAP_WIRED", - "MAXIMUM_REPARSE_DATA_BUFFER_SIZE", - "MAXLEN_IFDESCR", - "MAXLEN_PHYSADDR", - "MAX_ADAPTER_ADDRESS_LENGTH", - "MAX_ADAPTER_DESCRIPTION_LENGTH", - "MAX_ADAPTER_NAME_LENGTH", - "MAX_COMPUTERNAME_LENGTH", - "MAX_INTERFACE_NAME_LEN", - "MAX_LONG_PATH", - "MAX_PATH", - "MAX_PROTOCOL_CHAIN", - "MCL_CURRENT", - "MCL_FUTURE", - "MNT_DETACH", - "MNT_EXPIRE", - "MNT_FORCE", - "MSG_BCAST", - "MSG_CMSG_CLOEXEC", - "MSG_COMPAT", - "MSG_CONFIRM", - "MSG_CONTROLMBUF", - "MSG_CTRUNC", - "MSG_DONTROUTE", - "MSG_DONTWAIT", - "MSG_EOF", - "MSG_EOR", - "MSG_ERRQUEUE", - "MSG_FASTOPEN", - "MSG_FIN", - "MSG_FLUSH", - "MSG_HAVEMORE", - "MSG_HOLD", - "MSG_IOVUSRSPACE", - "MSG_LENUSRSPACE", - "MSG_MCAST", - "MSG_MORE", - "MSG_NAMEMBUF", - "MSG_NBIO", - "MSG_NEEDSA", - "MSG_NOSIGNAL", - "MSG_NOTIFICATION", - "MSG_OOB", - "MSG_PEEK", - "MSG_PROXY", - "MSG_RCVMORE", - "MSG_RST", - "MSG_SEND", - "MSG_SYN", - "MSG_TRUNC", - "MSG_TRYHARD", - "MSG_USERFLAGS", - "MSG_WAITALL", - "MSG_WAITFORONE", - "MSG_WAITSTREAM", - "MS_ACTIVE", - "MS_ASYNC", - "MS_BIND", - "MS_DEACTIVATE", - "MS_DIRSYNC", - "MS_INVALIDATE", - "MS_I_VERSION", - "MS_KERNMOUNT", - "MS_KILLPAGES", - "MS_MANDLOCK", - "MS_MGC_MSK", - "MS_MGC_VAL", - "MS_MOVE", - "MS_NOATIME", - "MS_NODEV", - "MS_NODIRATIME", - "MS_NOEXEC", - "MS_NOSUID", - "MS_NOUSER", - "MS_POSIXACL", - "MS_PRIVATE", - "MS_RDONLY", - "MS_REC", - "MS_RELATIME", - "MS_REMOUNT", - "MS_RMT_MASK", - "MS_SHARED", - "MS_SILENT", - "MS_SLAVE", - "MS_STRICTATIME", - "MS_SYNC", - "MS_SYNCHRONOUS", - "MS_UNBINDABLE", - "Madvise", - "MapViewOfFile", - "MaxTokenInfoClass", - "Mclpool", - "MibIfRow", - "Mkdir", - "Mkdirat", - "Mkfifo", - "Mknod", - "Mknodat", - "Mlock", - "Mlockall", - "Mmap", - "Mount", - "MoveFile", - "Mprotect", - "Msghdr", - "Munlock", - "Munlockall", - "Munmap", - "MustLoadDLL", - "NAME_MAX", - "NETLINK_ADD_MEMBERSHIP", - "NETLINK_AUDIT", - "NETLINK_BROADCAST_ERROR", - "NETLINK_CONNECTOR", - "NETLINK_DNRTMSG", - "NETLINK_DROP_MEMBERSHIP", - "NETLINK_ECRYPTFS", - "NETLINK_FIB_LOOKUP", - "NETLINK_FIREWALL", - "NETLINK_GENERIC", - "NETLINK_INET_DIAG", - "NETLINK_IP6_FW", - "NETLINK_ISCSI", - "NETLINK_KOBJECT_UEVENT", - "NETLINK_NETFILTER", - "NETLINK_NFLOG", - "NETLINK_NO_ENOBUFS", - "NETLINK_PKTINFO", - "NETLINK_RDMA", - "NETLINK_ROUTE", - "NETLINK_SCSITRANSPORT", - "NETLINK_SELINUX", - "NETLINK_UNUSED", - "NETLINK_USERSOCK", - "NETLINK_XFRM", - "NET_RT_DUMP", - "NET_RT_DUMP2", - "NET_RT_FLAGS", - "NET_RT_IFLIST", - "NET_RT_IFLIST2", - "NET_RT_IFLISTL", - "NET_RT_IFMALIST", - "NET_RT_MAXID", - "NET_RT_OIFLIST", - "NET_RT_OOIFLIST", - "NET_RT_STAT", - "NET_RT_STATS", - "NET_RT_TABLE", - "NET_RT_TRASH", - "NLA_ALIGNTO", - "NLA_F_NESTED", - "NLA_F_NET_BYTEORDER", - "NLA_HDRLEN", - "NLMSG_ALIGNTO", - "NLMSG_DONE", - "NLMSG_ERROR", - "NLMSG_HDRLEN", - "NLMSG_MIN_TYPE", - "NLMSG_NOOP", - "NLMSG_OVERRUN", - "NLM_F_ACK", - "NLM_F_APPEND", - "NLM_F_ATOMIC", - "NLM_F_CREATE", - "NLM_F_DUMP", - "NLM_F_ECHO", - "NLM_F_EXCL", - "NLM_F_MATCH", - "NLM_F_MULTI", - "NLM_F_REPLACE", - "NLM_F_REQUEST", - "NLM_F_ROOT", - "NOFLSH", - "NOTE_ABSOLUTE", - "NOTE_ATTRIB", - "NOTE_BACKGROUND", - "NOTE_CHILD", - "NOTE_CRITICAL", - "NOTE_DELETE", - "NOTE_EOF", - "NOTE_EXEC", - "NOTE_EXIT", - "NOTE_EXITSTATUS", - "NOTE_EXIT_CSERROR", - "NOTE_EXIT_DECRYPTFAIL", - "NOTE_EXIT_DETAIL", - "NOTE_EXIT_DETAIL_MASK", - "NOTE_EXIT_MEMORY", - "NOTE_EXIT_REPARENTED", - "NOTE_EXTEND", - "NOTE_FFAND", - "NOTE_FFCOPY", - "NOTE_FFCTRLMASK", - "NOTE_FFLAGSMASK", - "NOTE_FFNOP", - "NOTE_FFOR", - "NOTE_FORK", - "NOTE_LEEWAY", - "NOTE_LINK", - "NOTE_LOWAT", - "NOTE_NONE", - "NOTE_NSECONDS", - "NOTE_PCTRLMASK", - "NOTE_PDATAMASK", - "NOTE_REAP", - "NOTE_RENAME", - "NOTE_RESOURCEEND", - "NOTE_REVOKE", - "NOTE_SECONDS", - "NOTE_SIGNAL", - "NOTE_TRACK", - "NOTE_TRACKERR", - "NOTE_TRIGGER", - "NOTE_TRUNCATE", - "NOTE_USECONDS", - "NOTE_VM_ERROR", - "NOTE_VM_PRESSURE", - "NOTE_VM_PRESSURE_SUDDEN_TERMINATE", - "NOTE_VM_PRESSURE_TERMINATE", - "NOTE_WRITE", - "NameCanonical", - "NameCanonicalEx", - "NameDisplay", - "NameDnsDomain", - "NameFullyQualifiedDN", - "NameSamCompatible", - "NameServicePrincipal", - "NameUniqueId", - "NameUnknown", - "NameUserPrincipal", - "Nanosleep", - "NetApiBufferFree", - "NetGetJoinInformation", - "NetSetupDomainName", - "NetSetupUnjoined", - "NetSetupUnknownStatus", - "NetSetupWorkgroupName", - "NetUserGetInfo", - "NetlinkMessage", - "NetlinkRIB", - "NetlinkRouteAttr", - "NetlinkRouteRequest", - "NewCallback", - "NewCallbackCDecl", - "NewLazyDLL", - "NlAttr", - "NlMsgerr", - "NlMsghdr", - "NsecToFiletime", - "NsecToTimespec", - "NsecToTimeval", - "Ntohs", - "OCRNL", - "OFDEL", - "OFILL", - "OFIOGETBMAP", - "OID_PKIX_KP_SERVER_AUTH", - "OID_SERVER_GATED_CRYPTO", - "OID_SGC_NETSCAPE", - "OLCUC", - "ONLCR", - "ONLRET", - "ONOCR", - "ONOEOT", - "OPEN_ALWAYS", - "OPEN_EXISTING", - "OPOST", - "O_ACCMODE", - "O_ALERT", - "O_ALT_IO", - "O_APPEND", - "O_ASYNC", - "O_CLOEXEC", - "O_CREAT", - "O_DIRECT", - "O_DIRECTORY", - "O_DP_GETRAWENCRYPTED", - "O_DSYNC", - "O_EVTONLY", - "O_EXCL", - "O_EXEC", - "O_EXLOCK", - "O_FSYNC", - "O_LARGEFILE", - "O_NDELAY", - "O_NOATIME", - "O_NOCTTY", - "O_NOFOLLOW", - "O_NONBLOCK", - "O_NOSIGPIPE", - "O_POPUP", - "O_RDONLY", - "O_RDWR", - "O_RSYNC", - "O_SHLOCK", - "O_SYMLINK", - "O_SYNC", - "O_TRUNC", - "O_TTY_INIT", - "O_WRONLY", - "Open", - "OpenCurrentProcessToken", - "OpenProcess", - "OpenProcessToken", - "Openat", - "Overlapped", - "PACKET_ADD_MEMBERSHIP", - "PACKET_BROADCAST", - "PACKET_DROP_MEMBERSHIP", - "PACKET_FASTROUTE", - "PACKET_HOST", - "PACKET_LOOPBACK", - "PACKET_MR_ALLMULTI", - "PACKET_MR_MULTICAST", - "PACKET_MR_PROMISC", - "PACKET_MULTICAST", - "PACKET_OTHERHOST", - "PACKET_OUTGOING", - "PACKET_RECV_OUTPUT", - "PACKET_RX_RING", - "PACKET_STATISTICS", - "PAGE_EXECUTE_READ", - "PAGE_EXECUTE_READWRITE", - "PAGE_EXECUTE_WRITECOPY", - "PAGE_READONLY", - "PAGE_READWRITE", - "PAGE_WRITECOPY", - "PARENB", - "PARMRK", - "PARODD", - "PENDIN", - "PFL_HIDDEN", - "PFL_MATCHES_PROTOCOL_ZERO", - "PFL_MULTIPLE_PROTO_ENTRIES", - "PFL_NETWORKDIRECT_PROVIDER", - "PFL_RECOMMENDED_PROTO_ENTRY", - "PF_FLUSH", - "PKCS_7_ASN_ENCODING", - "PMC5_PIPELINE_FLUSH", - "PRIO_PGRP", - "PRIO_PROCESS", - "PRIO_USER", - "PRI_IOFLUSH", - "PROCESS_QUERY_INFORMATION", - "PROCESS_TERMINATE", - "PROT_EXEC", - "PROT_GROWSDOWN", - "PROT_GROWSUP", - "PROT_NONE", - "PROT_READ", - "PROT_WRITE", - "PROV_DH_SCHANNEL", - "PROV_DSS", - "PROV_DSS_DH", - "PROV_EC_ECDSA_FULL", - "PROV_EC_ECDSA_SIG", - "PROV_EC_ECNRA_FULL", - "PROV_EC_ECNRA_SIG", - "PROV_FORTEZZA", - "PROV_INTEL_SEC", - "PROV_MS_EXCHANGE", - "PROV_REPLACE_OWF", - "PROV_RNG", - "PROV_RSA_AES", - "PROV_RSA_FULL", - "PROV_RSA_SCHANNEL", - "PROV_RSA_SIG", - "PROV_SPYRUS_LYNKS", - "PROV_SSL", - "PR_CAPBSET_DROP", - "PR_CAPBSET_READ", - "PR_CLEAR_SECCOMP_FILTER", - "PR_ENDIAN_BIG", - "PR_ENDIAN_LITTLE", - "PR_ENDIAN_PPC_LITTLE", - "PR_FPEMU_NOPRINT", - "PR_FPEMU_SIGFPE", - "PR_FP_EXC_ASYNC", - "PR_FP_EXC_DISABLED", - "PR_FP_EXC_DIV", - "PR_FP_EXC_INV", - "PR_FP_EXC_NONRECOV", - "PR_FP_EXC_OVF", - "PR_FP_EXC_PRECISE", - "PR_FP_EXC_RES", - "PR_FP_EXC_SW_ENABLE", - "PR_FP_EXC_UND", - "PR_GET_DUMPABLE", - "PR_GET_ENDIAN", - "PR_GET_FPEMU", - "PR_GET_FPEXC", - "PR_GET_KEEPCAPS", - "PR_GET_NAME", - "PR_GET_PDEATHSIG", - "PR_GET_SECCOMP", - "PR_GET_SECCOMP_FILTER", - "PR_GET_SECUREBITS", - "PR_GET_TIMERSLACK", - "PR_GET_TIMING", - "PR_GET_TSC", - "PR_GET_UNALIGN", - "PR_MCE_KILL", - "PR_MCE_KILL_CLEAR", - "PR_MCE_KILL_DEFAULT", - "PR_MCE_KILL_EARLY", - "PR_MCE_KILL_GET", - "PR_MCE_KILL_LATE", - "PR_MCE_KILL_SET", - "PR_SECCOMP_FILTER_EVENT", - "PR_SECCOMP_FILTER_SYSCALL", - "PR_SET_DUMPABLE", - "PR_SET_ENDIAN", - "PR_SET_FPEMU", - "PR_SET_FPEXC", - "PR_SET_KEEPCAPS", - "PR_SET_NAME", - "PR_SET_PDEATHSIG", - "PR_SET_PTRACER", - "PR_SET_SECCOMP", - "PR_SET_SECCOMP_FILTER", - "PR_SET_SECUREBITS", - "PR_SET_TIMERSLACK", - "PR_SET_TIMING", - "PR_SET_TSC", - "PR_SET_UNALIGN", - "PR_TASK_PERF_EVENTS_DISABLE", - "PR_TASK_PERF_EVENTS_ENABLE", - "PR_TIMING_STATISTICAL", - "PR_TIMING_TIMESTAMP", - "PR_TSC_ENABLE", - "PR_TSC_SIGSEGV", - "PR_UNALIGN_NOPRINT", - "PR_UNALIGN_SIGBUS", - "PTRACE_ARCH_PRCTL", - "PTRACE_ATTACH", - "PTRACE_CONT", - "PTRACE_DETACH", - "PTRACE_EVENT_CLONE", - "PTRACE_EVENT_EXEC", - "PTRACE_EVENT_EXIT", - "PTRACE_EVENT_FORK", - "PTRACE_EVENT_VFORK", - "PTRACE_EVENT_VFORK_DONE", - "PTRACE_GETCRUNCHREGS", - "PTRACE_GETEVENTMSG", - "PTRACE_GETFPREGS", - "PTRACE_GETFPXREGS", - "PTRACE_GETHBPREGS", - "PTRACE_GETREGS", - "PTRACE_GETREGSET", - "PTRACE_GETSIGINFO", - "PTRACE_GETVFPREGS", - "PTRACE_GETWMMXREGS", - "PTRACE_GET_THREAD_AREA", - "PTRACE_KILL", - "PTRACE_OLDSETOPTIONS", - "PTRACE_O_MASK", - "PTRACE_O_TRACECLONE", - "PTRACE_O_TRACEEXEC", - "PTRACE_O_TRACEEXIT", - "PTRACE_O_TRACEFORK", - "PTRACE_O_TRACESYSGOOD", - "PTRACE_O_TRACEVFORK", - "PTRACE_O_TRACEVFORKDONE", - "PTRACE_PEEKDATA", - "PTRACE_PEEKTEXT", - "PTRACE_PEEKUSR", - "PTRACE_POKEDATA", - "PTRACE_POKETEXT", - "PTRACE_POKEUSR", - "PTRACE_SETCRUNCHREGS", - "PTRACE_SETFPREGS", - "PTRACE_SETFPXREGS", - "PTRACE_SETHBPREGS", - "PTRACE_SETOPTIONS", - "PTRACE_SETREGS", - "PTRACE_SETREGSET", - "PTRACE_SETSIGINFO", - "PTRACE_SETVFPREGS", - "PTRACE_SETWMMXREGS", - "PTRACE_SET_SYSCALL", - "PTRACE_SET_THREAD_AREA", - "PTRACE_SINGLEBLOCK", - "PTRACE_SINGLESTEP", - "PTRACE_SYSCALL", - "PTRACE_SYSEMU", - "PTRACE_SYSEMU_SINGLESTEP", - "PTRACE_TRACEME", - "PT_ATTACH", - "PT_ATTACHEXC", - "PT_CONTINUE", - "PT_DATA_ADDR", - "PT_DENY_ATTACH", - "PT_DETACH", - "PT_FIRSTMACH", - "PT_FORCEQUOTA", - "PT_KILL", - "PT_MASK", - "PT_READ_D", - "PT_READ_I", - "PT_READ_U", - "PT_SIGEXC", - "PT_STEP", - "PT_TEXT_ADDR", - "PT_TEXT_END_ADDR", - "PT_THUPDATE", - "PT_TRACE_ME", - "PT_WRITE_D", - "PT_WRITE_I", - "PT_WRITE_U", - "ParseDirent", - "ParseNetlinkMessage", - "ParseNetlinkRouteAttr", - "ParseRoutingMessage", - "ParseRoutingSockaddr", - "ParseSocketControlMessage", - "ParseUnixCredentials", - "ParseUnixRights", - "PathMax", - "Pathconf", - "Pause", - "Pipe", - "Pipe2", - "PivotRoot", - "Pointer", - "PostQueuedCompletionStatus", - "Pread", - "Proc", - "ProcAttr", - "Process32First", - "Process32Next", - "ProcessEntry32", - "ProcessInformation", - "Protoent", - "PtraceAttach", - "PtraceCont", - "PtraceDetach", - "PtraceGetEventMsg", - "PtraceGetRegs", - "PtracePeekData", - "PtracePeekText", - "PtracePokeData", - "PtracePokeText", - "PtraceRegs", - "PtraceSetOptions", - "PtraceSetRegs", - "PtraceSingleStep", - "PtraceSyscall", - "Pwrite", - "REG_BINARY", - "REG_DWORD", - "REG_DWORD_BIG_ENDIAN", - "REG_DWORD_LITTLE_ENDIAN", - "REG_EXPAND_SZ", - "REG_FULL_RESOURCE_DESCRIPTOR", - "REG_LINK", - "REG_MULTI_SZ", - "REG_NONE", - "REG_QWORD", - "REG_QWORD_LITTLE_ENDIAN", - "REG_RESOURCE_LIST", - "REG_RESOURCE_REQUIREMENTS_LIST", - "REG_SZ", - "RLIMIT_AS", - "RLIMIT_CORE", - "RLIMIT_CPU", - "RLIMIT_CPU_USAGE_MONITOR", - "RLIMIT_DATA", - "RLIMIT_FSIZE", - "RLIMIT_NOFILE", - "RLIMIT_STACK", - "RLIM_INFINITY", - "RTAX_ADVMSS", - "RTAX_AUTHOR", - "RTAX_BRD", - "RTAX_CWND", - "RTAX_DST", - "RTAX_FEATURES", - "RTAX_FEATURE_ALLFRAG", - "RTAX_FEATURE_ECN", - "RTAX_FEATURE_SACK", - "RTAX_FEATURE_TIMESTAMP", - "RTAX_GATEWAY", - "RTAX_GENMASK", - "RTAX_HOPLIMIT", - "RTAX_IFA", - "RTAX_IFP", - "RTAX_INITCWND", - "RTAX_INITRWND", - "RTAX_LABEL", - "RTAX_LOCK", - "RTAX_MAX", - "RTAX_MTU", - "RTAX_NETMASK", - "RTAX_REORDERING", - "RTAX_RTO_MIN", - "RTAX_RTT", - "RTAX_RTTVAR", - "RTAX_SRC", - "RTAX_SRCMASK", - "RTAX_SSTHRESH", - "RTAX_TAG", - "RTAX_UNSPEC", - "RTAX_WINDOW", - "RTA_ALIGNTO", - "RTA_AUTHOR", - "RTA_BRD", - "RTA_CACHEINFO", - "RTA_DST", - "RTA_FLOW", - "RTA_GATEWAY", - "RTA_GENMASK", - "RTA_IFA", - "RTA_IFP", - "RTA_IIF", - "RTA_LABEL", - "RTA_MAX", - "RTA_METRICS", - "RTA_MULTIPATH", - "RTA_NETMASK", - "RTA_OIF", - "RTA_PREFSRC", - "RTA_PRIORITY", - "RTA_SRC", - "RTA_SRCMASK", - "RTA_TABLE", - "RTA_TAG", - "RTA_UNSPEC", - "RTCF_DIRECTSRC", - "RTCF_DOREDIRECT", - "RTCF_LOG", - "RTCF_MASQ", - "RTCF_NAT", - "RTCF_VALVE", - "RTF_ADDRCLASSMASK", - "RTF_ADDRCONF", - "RTF_ALLONLINK", - "RTF_ANNOUNCE", - "RTF_BLACKHOLE", - "RTF_BROADCAST", - "RTF_CACHE", - "RTF_CLONED", - "RTF_CLONING", - "RTF_CONDEMNED", - "RTF_DEFAULT", - "RTF_DELCLONE", - "RTF_DONE", - "RTF_DYNAMIC", - "RTF_FLOW", - "RTF_FMASK", - "RTF_GATEWAY", - "RTF_GWFLAG_COMPAT", - "RTF_HOST", - "RTF_IFREF", - "RTF_IFSCOPE", - "RTF_INTERFACE", - "RTF_IRTT", - "RTF_LINKRT", - "RTF_LLDATA", - "RTF_LLINFO", - "RTF_LOCAL", - "RTF_MASK", - "RTF_MODIFIED", - "RTF_MPATH", - "RTF_MPLS", - "RTF_MSS", - "RTF_MTU", - "RTF_MULTICAST", - "RTF_NAT", - "RTF_NOFORWARD", - "RTF_NONEXTHOP", - "RTF_NOPMTUDISC", - "RTF_PERMANENT_ARP", - "RTF_PINNED", - "RTF_POLICY", - "RTF_PRCLONING", - "RTF_PROTO1", - "RTF_PROTO2", - "RTF_PROTO3", - "RTF_PROXY", - "RTF_REINSTATE", - "RTF_REJECT", - "RTF_RNH_LOCKED", - "RTF_ROUTER", - "RTF_SOURCE", - "RTF_SRC", - "RTF_STATIC", - "RTF_STICKY", - "RTF_THROW", - "RTF_TUNNEL", - "RTF_UP", - "RTF_USETRAILERS", - "RTF_WASCLONED", - "RTF_WINDOW", - "RTF_XRESOLVE", - "RTM_ADD", - "RTM_BASE", - "RTM_CHANGE", - "RTM_CHGADDR", - "RTM_DELACTION", - "RTM_DELADDR", - "RTM_DELADDRLABEL", - "RTM_DELETE", - "RTM_DELLINK", - "RTM_DELMADDR", - "RTM_DELNEIGH", - "RTM_DELQDISC", - "RTM_DELROUTE", - "RTM_DELRULE", - "RTM_DELTCLASS", - "RTM_DELTFILTER", - "RTM_DESYNC", - "RTM_F_CLONED", - "RTM_F_EQUALIZE", - "RTM_F_NOTIFY", - "RTM_F_PREFIX", - "RTM_GET", - "RTM_GET2", - "RTM_GETACTION", - "RTM_GETADDR", - "RTM_GETADDRLABEL", - "RTM_GETANYCAST", - "RTM_GETDCB", - "RTM_GETLINK", - "RTM_GETMULTICAST", - "RTM_GETNEIGH", - "RTM_GETNEIGHTBL", - "RTM_GETQDISC", - "RTM_GETROUTE", - "RTM_GETRULE", - "RTM_GETTCLASS", - "RTM_GETTFILTER", - "RTM_IEEE80211", - "RTM_IFANNOUNCE", - "RTM_IFINFO", - "RTM_IFINFO2", - "RTM_LLINFO_UPD", - "RTM_LOCK", - "RTM_LOSING", - "RTM_MAX", - "RTM_MAXSIZE", - "RTM_MISS", - "RTM_NEWACTION", - "RTM_NEWADDR", - "RTM_NEWADDRLABEL", - "RTM_NEWLINK", - "RTM_NEWMADDR", - "RTM_NEWMADDR2", - "RTM_NEWNDUSEROPT", - "RTM_NEWNEIGH", - "RTM_NEWNEIGHTBL", - "RTM_NEWPREFIX", - "RTM_NEWQDISC", - "RTM_NEWROUTE", - "RTM_NEWRULE", - "RTM_NEWTCLASS", - "RTM_NEWTFILTER", - "RTM_NR_FAMILIES", - "RTM_NR_MSGTYPES", - "RTM_OIFINFO", - "RTM_OLDADD", - "RTM_OLDDEL", - "RTM_OOIFINFO", - "RTM_REDIRECT", - "RTM_RESOLVE", - "RTM_RTTUNIT", - "RTM_SETDCB", - "RTM_SETGATE", - "RTM_SETLINK", - "RTM_SETNEIGHTBL", - "RTM_VERSION", - "RTNH_ALIGNTO", - "RTNH_F_DEAD", - "RTNH_F_ONLINK", - "RTNH_F_PERVASIVE", - "RTNLGRP_IPV4_IFADDR", - "RTNLGRP_IPV4_MROUTE", - "RTNLGRP_IPV4_ROUTE", - "RTNLGRP_IPV4_RULE", - "RTNLGRP_IPV6_IFADDR", - "RTNLGRP_IPV6_IFINFO", - "RTNLGRP_IPV6_MROUTE", - "RTNLGRP_IPV6_PREFIX", - "RTNLGRP_IPV6_ROUTE", - "RTNLGRP_IPV6_RULE", - "RTNLGRP_LINK", - "RTNLGRP_ND_USEROPT", - "RTNLGRP_NEIGH", - "RTNLGRP_NONE", - "RTNLGRP_NOTIFY", - "RTNLGRP_TC", - "RTN_ANYCAST", - "RTN_BLACKHOLE", - "RTN_BROADCAST", - "RTN_LOCAL", - "RTN_MAX", - "RTN_MULTICAST", - "RTN_NAT", - "RTN_PROHIBIT", - "RTN_THROW", - "RTN_UNICAST", - "RTN_UNREACHABLE", - "RTN_UNSPEC", - "RTN_XRESOLVE", - "RTPROT_BIRD", - "RTPROT_BOOT", - "RTPROT_DHCP", - "RTPROT_DNROUTED", - "RTPROT_GATED", - "RTPROT_KERNEL", - "RTPROT_MRT", - "RTPROT_NTK", - "RTPROT_RA", - "RTPROT_REDIRECT", - "RTPROT_STATIC", - "RTPROT_UNSPEC", - "RTPROT_XORP", - "RTPROT_ZEBRA", - "RTV_EXPIRE", - "RTV_HOPCOUNT", - "RTV_MTU", - "RTV_RPIPE", - "RTV_RTT", - "RTV_RTTVAR", - "RTV_SPIPE", - "RTV_SSTHRESH", - "RTV_WEIGHT", - "RT_CACHING_CONTEXT", - "RT_CLASS_DEFAULT", - "RT_CLASS_LOCAL", - "RT_CLASS_MAIN", - "RT_CLASS_MAX", - "RT_CLASS_UNSPEC", - "RT_DEFAULT_FIB", - "RT_NORTREF", - "RT_SCOPE_HOST", - "RT_SCOPE_LINK", - "RT_SCOPE_NOWHERE", - "RT_SCOPE_SITE", - "RT_SCOPE_UNIVERSE", - "RT_TABLEID_MAX", - "RT_TABLE_COMPAT", - "RT_TABLE_DEFAULT", - "RT_TABLE_LOCAL", - "RT_TABLE_MAIN", - "RT_TABLE_MAX", - "RT_TABLE_UNSPEC", - "RUSAGE_CHILDREN", - "RUSAGE_SELF", - "RUSAGE_THREAD", - "Radvisory_t", - "RawConn", - "RawSockaddr", - "RawSockaddrAny", - "RawSockaddrDatalink", - "RawSockaddrInet4", - "RawSockaddrInet6", - "RawSockaddrLinklayer", - "RawSockaddrNetlink", - "RawSockaddrUnix", - "RawSyscall", - "RawSyscall6", - "Read", - "ReadConsole", - "ReadDirectoryChanges", - "ReadDirent", - "ReadFile", - "Readlink", - "Reboot", - "Recvfrom", - "Recvmsg", - "RegCloseKey", - "RegEnumKeyEx", - "RegOpenKeyEx", - "RegQueryInfoKey", - "RegQueryValueEx", - "RemoveDirectory", - "Removexattr", - "Rename", - "Renameat", - "Revoke", - "Rlimit", - "Rmdir", - "RouteMessage", - "RouteRIB", - "RoutingMessage", - "RtAttr", - "RtGenmsg", - "RtMetrics", - "RtMsg", - "RtMsghdr", - "RtNexthop", - "Rusage", - "SCM_BINTIME", - "SCM_CREDENTIALS", - "SCM_CREDS", - "SCM_RIGHTS", - "SCM_TIMESTAMP", - "SCM_TIMESTAMPING", - "SCM_TIMESTAMPNS", - "SCM_TIMESTAMP_MONOTONIC", - "SHUT_RD", - "SHUT_RDWR", - "SHUT_WR", - "SID", - "SIDAndAttributes", - "SIGABRT", - "SIGALRM", - "SIGBUS", - "SIGCHLD", - "SIGCLD", - "SIGCONT", - "SIGEMT", - "SIGFPE", - "SIGHUP", - "SIGILL", - "SIGINFO", - "SIGINT", - "SIGIO", - "SIGIOT", - "SIGKILL", - "SIGLIBRT", - "SIGLWP", - "SIGPIPE", - "SIGPOLL", - "SIGPROF", - "SIGPWR", - "SIGQUIT", - "SIGSEGV", - "SIGSTKFLT", - "SIGSTOP", - "SIGSYS", - "SIGTERM", - "SIGTHR", - "SIGTRAP", - "SIGTSTP", - "SIGTTIN", - "SIGTTOU", - "SIGUNUSED", - "SIGURG", - "SIGUSR1", - "SIGUSR2", - "SIGVTALRM", - "SIGWINCH", - "SIGXCPU", - "SIGXFSZ", - "SIOCADDDLCI", - "SIOCADDMULTI", - "SIOCADDRT", - "SIOCAIFADDR", - "SIOCAIFGROUP", - "SIOCALIFADDR", - "SIOCARPIPLL", - "SIOCATMARK", - "SIOCAUTOADDR", - "SIOCAUTONETMASK", - "SIOCBRDGADD", - "SIOCBRDGADDS", - "SIOCBRDGARL", - "SIOCBRDGDADDR", - "SIOCBRDGDEL", - "SIOCBRDGDELS", - "SIOCBRDGFLUSH", - "SIOCBRDGFRL", - "SIOCBRDGGCACHE", - "SIOCBRDGGFD", - "SIOCBRDGGHT", - "SIOCBRDGGIFFLGS", - "SIOCBRDGGMA", - "SIOCBRDGGPARAM", - "SIOCBRDGGPRI", - "SIOCBRDGGRL", - "SIOCBRDGGSIFS", - "SIOCBRDGGTO", - "SIOCBRDGIFS", - "SIOCBRDGRTS", - "SIOCBRDGSADDR", - "SIOCBRDGSCACHE", - "SIOCBRDGSFD", - "SIOCBRDGSHT", - "SIOCBRDGSIFCOST", - "SIOCBRDGSIFFLGS", - "SIOCBRDGSIFPRIO", - "SIOCBRDGSMA", - "SIOCBRDGSPRI", - "SIOCBRDGSPROTO", - "SIOCBRDGSTO", - "SIOCBRDGSTXHC", - "SIOCDARP", - "SIOCDELDLCI", - "SIOCDELMULTI", - "SIOCDELRT", - "SIOCDEVPRIVATE", - "SIOCDIFADDR", - "SIOCDIFGROUP", - "SIOCDIFPHYADDR", - "SIOCDLIFADDR", - "SIOCDRARP", - "SIOCGARP", - "SIOCGDRVSPEC", - "SIOCGETKALIVE", - "SIOCGETLABEL", - "SIOCGETPFLOW", - "SIOCGETPFSYNC", - "SIOCGETSGCNT", - "SIOCGETVIFCNT", - "SIOCGETVLAN", - "SIOCGHIWAT", - "SIOCGIFADDR", - "SIOCGIFADDRPREF", - "SIOCGIFALIAS", - "SIOCGIFALTMTU", - "SIOCGIFASYNCMAP", - "SIOCGIFBOND", - "SIOCGIFBR", - "SIOCGIFBRDADDR", - "SIOCGIFCAP", - "SIOCGIFCONF", - "SIOCGIFCOUNT", - "SIOCGIFDATA", - "SIOCGIFDESCR", - "SIOCGIFDEVMTU", - "SIOCGIFDLT", - "SIOCGIFDSTADDR", - "SIOCGIFENCAP", - "SIOCGIFFIB", - "SIOCGIFFLAGS", - "SIOCGIFGATTR", - "SIOCGIFGENERIC", - "SIOCGIFGMEMB", - "SIOCGIFGROUP", - "SIOCGIFHARDMTU", - "SIOCGIFHWADDR", - "SIOCGIFINDEX", - "SIOCGIFKPI", - "SIOCGIFMAC", - "SIOCGIFMAP", - "SIOCGIFMEDIA", - "SIOCGIFMEM", - "SIOCGIFMETRIC", - "SIOCGIFMTU", - "SIOCGIFNAME", - "SIOCGIFNETMASK", - "SIOCGIFPDSTADDR", - "SIOCGIFPFLAGS", - "SIOCGIFPHYS", - "SIOCGIFPRIORITY", - "SIOCGIFPSRCADDR", - "SIOCGIFRDOMAIN", - "SIOCGIFRTLABEL", - "SIOCGIFSLAVE", - "SIOCGIFSTATUS", - "SIOCGIFTIMESLOT", - "SIOCGIFTXQLEN", - "SIOCGIFVLAN", - "SIOCGIFWAKEFLAGS", - "SIOCGIFXFLAGS", - "SIOCGLIFADDR", - "SIOCGLIFPHYADDR", - "SIOCGLIFPHYRTABLE", - "SIOCGLIFPHYTTL", - "SIOCGLINKSTR", - "SIOCGLOWAT", - "SIOCGPGRP", - "SIOCGPRIVATE_0", - "SIOCGPRIVATE_1", - "SIOCGRARP", - "SIOCGSPPPPARAMS", - "SIOCGSTAMP", - "SIOCGSTAMPNS", - "SIOCGVH", - "SIOCGVNETID", - "SIOCIFCREATE", - "SIOCIFCREATE2", - "SIOCIFDESTROY", - "SIOCIFGCLONERS", - "SIOCINITIFADDR", - "SIOCPROTOPRIVATE", - "SIOCRSLVMULTI", - "SIOCRTMSG", - "SIOCSARP", - "SIOCSDRVSPEC", - "SIOCSETKALIVE", - "SIOCSETLABEL", - "SIOCSETPFLOW", - "SIOCSETPFSYNC", - "SIOCSETVLAN", - "SIOCSHIWAT", - "SIOCSIFADDR", - "SIOCSIFADDRPREF", - "SIOCSIFALTMTU", - "SIOCSIFASYNCMAP", - "SIOCSIFBOND", - "SIOCSIFBR", - "SIOCSIFBRDADDR", - "SIOCSIFCAP", - "SIOCSIFDESCR", - "SIOCSIFDSTADDR", - "SIOCSIFENCAP", - "SIOCSIFFIB", - "SIOCSIFFLAGS", - "SIOCSIFGATTR", - "SIOCSIFGENERIC", - "SIOCSIFHWADDR", - "SIOCSIFHWBROADCAST", - "SIOCSIFKPI", - "SIOCSIFLINK", - "SIOCSIFLLADDR", - "SIOCSIFMAC", - "SIOCSIFMAP", - "SIOCSIFMEDIA", - "SIOCSIFMEM", - "SIOCSIFMETRIC", - "SIOCSIFMTU", - "SIOCSIFNAME", - "SIOCSIFNETMASK", - "SIOCSIFPFLAGS", - "SIOCSIFPHYADDR", - "SIOCSIFPHYS", - "SIOCSIFPRIORITY", - "SIOCSIFRDOMAIN", - "SIOCSIFRTLABEL", - "SIOCSIFRVNET", - "SIOCSIFSLAVE", - "SIOCSIFTIMESLOT", - "SIOCSIFTXQLEN", - "SIOCSIFVLAN", - "SIOCSIFVNET", - "SIOCSIFXFLAGS", - "SIOCSLIFPHYADDR", - "SIOCSLIFPHYRTABLE", - "SIOCSLIFPHYTTL", - "SIOCSLINKSTR", - "SIOCSLOWAT", - "SIOCSPGRP", - "SIOCSRARP", - "SIOCSSPPPPARAMS", - "SIOCSVH", - "SIOCSVNETID", - "SIOCZIFDATA", - "SIO_GET_EXTENSION_FUNCTION_POINTER", - "SIO_GET_INTERFACE_LIST", - "SIO_KEEPALIVE_VALS", - "SIO_UDP_CONNRESET", - "SOCK_CLOEXEC", - "SOCK_DCCP", - "SOCK_DGRAM", - "SOCK_FLAGS_MASK", - "SOCK_MAXADDRLEN", - "SOCK_NONBLOCK", - "SOCK_NOSIGPIPE", - "SOCK_PACKET", - "SOCK_RAW", - "SOCK_RDM", - "SOCK_SEQPACKET", - "SOCK_STREAM", - "SOL_AAL", - "SOL_ATM", - "SOL_DECNET", - "SOL_ICMPV6", - "SOL_IP", - "SOL_IPV6", - "SOL_IRDA", - "SOL_PACKET", - "SOL_RAW", - "SOL_SOCKET", - "SOL_TCP", - "SOL_X25", - "SOMAXCONN", - "SO_ACCEPTCONN", - "SO_ACCEPTFILTER", - "SO_ATTACH_FILTER", - "SO_BINDANY", - "SO_BINDTODEVICE", - "SO_BINTIME", - "SO_BROADCAST", - "SO_BSDCOMPAT", - "SO_DEBUG", - "SO_DETACH_FILTER", - "SO_DOMAIN", - "SO_DONTROUTE", - "SO_DONTTRUNC", - "SO_ERROR", - "SO_KEEPALIVE", - "SO_LABEL", - "SO_LINGER", - "SO_LINGER_SEC", - "SO_LISTENINCQLEN", - "SO_LISTENQLEN", - "SO_LISTENQLIMIT", - "SO_MARK", - "SO_NETPROC", - "SO_NKE", - "SO_NOADDRERR", - "SO_NOHEADER", - "SO_NOSIGPIPE", - "SO_NOTIFYCONFLICT", - "SO_NO_CHECK", - "SO_NO_DDP", - "SO_NO_OFFLOAD", - "SO_NP_EXTENSIONS", - "SO_NREAD", - "SO_NUMRCVPKT", - "SO_NWRITE", - "SO_OOBINLINE", - "SO_OVERFLOWED", - "SO_PASSCRED", - "SO_PASSSEC", - "SO_PEERCRED", - "SO_PEERLABEL", - "SO_PEERNAME", - "SO_PEERSEC", - "SO_PRIORITY", - "SO_PROTOCOL", - "SO_PROTOTYPE", - "SO_RANDOMPORT", - "SO_RCVBUF", - "SO_RCVBUFFORCE", - "SO_RCVLOWAT", - "SO_RCVTIMEO", - "SO_RESTRICTIONS", - "SO_RESTRICT_DENYIN", - "SO_RESTRICT_DENYOUT", - "SO_RESTRICT_DENYSET", - "SO_REUSEADDR", - "SO_REUSEPORT", - "SO_REUSESHAREUID", - "SO_RTABLE", - "SO_RXQ_OVFL", - "SO_SECURITY_AUTHENTICATION", - "SO_SECURITY_ENCRYPTION_NETWORK", - "SO_SECURITY_ENCRYPTION_TRANSPORT", - "SO_SETFIB", - "SO_SNDBUF", - "SO_SNDBUFFORCE", - "SO_SNDLOWAT", - "SO_SNDTIMEO", - "SO_SPLICE", - "SO_TIMESTAMP", - "SO_TIMESTAMPING", - "SO_TIMESTAMPNS", - "SO_TIMESTAMP_MONOTONIC", - "SO_TYPE", - "SO_UPCALLCLOSEWAIT", - "SO_UPDATE_ACCEPT_CONTEXT", - "SO_UPDATE_CONNECT_CONTEXT", - "SO_USELOOPBACK", - "SO_USER_COOKIE", - "SO_VENDOR", - "SO_WANTMORE", - "SO_WANTOOBFLAG", - "SSLExtraCertChainPolicyPara", - "STANDARD_RIGHTS_ALL", - "STANDARD_RIGHTS_EXECUTE", - "STANDARD_RIGHTS_READ", - "STANDARD_RIGHTS_REQUIRED", - "STANDARD_RIGHTS_WRITE", - "STARTF_USESHOWWINDOW", - "STARTF_USESTDHANDLES", - "STD_ERROR_HANDLE", - "STD_INPUT_HANDLE", - "STD_OUTPUT_HANDLE", - "SUBLANG_ENGLISH_US", - "SW_FORCEMINIMIZE", - "SW_HIDE", - "SW_MAXIMIZE", - "SW_MINIMIZE", - "SW_NORMAL", - "SW_RESTORE", - "SW_SHOW", - "SW_SHOWDEFAULT", - "SW_SHOWMAXIMIZED", - "SW_SHOWMINIMIZED", - "SW_SHOWMINNOACTIVE", - "SW_SHOWNA", - "SW_SHOWNOACTIVATE", - "SW_SHOWNORMAL", - "SYMBOLIC_LINK_FLAG_DIRECTORY", - "SYNCHRONIZE", - "SYSCTL_VERSION", - "SYSCTL_VERS_0", - "SYSCTL_VERS_1", - "SYSCTL_VERS_MASK", - "SYS_ABORT2", - "SYS_ACCEPT", - "SYS_ACCEPT4", - "SYS_ACCEPT_NOCANCEL", - "SYS_ACCESS", - "SYS_ACCESS_EXTENDED", - "SYS_ACCT", - "SYS_ADD_KEY", - "SYS_ADD_PROFIL", - "SYS_ADJFREQ", - "SYS_ADJTIME", - "SYS_ADJTIMEX", - "SYS_AFS_SYSCALL", - "SYS_AIO_CANCEL", - "SYS_AIO_ERROR", - "SYS_AIO_FSYNC", - "SYS_AIO_MLOCK", - "SYS_AIO_READ", - "SYS_AIO_RETURN", - "SYS_AIO_SUSPEND", - "SYS_AIO_SUSPEND_NOCANCEL", - "SYS_AIO_WAITCOMPLETE", - "SYS_AIO_WRITE", - "SYS_ALARM", - "SYS_ARCH_PRCTL", - "SYS_ARM_FADVISE64_64", - "SYS_ARM_SYNC_FILE_RANGE", - "SYS_ATGETMSG", - "SYS_ATPGETREQ", - "SYS_ATPGETRSP", - "SYS_ATPSNDREQ", - "SYS_ATPSNDRSP", - "SYS_ATPUTMSG", - "SYS_ATSOCKET", - "SYS_AUDIT", - "SYS_AUDITCTL", - "SYS_AUDITON", - "SYS_AUDIT_SESSION_JOIN", - "SYS_AUDIT_SESSION_PORT", - "SYS_AUDIT_SESSION_SELF", - "SYS_BDFLUSH", - "SYS_BIND", - "SYS_BINDAT", - "SYS_BREAK", - "SYS_BRK", - "SYS_BSDTHREAD_CREATE", - "SYS_BSDTHREAD_REGISTER", - "SYS_BSDTHREAD_TERMINATE", - "SYS_CAPGET", - "SYS_CAPSET", - "SYS_CAP_ENTER", - "SYS_CAP_FCNTLS_GET", - "SYS_CAP_FCNTLS_LIMIT", - "SYS_CAP_GETMODE", - "SYS_CAP_GETRIGHTS", - "SYS_CAP_IOCTLS_GET", - "SYS_CAP_IOCTLS_LIMIT", - "SYS_CAP_NEW", - "SYS_CAP_RIGHTS_GET", - "SYS_CAP_RIGHTS_LIMIT", - "SYS_CHDIR", - "SYS_CHFLAGS", - "SYS_CHFLAGSAT", - "SYS_CHMOD", - "SYS_CHMOD_EXTENDED", - "SYS_CHOWN", - "SYS_CHOWN32", - "SYS_CHROOT", - "SYS_CHUD", - "SYS_CLOCK_ADJTIME", - "SYS_CLOCK_GETCPUCLOCKID2", - "SYS_CLOCK_GETRES", - "SYS_CLOCK_GETTIME", - "SYS_CLOCK_NANOSLEEP", - "SYS_CLOCK_SETTIME", - "SYS_CLONE", - "SYS_CLOSE", - "SYS_CLOSEFROM", - "SYS_CLOSE_NOCANCEL", - "SYS_CONNECT", - "SYS_CONNECTAT", - "SYS_CONNECT_NOCANCEL", - "SYS_COPYFILE", - "SYS_CPUSET", - "SYS_CPUSET_GETAFFINITY", - "SYS_CPUSET_GETID", - "SYS_CPUSET_SETAFFINITY", - "SYS_CPUSET_SETID", - "SYS_CREAT", - "SYS_CREATE_MODULE", - "SYS_CSOPS", - "SYS_CSOPS_AUDITTOKEN", - "SYS_DELETE", - "SYS_DELETE_MODULE", - "SYS_DUP", - "SYS_DUP2", - "SYS_DUP3", - "SYS_EACCESS", - "SYS_EPOLL_CREATE", - "SYS_EPOLL_CREATE1", - "SYS_EPOLL_CTL", - "SYS_EPOLL_CTL_OLD", - "SYS_EPOLL_PWAIT", - "SYS_EPOLL_WAIT", - "SYS_EPOLL_WAIT_OLD", - "SYS_EVENTFD", - "SYS_EVENTFD2", - "SYS_EXCHANGEDATA", - "SYS_EXECVE", - "SYS_EXIT", - "SYS_EXIT_GROUP", - "SYS_EXTATTRCTL", - "SYS_EXTATTR_DELETE_FD", - "SYS_EXTATTR_DELETE_FILE", - "SYS_EXTATTR_DELETE_LINK", - "SYS_EXTATTR_GET_FD", - "SYS_EXTATTR_GET_FILE", - "SYS_EXTATTR_GET_LINK", - "SYS_EXTATTR_LIST_FD", - "SYS_EXTATTR_LIST_FILE", - "SYS_EXTATTR_LIST_LINK", - "SYS_EXTATTR_SET_FD", - "SYS_EXTATTR_SET_FILE", - "SYS_EXTATTR_SET_LINK", - "SYS_FACCESSAT", - "SYS_FADVISE64", - "SYS_FADVISE64_64", - "SYS_FALLOCATE", - "SYS_FANOTIFY_INIT", - "SYS_FANOTIFY_MARK", - "SYS_FCHDIR", - "SYS_FCHFLAGS", - "SYS_FCHMOD", - "SYS_FCHMODAT", - "SYS_FCHMOD_EXTENDED", - "SYS_FCHOWN", - "SYS_FCHOWN32", - "SYS_FCHOWNAT", - "SYS_FCHROOT", - "SYS_FCNTL", - "SYS_FCNTL64", - "SYS_FCNTL_NOCANCEL", - "SYS_FDATASYNC", - "SYS_FEXECVE", - "SYS_FFCLOCK_GETCOUNTER", - "SYS_FFCLOCK_GETESTIMATE", - "SYS_FFCLOCK_SETESTIMATE", - "SYS_FFSCTL", - "SYS_FGETATTRLIST", - "SYS_FGETXATTR", - "SYS_FHOPEN", - "SYS_FHSTAT", - "SYS_FHSTATFS", - "SYS_FILEPORT_MAKEFD", - "SYS_FILEPORT_MAKEPORT", - "SYS_FKTRACE", - "SYS_FLISTXATTR", - "SYS_FLOCK", - "SYS_FORK", - "SYS_FPATHCONF", - "SYS_FREEBSD6_FTRUNCATE", - "SYS_FREEBSD6_LSEEK", - "SYS_FREEBSD6_MMAP", - "SYS_FREEBSD6_PREAD", - "SYS_FREEBSD6_PWRITE", - "SYS_FREEBSD6_TRUNCATE", - "SYS_FREMOVEXATTR", - "SYS_FSCTL", - "SYS_FSETATTRLIST", - "SYS_FSETXATTR", - "SYS_FSGETPATH", - "SYS_FSTAT", - "SYS_FSTAT64", - "SYS_FSTAT64_EXTENDED", - "SYS_FSTATAT", - "SYS_FSTATAT64", - "SYS_FSTATFS", - "SYS_FSTATFS64", - "SYS_FSTATV", - "SYS_FSTATVFS1", - "SYS_FSTAT_EXTENDED", - "SYS_FSYNC", - "SYS_FSYNC_NOCANCEL", - "SYS_FSYNC_RANGE", - "SYS_FTIME", - "SYS_FTRUNCATE", - "SYS_FTRUNCATE64", - "SYS_FUTEX", - "SYS_FUTIMENS", - "SYS_FUTIMES", - "SYS_FUTIMESAT", - "SYS_GETATTRLIST", - "SYS_GETAUDIT", - "SYS_GETAUDIT_ADDR", - "SYS_GETAUID", - "SYS_GETCONTEXT", - "SYS_GETCPU", - "SYS_GETCWD", - "SYS_GETDENTS", - "SYS_GETDENTS64", - "SYS_GETDIRENTRIES", - "SYS_GETDIRENTRIES64", - "SYS_GETDIRENTRIESATTR", - "SYS_GETDTABLECOUNT", - "SYS_GETDTABLESIZE", - "SYS_GETEGID", - "SYS_GETEGID32", - "SYS_GETEUID", - "SYS_GETEUID32", - "SYS_GETFH", - "SYS_GETFSSTAT", - "SYS_GETFSSTAT64", - "SYS_GETGID", - "SYS_GETGID32", - "SYS_GETGROUPS", - "SYS_GETGROUPS32", - "SYS_GETHOSTUUID", - "SYS_GETITIMER", - "SYS_GETLCID", - "SYS_GETLOGIN", - "SYS_GETLOGINCLASS", - "SYS_GETPEERNAME", - "SYS_GETPGID", - "SYS_GETPGRP", - "SYS_GETPID", - "SYS_GETPMSG", - "SYS_GETPPID", - "SYS_GETPRIORITY", - "SYS_GETRESGID", - "SYS_GETRESGID32", - "SYS_GETRESUID", - "SYS_GETRESUID32", - "SYS_GETRLIMIT", - "SYS_GETRTABLE", - "SYS_GETRUSAGE", - "SYS_GETSGROUPS", - "SYS_GETSID", - "SYS_GETSOCKNAME", - "SYS_GETSOCKOPT", - "SYS_GETTHRID", - "SYS_GETTID", - "SYS_GETTIMEOFDAY", - "SYS_GETUID", - "SYS_GETUID32", - "SYS_GETVFSSTAT", - "SYS_GETWGROUPS", - "SYS_GETXATTR", - "SYS_GET_KERNEL_SYMS", - "SYS_GET_MEMPOLICY", - "SYS_GET_ROBUST_LIST", - "SYS_GET_THREAD_AREA", - "SYS_GSSD_SYSCALL", - "SYS_GTTY", - "SYS_IDENTITYSVC", - "SYS_IDLE", - "SYS_INITGROUPS", - "SYS_INIT_MODULE", - "SYS_INOTIFY_ADD_WATCH", - "SYS_INOTIFY_INIT", - "SYS_INOTIFY_INIT1", - "SYS_INOTIFY_RM_WATCH", - "SYS_IOCTL", - "SYS_IOPERM", - "SYS_IOPL", - "SYS_IOPOLICYSYS", - "SYS_IOPRIO_GET", - "SYS_IOPRIO_SET", - "SYS_IO_CANCEL", - "SYS_IO_DESTROY", - "SYS_IO_GETEVENTS", - "SYS_IO_SETUP", - "SYS_IO_SUBMIT", - "SYS_IPC", - "SYS_ISSETUGID", - "SYS_JAIL", - "SYS_JAIL_ATTACH", - "SYS_JAIL_GET", - "SYS_JAIL_REMOVE", - "SYS_JAIL_SET", - "SYS_KAS_INFO", - "SYS_KDEBUG_TRACE", - "SYS_KENV", - "SYS_KEVENT", - "SYS_KEVENT64", - "SYS_KEXEC_LOAD", - "SYS_KEYCTL", - "SYS_KILL", - "SYS_KLDFIND", - "SYS_KLDFIRSTMOD", - "SYS_KLDLOAD", - "SYS_KLDNEXT", - "SYS_KLDSTAT", - "SYS_KLDSYM", - "SYS_KLDUNLOAD", - "SYS_KLDUNLOADF", - "SYS_KMQ_NOTIFY", - "SYS_KMQ_OPEN", - "SYS_KMQ_SETATTR", - "SYS_KMQ_TIMEDRECEIVE", - "SYS_KMQ_TIMEDSEND", - "SYS_KMQ_UNLINK", - "SYS_KQUEUE", - "SYS_KQUEUE1", - "SYS_KSEM_CLOSE", - "SYS_KSEM_DESTROY", - "SYS_KSEM_GETVALUE", - "SYS_KSEM_INIT", - "SYS_KSEM_OPEN", - "SYS_KSEM_POST", - "SYS_KSEM_TIMEDWAIT", - "SYS_KSEM_TRYWAIT", - "SYS_KSEM_UNLINK", - "SYS_KSEM_WAIT", - "SYS_KTIMER_CREATE", - "SYS_KTIMER_DELETE", - "SYS_KTIMER_GETOVERRUN", - "SYS_KTIMER_GETTIME", - "SYS_KTIMER_SETTIME", - "SYS_KTRACE", - "SYS_LCHFLAGS", - "SYS_LCHMOD", - "SYS_LCHOWN", - "SYS_LCHOWN32", - "SYS_LEDGER", - "SYS_LGETFH", - "SYS_LGETXATTR", - "SYS_LINK", - "SYS_LINKAT", - "SYS_LIO_LISTIO", - "SYS_LISTEN", - "SYS_LISTXATTR", - "SYS_LLISTXATTR", - "SYS_LOCK", - "SYS_LOOKUP_DCOOKIE", - "SYS_LPATHCONF", - "SYS_LREMOVEXATTR", - "SYS_LSEEK", - "SYS_LSETXATTR", - "SYS_LSTAT", - "SYS_LSTAT64", - "SYS_LSTAT64_EXTENDED", - "SYS_LSTATV", - "SYS_LSTAT_EXTENDED", - "SYS_LUTIMES", - "SYS_MAC_SYSCALL", - "SYS_MADVISE", - "SYS_MADVISE1", - "SYS_MAXSYSCALL", - "SYS_MBIND", - "SYS_MIGRATE_PAGES", - "SYS_MINCORE", - "SYS_MINHERIT", - "SYS_MKCOMPLEX", - "SYS_MKDIR", - "SYS_MKDIRAT", - "SYS_MKDIR_EXTENDED", - "SYS_MKFIFO", - "SYS_MKFIFOAT", - "SYS_MKFIFO_EXTENDED", - "SYS_MKNOD", - "SYS_MKNODAT", - "SYS_MLOCK", - "SYS_MLOCKALL", - "SYS_MMAP", - "SYS_MMAP2", - "SYS_MODCTL", - "SYS_MODFIND", - "SYS_MODFNEXT", - "SYS_MODIFY_LDT", - "SYS_MODNEXT", - "SYS_MODSTAT", - "SYS_MODWATCH", - "SYS_MOUNT", - "SYS_MOVE_PAGES", - "SYS_MPROTECT", - "SYS_MPX", - "SYS_MQUERY", - "SYS_MQ_GETSETATTR", - "SYS_MQ_NOTIFY", - "SYS_MQ_OPEN", - "SYS_MQ_TIMEDRECEIVE", - "SYS_MQ_TIMEDSEND", - "SYS_MQ_UNLINK", - "SYS_MREMAP", - "SYS_MSGCTL", - "SYS_MSGGET", - "SYS_MSGRCV", - "SYS_MSGRCV_NOCANCEL", - "SYS_MSGSND", - "SYS_MSGSND_NOCANCEL", - "SYS_MSGSYS", - "SYS_MSYNC", - "SYS_MSYNC_NOCANCEL", - "SYS_MUNLOCK", - "SYS_MUNLOCKALL", - "SYS_MUNMAP", - "SYS_NAME_TO_HANDLE_AT", - "SYS_NANOSLEEP", - "SYS_NEWFSTATAT", - "SYS_NFSCLNT", - "SYS_NFSSERVCTL", - "SYS_NFSSVC", - "SYS_NFSTAT", - "SYS_NICE", - "SYS_NLM_SYSCALL", - "SYS_NLSTAT", - "SYS_NMOUNT", - "SYS_NSTAT", - "SYS_NTP_ADJTIME", - "SYS_NTP_GETTIME", - "SYS_NUMA_GETAFFINITY", - "SYS_NUMA_SETAFFINITY", - "SYS_OABI_SYSCALL_BASE", - "SYS_OBREAK", - "SYS_OLDFSTAT", - "SYS_OLDLSTAT", - "SYS_OLDOLDUNAME", - "SYS_OLDSTAT", - "SYS_OLDUNAME", - "SYS_OPEN", - "SYS_OPENAT", - "SYS_OPENBSD_POLL", - "SYS_OPEN_BY_HANDLE_AT", - "SYS_OPEN_DPROTECTED_NP", - "SYS_OPEN_EXTENDED", - "SYS_OPEN_NOCANCEL", - "SYS_OVADVISE", - "SYS_PACCEPT", - "SYS_PATHCONF", - "SYS_PAUSE", - "SYS_PCICONFIG_IOBASE", - "SYS_PCICONFIG_READ", - "SYS_PCICONFIG_WRITE", - "SYS_PDFORK", - "SYS_PDGETPID", - "SYS_PDKILL", - "SYS_PERF_EVENT_OPEN", - "SYS_PERSONALITY", - "SYS_PID_HIBERNATE", - "SYS_PID_RESUME", - "SYS_PID_SHUTDOWN_SOCKETS", - "SYS_PID_SUSPEND", - "SYS_PIPE", - "SYS_PIPE2", - "SYS_PIVOT_ROOT", - "SYS_PMC_CONTROL", - "SYS_PMC_GET_INFO", - "SYS_POLL", - "SYS_POLLTS", - "SYS_POLL_NOCANCEL", - "SYS_POSIX_FADVISE", - "SYS_POSIX_FALLOCATE", - "SYS_POSIX_OPENPT", - "SYS_POSIX_SPAWN", - "SYS_PPOLL", - "SYS_PRCTL", - "SYS_PREAD", - "SYS_PREAD64", - "SYS_PREADV", - "SYS_PREAD_NOCANCEL", - "SYS_PRLIMIT64", - "SYS_PROCCTL", - "SYS_PROCESS_POLICY", - "SYS_PROCESS_VM_READV", - "SYS_PROCESS_VM_WRITEV", - "SYS_PROC_INFO", - "SYS_PROF", - "SYS_PROFIL", - "SYS_PSELECT", - "SYS_PSELECT6", - "SYS_PSET_ASSIGN", - "SYS_PSET_CREATE", - "SYS_PSET_DESTROY", - "SYS_PSYNCH_CVBROAD", - "SYS_PSYNCH_CVCLRPREPOST", - "SYS_PSYNCH_CVSIGNAL", - "SYS_PSYNCH_CVWAIT", - "SYS_PSYNCH_MUTEXDROP", - "SYS_PSYNCH_MUTEXWAIT", - "SYS_PSYNCH_RW_DOWNGRADE", - "SYS_PSYNCH_RW_LONGRDLOCK", - "SYS_PSYNCH_RW_RDLOCK", - "SYS_PSYNCH_RW_UNLOCK", - "SYS_PSYNCH_RW_UNLOCK2", - "SYS_PSYNCH_RW_UPGRADE", - "SYS_PSYNCH_RW_WRLOCK", - "SYS_PSYNCH_RW_YIELDWRLOCK", - "SYS_PTRACE", - "SYS_PUTPMSG", - "SYS_PWRITE", - "SYS_PWRITE64", - "SYS_PWRITEV", - "SYS_PWRITE_NOCANCEL", - "SYS_QUERY_MODULE", - "SYS_QUOTACTL", - "SYS_RASCTL", - "SYS_RCTL_ADD_RULE", - "SYS_RCTL_GET_LIMITS", - "SYS_RCTL_GET_RACCT", - "SYS_RCTL_GET_RULES", - "SYS_RCTL_REMOVE_RULE", - "SYS_READ", - "SYS_READAHEAD", - "SYS_READDIR", - "SYS_READLINK", - "SYS_READLINKAT", - "SYS_READV", - "SYS_READV_NOCANCEL", - "SYS_READ_NOCANCEL", - "SYS_REBOOT", - "SYS_RECV", - "SYS_RECVFROM", - "SYS_RECVFROM_NOCANCEL", - "SYS_RECVMMSG", - "SYS_RECVMSG", - "SYS_RECVMSG_NOCANCEL", - "SYS_REMAP_FILE_PAGES", - "SYS_REMOVEXATTR", - "SYS_RENAME", - "SYS_RENAMEAT", - "SYS_REQUEST_KEY", - "SYS_RESTART_SYSCALL", - "SYS_REVOKE", - "SYS_RFORK", - "SYS_RMDIR", - "SYS_RTPRIO", - "SYS_RTPRIO_THREAD", - "SYS_RT_SIGACTION", - "SYS_RT_SIGPENDING", - "SYS_RT_SIGPROCMASK", - "SYS_RT_SIGQUEUEINFO", - "SYS_RT_SIGRETURN", - "SYS_RT_SIGSUSPEND", - "SYS_RT_SIGTIMEDWAIT", - "SYS_RT_TGSIGQUEUEINFO", - "SYS_SBRK", - "SYS_SCHED_GETAFFINITY", - "SYS_SCHED_GETPARAM", - "SYS_SCHED_GETSCHEDULER", - "SYS_SCHED_GET_PRIORITY_MAX", - "SYS_SCHED_GET_PRIORITY_MIN", - "SYS_SCHED_RR_GET_INTERVAL", - "SYS_SCHED_SETAFFINITY", - "SYS_SCHED_SETPARAM", - "SYS_SCHED_SETSCHEDULER", - "SYS_SCHED_YIELD", - "SYS_SCTP_GENERIC_RECVMSG", - "SYS_SCTP_GENERIC_SENDMSG", - "SYS_SCTP_GENERIC_SENDMSG_IOV", - "SYS_SCTP_PEELOFF", - "SYS_SEARCHFS", - "SYS_SECURITY", - "SYS_SELECT", - "SYS_SELECT_NOCANCEL", - "SYS_SEMCONFIG", - "SYS_SEMCTL", - "SYS_SEMGET", - "SYS_SEMOP", - "SYS_SEMSYS", - "SYS_SEMTIMEDOP", - "SYS_SEM_CLOSE", - "SYS_SEM_DESTROY", - "SYS_SEM_GETVALUE", - "SYS_SEM_INIT", - "SYS_SEM_OPEN", - "SYS_SEM_POST", - "SYS_SEM_TRYWAIT", - "SYS_SEM_UNLINK", - "SYS_SEM_WAIT", - "SYS_SEM_WAIT_NOCANCEL", - "SYS_SEND", - "SYS_SENDFILE", - "SYS_SENDFILE64", - "SYS_SENDMMSG", - "SYS_SENDMSG", - "SYS_SENDMSG_NOCANCEL", - "SYS_SENDTO", - "SYS_SENDTO_NOCANCEL", - "SYS_SETATTRLIST", - "SYS_SETAUDIT", - "SYS_SETAUDIT_ADDR", - "SYS_SETAUID", - "SYS_SETCONTEXT", - "SYS_SETDOMAINNAME", - "SYS_SETEGID", - "SYS_SETEUID", - "SYS_SETFIB", - "SYS_SETFSGID", - "SYS_SETFSGID32", - "SYS_SETFSUID", - "SYS_SETFSUID32", - "SYS_SETGID", - "SYS_SETGID32", - "SYS_SETGROUPS", - "SYS_SETGROUPS32", - "SYS_SETHOSTNAME", - "SYS_SETITIMER", - "SYS_SETLCID", - "SYS_SETLOGIN", - "SYS_SETLOGINCLASS", - "SYS_SETNS", - "SYS_SETPGID", - "SYS_SETPRIORITY", - "SYS_SETPRIVEXEC", - "SYS_SETREGID", - "SYS_SETREGID32", - "SYS_SETRESGID", - "SYS_SETRESGID32", - "SYS_SETRESUID", - "SYS_SETRESUID32", - "SYS_SETREUID", - "SYS_SETREUID32", - "SYS_SETRLIMIT", - "SYS_SETRTABLE", - "SYS_SETSGROUPS", - "SYS_SETSID", - "SYS_SETSOCKOPT", - "SYS_SETTID", - "SYS_SETTID_WITH_PID", - "SYS_SETTIMEOFDAY", - "SYS_SETUID", - "SYS_SETUID32", - "SYS_SETWGROUPS", - "SYS_SETXATTR", - "SYS_SET_MEMPOLICY", - "SYS_SET_ROBUST_LIST", - "SYS_SET_THREAD_AREA", - "SYS_SET_TID_ADDRESS", - "SYS_SGETMASK", - "SYS_SHARED_REGION_CHECK_NP", - "SYS_SHARED_REGION_MAP_AND_SLIDE_NP", - "SYS_SHMAT", - "SYS_SHMCTL", - "SYS_SHMDT", - "SYS_SHMGET", - "SYS_SHMSYS", - "SYS_SHM_OPEN", - "SYS_SHM_UNLINK", - "SYS_SHUTDOWN", - "SYS_SIGACTION", - "SYS_SIGALTSTACK", - "SYS_SIGNAL", - "SYS_SIGNALFD", - "SYS_SIGNALFD4", - "SYS_SIGPENDING", - "SYS_SIGPROCMASK", - "SYS_SIGQUEUE", - "SYS_SIGQUEUEINFO", - "SYS_SIGRETURN", - "SYS_SIGSUSPEND", - "SYS_SIGSUSPEND_NOCANCEL", - "SYS_SIGTIMEDWAIT", - "SYS_SIGWAIT", - "SYS_SIGWAITINFO", - "SYS_SOCKET", - "SYS_SOCKETCALL", - "SYS_SOCKETPAIR", - "SYS_SPLICE", - "SYS_SSETMASK", - "SYS_SSTK", - "SYS_STACK_SNAPSHOT", - "SYS_STAT", - "SYS_STAT64", - "SYS_STAT64_EXTENDED", - "SYS_STATFS", - "SYS_STATFS64", - "SYS_STATV", - "SYS_STATVFS1", - "SYS_STAT_EXTENDED", - "SYS_STIME", - "SYS_STTY", - "SYS_SWAPCONTEXT", - "SYS_SWAPCTL", - "SYS_SWAPOFF", - "SYS_SWAPON", - "SYS_SYMLINK", - "SYS_SYMLINKAT", - "SYS_SYNC", - "SYS_SYNCFS", - "SYS_SYNC_FILE_RANGE", - "SYS_SYSARCH", - "SYS_SYSCALL", - "SYS_SYSCALL_BASE", - "SYS_SYSFS", - "SYS_SYSINFO", - "SYS_SYSLOG", - "SYS_TEE", - "SYS_TGKILL", - "SYS_THREAD_SELFID", - "SYS_THR_CREATE", - "SYS_THR_EXIT", - "SYS_THR_KILL", - "SYS_THR_KILL2", - "SYS_THR_NEW", - "SYS_THR_SELF", - "SYS_THR_SET_NAME", - "SYS_THR_SUSPEND", - "SYS_THR_WAKE", - "SYS_TIME", - "SYS_TIMERFD_CREATE", - "SYS_TIMERFD_GETTIME", - "SYS_TIMERFD_SETTIME", - "SYS_TIMER_CREATE", - "SYS_TIMER_DELETE", - "SYS_TIMER_GETOVERRUN", - "SYS_TIMER_GETTIME", - "SYS_TIMER_SETTIME", - "SYS_TIMES", - "SYS_TKILL", - "SYS_TRUNCATE", - "SYS_TRUNCATE64", - "SYS_TUXCALL", - "SYS_UGETRLIMIT", - "SYS_ULIMIT", - "SYS_UMASK", - "SYS_UMASK_EXTENDED", - "SYS_UMOUNT", - "SYS_UMOUNT2", - "SYS_UNAME", - "SYS_UNDELETE", - "SYS_UNLINK", - "SYS_UNLINKAT", - "SYS_UNMOUNT", - "SYS_UNSHARE", - "SYS_USELIB", - "SYS_USTAT", - "SYS_UTIME", - "SYS_UTIMENSAT", - "SYS_UTIMES", - "SYS_UTRACE", - "SYS_UUIDGEN", - "SYS_VADVISE", - "SYS_VFORK", - "SYS_VHANGUP", - "SYS_VM86", - "SYS_VM86OLD", - "SYS_VMSPLICE", - "SYS_VM_PRESSURE_MONITOR", - "SYS_VSERVER", - "SYS_WAIT4", - "SYS_WAIT4_NOCANCEL", - "SYS_WAIT6", - "SYS_WAITEVENT", - "SYS_WAITID", - "SYS_WAITID_NOCANCEL", - "SYS_WAITPID", - "SYS_WATCHEVENT", - "SYS_WORKQ_KERNRETURN", - "SYS_WORKQ_OPEN", - "SYS_WRITE", - "SYS_WRITEV", - "SYS_WRITEV_NOCANCEL", - "SYS_WRITE_NOCANCEL", - "SYS_YIELD", - "SYS__LLSEEK", - "SYS__LWP_CONTINUE", - "SYS__LWP_CREATE", - "SYS__LWP_CTL", - "SYS__LWP_DETACH", - "SYS__LWP_EXIT", - "SYS__LWP_GETNAME", - "SYS__LWP_GETPRIVATE", - "SYS__LWP_KILL", - "SYS__LWP_PARK", - "SYS__LWP_SELF", - "SYS__LWP_SETNAME", - "SYS__LWP_SETPRIVATE", - "SYS__LWP_SUSPEND", - "SYS__LWP_UNPARK", - "SYS__LWP_UNPARK_ALL", - "SYS__LWP_WAIT", - "SYS__LWP_WAKEUP", - "SYS__NEWSELECT", - "SYS__PSET_BIND", - "SYS__SCHED_GETAFFINITY", - "SYS__SCHED_GETPARAM", - "SYS__SCHED_SETAFFINITY", - "SYS__SCHED_SETPARAM", - "SYS__SYSCTL", - "SYS__UMTX_LOCK", - "SYS__UMTX_OP", - "SYS__UMTX_UNLOCK", - "SYS___ACL_ACLCHECK_FD", - "SYS___ACL_ACLCHECK_FILE", - "SYS___ACL_ACLCHECK_LINK", - "SYS___ACL_DELETE_FD", - "SYS___ACL_DELETE_FILE", - "SYS___ACL_DELETE_LINK", - "SYS___ACL_GET_FD", - "SYS___ACL_GET_FILE", - "SYS___ACL_GET_LINK", - "SYS___ACL_SET_FD", - "SYS___ACL_SET_FILE", - "SYS___ACL_SET_LINK", - "SYS___CAP_RIGHTS_GET", - "SYS___CLONE", - "SYS___DISABLE_THREADSIGNAL", - "SYS___GETCWD", - "SYS___GETLOGIN", - "SYS___GET_TCB", - "SYS___MAC_EXECVE", - "SYS___MAC_GETFSSTAT", - "SYS___MAC_GET_FD", - "SYS___MAC_GET_FILE", - "SYS___MAC_GET_LCID", - "SYS___MAC_GET_LCTX", - "SYS___MAC_GET_LINK", - "SYS___MAC_GET_MOUNT", - "SYS___MAC_GET_PID", - "SYS___MAC_GET_PROC", - "SYS___MAC_MOUNT", - "SYS___MAC_SET_FD", - "SYS___MAC_SET_FILE", - "SYS___MAC_SET_LCTX", - "SYS___MAC_SET_LINK", - "SYS___MAC_SET_PROC", - "SYS___MAC_SYSCALL", - "SYS___OLD_SEMWAIT_SIGNAL", - "SYS___OLD_SEMWAIT_SIGNAL_NOCANCEL", - "SYS___POSIX_CHOWN", - "SYS___POSIX_FCHOWN", - "SYS___POSIX_LCHOWN", - "SYS___POSIX_RENAME", - "SYS___PTHREAD_CANCELED", - "SYS___PTHREAD_CHDIR", - "SYS___PTHREAD_FCHDIR", - "SYS___PTHREAD_KILL", - "SYS___PTHREAD_MARKCANCEL", - "SYS___PTHREAD_SIGMASK", - "SYS___QUOTACTL", - "SYS___SEMCTL", - "SYS___SEMWAIT_SIGNAL", - "SYS___SEMWAIT_SIGNAL_NOCANCEL", - "SYS___SETLOGIN", - "SYS___SETUGID", - "SYS___SET_TCB", - "SYS___SIGACTION_SIGTRAMP", - "SYS___SIGTIMEDWAIT", - "SYS___SIGWAIT", - "SYS___SIGWAIT_NOCANCEL", - "SYS___SYSCTL", - "SYS___TFORK", - "SYS___THREXIT", - "SYS___THRSIGDIVERT", - "SYS___THRSLEEP", - "SYS___THRWAKEUP", - "S_ARCH1", - "S_ARCH2", - "S_BLKSIZE", - "S_IEXEC", - "S_IFBLK", - "S_IFCHR", - "S_IFDIR", - "S_IFIFO", - "S_IFLNK", - "S_IFMT", - "S_IFREG", - "S_IFSOCK", - "S_IFWHT", - "S_IREAD", - "S_IRGRP", - "S_IROTH", - "S_IRUSR", - "S_IRWXG", - "S_IRWXO", - "S_IRWXU", - "S_ISGID", - "S_ISTXT", - "S_ISUID", - "S_ISVTX", - "S_IWGRP", - "S_IWOTH", - "S_IWRITE", - "S_IWUSR", - "S_IXGRP", - "S_IXOTH", - "S_IXUSR", - "S_LOGIN_SET", - "SecurityAttributes", - "Seek", - "Select", - "Sendfile", - "Sendmsg", - "SendmsgN", - "Sendto", - "Servent", - "SetBpf", - "SetBpfBuflen", - "SetBpfDatalink", - "SetBpfHeadercmpl", - "SetBpfImmediate", - "SetBpfInterface", - "SetBpfPromisc", - "SetBpfTimeout", - "SetCurrentDirectory", - "SetEndOfFile", - "SetEnvironmentVariable", - "SetFileAttributes", - "SetFileCompletionNotificationModes", - "SetFilePointer", - "SetFileTime", - "SetHandleInformation", - "SetKevent", - "SetLsfPromisc", - "SetNonblock", - "Setdomainname", - "Setegid", - "Setenv", - "Seteuid", - "Setfsgid", - "Setfsuid", - "Setgid", - "Setgroups", - "Sethostname", - "Setlogin", - "Setpgid", - "Setpriority", - "Setprivexec", - "Setregid", - "Setresgid", - "Setresuid", - "Setreuid", - "Setrlimit", - "Setsid", - "Setsockopt", - "SetsockoptByte", - "SetsockoptICMPv6Filter", - "SetsockoptIPMreq", - "SetsockoptIPMreqn", - "SetsockoptIPv6Mreq", - "SetsockoptInet4Addr", - "SetsockoptInt", - "SetsockoptLinger", - "SetsockoptString", - "SetsockoptTimeval", - "Settimeofday", - "Setuid", - "Setxattr", - "Shutdown", - "SidTypeAlias", - "SidTypeComputer", - "SidTypeDeletedAccount", - "SidTypeDomain", - "SidTypeGroup", - "SidTypeInvalid", - "SidTypeLabel", - "SidTypeUnknown", - "SidTypeUser", - "SidTypeWellKnownGroup", - "Signal", - "SizeofBpfHdr", - "SizeofBpfInsn", - "SizeofBpfProgram", - "SizeofBpfStat", - "SizeofBpfVersion", - "SizeofBpfZbuf", - "SizeofBpfZbufHeader", - "SizeofCmsghdr", - "SizeofICMPv6Filter", - "SizeofIPMreq", - "SizeofIPMreqn", - "SizeofIPv6MTUInfo", - "SizeofIPv6Mreq", - "SizeofIfAddrmsg", - "SizeofIfAnnounceMsghdr", - "SizeofIfData", - "SizeofIfInfomsg", - "SizeofIfMsghdr", - "SizeofIfaMsghdr", - "SizeofIfmaMsghdr", - "SizeofIfmaMsghdr2", - "SizeofInet4Pktinfo", - "SizeofInet6Pktinfo", - "SizeofInotifyEvent", - "SizeofLinger", - "SizeofMsghdr", - "SizeofNlAttr", - "SizeofNlMsgerr", - "SizeofNlMsghdr", - "SizeofRtAttr", - "SizeofRtGenmsg", - "SizeofRtMetrics", - "SizeofRtMsg", - "SizeofRtMsghdr", - "SizeofRtNexthop", - "SizeofSockFilter", - "SizeofSockFprog", - "SizeofSockaddrAny", - "SizeofSockaddrDatalink", - "SizeofSockaddrInet4", - "SizeofSockaddrInet6", - "SizeofSockaddrLinklayer", - "SizeofSockaddrNetlink", - "SizeofSockaddrUnix", - "SizeofTCPInfo", - "SizeofUcred", - "SlicePtrFromStrings", - "SockFilter", - "SockFprog", - "Sockaddr", - "SockaddrDatalink", - "SockaddrGen", - "SockaddrInet4", - "SockaddrInet6", - "SockaddrLinklayer", - "SockaddrNetlink", - "SockaddrUnix", - "Socket", - "SocketControlMessage", - "SocketDisableIPv6", - "Socketpair", - "Splice", - "StartProcess", - "StartupInfo", - "Stat", - "Stat_t", - "Statfs", - "Statfs_t", - "Stderr", - "Stdin", - "Stdout", - "StringBytePtr", - "StringByteSlice", - "StringSlicePtr", - "StringToSid", - "StringToUTF16", - "StringToUTF16Ptr", - "Symlink", - "Sync", - "SyncFileRange", - "SysProcAttr", - "SysProcIDMap", - "Syscall", - "Syscall12", - "Syscall15", - "Syscall18", - "Syscall6", - "Syscall9", - "SyscallN", - "Sysctl", - "SysctlUint32", - "Sysctlnode", - "Sysinfo", - "Sysinfo_t", - "Systemtime", - "TCGETS", - "TCIFLUSH", - "TCIOFLUSH", - "TCOFLUSH", - "TCPInfo", - "TCPKeepalive", - "TCP_CA_NAME_MAX", - "TCP_CONGCTL", - "TCP_CONGESTION", - "TCP_CONNECTIONTIMEOUT", - "TCP_CORK", - "TCP_DEFER_ACCEPT", - "TCP_ENABLE_ECN", - "TCP_INFO", - "TCP_KEEPALIVE", - "TCP_KEEPCNT", - "TCP_KEEPIDLE", - "TCP_KEEPINIT", - "TCP_KEEPINTVL", - "TCP_LINGER2", - "TCP_MAXBURST", - "TCP_MAXHLEN", - "TCP_MAXOLEN", - "TCP_MAXSEG", - "TCP_MAXWIN", - "TCP_MAX_SACK", - "TCP_MAX_WINSHIFT", - "TCP_MD5SIG", - "TCP_MD5SIG_MAXKEYLEN", - "TCP_MINMSS", - "TCP_MINMSSOVERLOAD", - "TCP_MSS", - "TCP_NODELAY", - "TCP_NOOPT", - "TCP_NOPUSH", - "TCP_NOTSENT_LOWAT", - "TCP_NSTATES", - "TCP_QUICKACK", - "TCP_RXT_CONNDROPTIME", - "TCP_RXT_FINDROP", - "TCP_SACK_ENABLE", - "TCP_SENDMOREACKS", - "TCP_SYNCNT", - "TCP_VENDOR", - "TCP_WINDOW_CLAMP", - "TCSAFLUSH", - "TCSETS", - "TF_DISCONNECT", - "TF_REUSE_SOCKET", - "TF_USE_DEFAULT_WORKER", - "TF_USE_KERNEL_APC", - "TF_USE_SYSTEM_THREAD", - "TF_WRITE_BEHIND", - "TH32CS_INHERIT", - "TH32CS_SNAPALL", - "TH32CS_SNAPHEAPLIST", - "TH32CS_SNAPMODULE", - "TH32CS_SNAPMODULE32", - "TH32CS_SNAPPROCESS", - "TH32CS_SNAPTHREAD", - "TIME_ZONE_ID_DAYLIGHT", - "TIME_ZONE_ID_STANDARD", - "TIME_ZONE_ID_UNKNOWN", - "TIOCCBRK", - "TIOCCDTR", - "TIOCCONS", - "TIOCDCDTIMESTAMP", - "TIOCDRAIN", - "TIOCDSIMICROCODE", - "TIOCEXCL", - "TIOCEXT", - "TIOCFLAG_CDTRCTS", - "TIOCFLAG_CLOCAL", - "TIOCFLAG_CRTSCTS", - "TIOCFLAG_MDMBUF", - "TIOCFLAG_PPS", - "TIOCFLAG_SOFTCAR", - "TIOCFLUSH", - "TIOCGDEV", - "TIOCGDRAINWAIT", - "TIOCGETA", - "TIOCGETD", - "TIOCGFLAGS", - "TIOCGICOUNT", - "TIOCGLCKTRMIOS", - "TIOCGLINED", - "TIOCGPGRP", - "TIOCGPTN", - "TIOCGQSIZE", - "TIOCGRANTPT", - "TIOCGRS485", - "TIOCGSERIAL", - "TIOCGSID", - "TIOCGSIZE", - "TIOCGSOFTCAR", - "TIOCGTSTAMP", - "TIOCGWINSZ", - "TIOCINQ", - "TIOCIXOFF", - "TIOCIXON", - "TIOCLINUX", - "TIOCMBIC", - "TIOCMBIS", - "TIOCMGDTRWAIT", - "TIOCMGET", - "TIOCMIWAIT", - "TIOCMODG", - "TIOCMODS", - "TIOCMSDTRWAIT", - "TIOCMSET", - "TIOCM_CAR", - "TIOCM_CD", - "TIOCM_CTS", - "TIOCM_DCD", - "TIOCM_DSR", - "TIOCM_DTR", - "TIOCM_LE", - "TIOCM_RI", - "TIOCM_RNG", - "TIOCM_RTS", - "TIOCM_SR", - "TIOCM_ST", - "TIOCNOTTY", - "TIOCNXCL", - "TIOCOUTQ", - "TIOCPKT", - "TIOCPKT_DATA", - "TIOCPKT_DOSTOP", - "TIOCPKT_FLUSHREAD", - "TIOCPKT_FLUSHWRITE", - "TIOCPKT_IOCTL", - "TIOCPKT_NOSTOP", - "TIOCPKT_START", - "TIOCPKT_STOP", - "TIOCPTMASTER", - "TIOCPTMGET", - "TIOCPTSNAME", - "TIOCPTYGNAME", - "TIOCPTYGRANT", - "TIOCPTYUNLK", - "TIOCRCVFRAME", - "TIOCREMOTE", - "TIOCSBRK", - "TIOCSCONS", - "TIOCSCTTY", - "TIOCSDRAINWAIT", - "TIOCSDTR", - "TIOCSERCONFIG", - "TIOCSERGETLSR", - "TIOCSERGETMULTI", - "TIOCSERGSTRUCT", - "TIOCSERGWILD", - "TIOCSERSETMULTI", - "TIOCSERSWILD", - "TIOCSER_TEMT", - "TIOCSETA", - "TIOCSETAF", - "TIOCSETAW", - "TIOCSETD", - "TIOCSFLAGS", - "TIOCSIG", - "TIOCSLCKTRMIOS", - "TIOCSLINED", - "TIOCSPGRP", - "TIOCSPTLCK", - "TIOCSQSIZE", - "TIOCSRS485", - "TIOCSSERIAL", - "TIOCSSIZE", - "TIOCSSOFTCAR", - "TIOCSTART", - "TIOCSTAT", - "TIOCSTI", - "TIOCSTOP", - "TIOCSTSTAMP", - "TIOCSWINSZ", - "TIOCTIMESTAMP", - "TIOCUCNTL", - "TIOCVHANGUP", - "TIOCXMTFRAME", - "TOKEN_ADJUST_DEFAULT", - "TOKEN_ADJUST_GROUPS", - "TOKEN_ADJUST_PRIVILEGES", - "TOKEN_ADJUST_SESSIONID", - "TOKEN_ALL_ACCESS", - "TOKEN_ASSIGN_PRIMARY", - "TOKEN_DUPLICATE", - "TOKEN_EXECUTE", - "TOKEN_IMPERSONATE", - "TOKEN_QUERY", - "TOKEN_QUERY_SOURCE", - "TOKEN_READ", - "TOKEN_WRITE", - "TOSTOP", - "TRUNCATE_EXISTING", - "TUNATTACHFILTER", - "TUNDETACHFILTER", - "TUNGETFEATURES", - "TUNGETIFF", - "TUNGETSNDBUF", - "TUNGETVNETHDRSZ", - "TUNSETDEBUG", - "TUNSETGROUP", - "TUNSETIFF", - "TUNSETLINK", - "TUNSETNOCSUM", - "TUNSETOFFLOAD", - "TUNSETOWNER", - "TUNSETPERSIST", - "TUNSETSNDBUF", - "TUNSETTXFILTER", - "TUNSETVNETHDRSZ", - "Tee", - "TerminateProcess", - "Termios", - "Tgkill", - "Time", - "Time_t", - "Times", - "Timespec", - "TimespecToNsec", - "Timeval", - "Timeval32", - "TimevalToNsec", - "Timex", - "Timezoneinformation", - "Tms", - "Token", - "TokenAccessInformation", - "TokenAuditPolicy", - "TokenDefaultDacl", - "TokenElevation", - "TokenElevationType", - "TokenGroups", - "TokenGroupsAndPrivileges", - "TokenHasRestrictions", - "TokenImpersonationLevel", - "TokenIntegrityLevel", - "TokenLinkedToken", - "TokenLogonSid", - "TokenMandatoryPolicy", - "TokenOrigin", - "TokenOwner", - "TokenPrimaryGroup", - "TokenPrivileges", - "TokenRestrictedSids", - "TokenSandBoxInert", - "TokenSessionId", - "TokenSessionReference", - "TokenSource", - "TokenStatistics", - "TokenType", - "TokenUIAccess", - "TokenUser", - "TokenVirtualizationAllowed", - "TokenVirtualizationEnabled", - "Tokenprimarygroup", - "Tokenuser", - "TranslateAccountName", - "TranslateName", - "TransmitFile", - "TransmitFileBuffers", - "Truncate", - "UNIX_PATH_MAX", - "USAGE_MATCH_TYPE_AND", - "USAGE_MATCH_TYPE_OR", - "UTF16FromString", - "UTF16PtrFromString", - "UTF16ToString", - "Ucred", - "Umask", - "Uname", - "Undelete", - "UnixCredentials", - "UnixRights", - "Unlink", - "Unlinkat", - "UnmapViewOfFile", - "Unmount", - "Unsetenv", - "Unshare", - "UserInfo10", - "Ustat", - "Ustat_t", - "Utimbuf", - "Utime", - "Utimes", - "UtimesNano", - "Utsname", - "VDISCARD", - "VDSUSP", - "VEOF", - "VEOL", - "VEOL2", - "VERASE", - "VERASE2", - "VINTR", - "VKILL", - "VLNEXT", - "VMIN", - "VQUIT", - "VREPRINT", - "VSTART", - "VSTATUS", - "VSTOP", - "VSUSP", - "VSWTC", - "VT0", - "VT1", - "VTDLY", - "VTIME", - "VWERASE", - "VirtualLock", - "VirtualUnlock", - "WAIT_ABANDONED", - "WAIT_FAILED", - "WAIT_OBJECT_0", - "WAIT_TIMEOUT", - "WALL", - "WALLSIG", - "WALTSIG", - "WCLONE", - "WCONTINUED", - "WCOREFLAG", - "WEXITED", - "WLINUXCLONE", - "WNOHANG", - "WNOTHREAD", - "WNOWAIT", - "WNOZOMBIE", - "WOPTSCHECKED", - "WORDSIZE", - "WSABuf", - "WSACleanup", - "WSADESCRIPTION_LEN", - "WSAData", - "WSAEACCES", - "WSAECONNABORTED", - "WSAECONNRESET", - "WSAEnumProtocols", - "WSAID_CONNECTEX", - "WSAIoctl", - "WSAPROTOCOL_LEN", - "WSAProtocolChain", - "WSAProtocolInfo", - "WSARecv", - "WSARecvFrom", - "WSASYS_STATUS_LEN", - "WSASend", - "WSASendTo", - "WSASendto", - "WSAStartup", - "WSTOPPED", - "WTRAPPED", - "WUNTRACED", - "Wait4", - "WaitForSingleObject", - "WaitStatus", - "Win32FileAttributeData", - "Win32finddata", - "Write", - "WriteConsole", - "WriteFile", - "X509_ASN_ENCODING", - "XCASE", - "XP1_CONNECTIONLESS", - "XP1_CONNECT_DATA", - "XP1_DISCONNECT_DATA", - "XP1_EXPEDITED_DATA", - "XP1_GRACEFUL_CLOSE", - "XP1_GUARANTEED_DELIVERY", - "XP1_GUARANTEED_ORDER", - "XP1_IFS_HANDLES", - "XP1_MESSAGE_ORIENTED", - "XP1_MULTIPOINT_CONTROL_PLANE", - "XP1_MULTIPOINT_DATA_PLANE", - "XP1_PARTIAL_MESSAGE", - "XP1_PSEUDO_STREAM", - "XP1_QOS_SUPPORTED", - "XP1_SAN_SUPPORT_SDP", - "XP1_SUPPORT_BROADCAST", - "XP1_SUPPORT_MULTIPOINT", - "XP1_UNI_RECV", - "XP1_UNI_SEND", - }, - "syscall/js": { - "CopyBytesToGo", - "CopyBytesToJS", - "Error", - "Func", - "FuncOf", - "Global", - "Null", - "Type", - "TypeBoolean", - "TypeFunction", - "TypeNull", - "TypeNumber", - "TypeObject", - "TypeString", - "TypeSymbol", - "TypeUndefined", - "Undefined", - "Value", - "ValueError", - "ValueOf", - }, - "testing": { - "AllocsPerRun", - "B", - "Benchmark", - "BenchmarkResult", - "Cover", - "CoverBlock", - "CoverMode", - "Coverage", - "F", - "Init", - "InternalBenchmark", - "InternalExample", - "InternalFuzzTarget", - "InternalTest", - "M", - "Main", - "MainStart", - "PB", - "RegisterCover", - "RunBenchmarks", - "RunExamples", - "RunTests", - "Short", - "T", - "TB", - "Testing", - "Verbose", - }, - "testing/fstest": { - "MapFS", - "MapFile", - "TestFS", - }, - "testing/iotest": { - "DataErrReader", - "ErrReader", - "ErrTimeout", - "HalfReader", - "NewReadLogger", - "NewWriteLogger", - "OneByteReader", - "TestReader", - "TimeoutReader", - "TruncateWriter", - }, - "testing/quick": { - "Check", - "CheckEqual", - "CheckEqualError", - "CheckError", - "Config", - "Generator", - "SetupError", - "Value", - }, - "testing/slogtest": { - "Run", - "TestHandler", - }, - "text/scanner": { - "Char", - "Comment", - "EOF", - "Float", - "GoTokens", - "GoWhitespace", - "Ident", - "Int", - "Position", - "RawString", - "ScanChars", - "ScanComments", - "ScanFloats", - "ScanIdents", - "ScanInts", - "ScanRawStrings", - "ScanStrings", - "Scanner", - "SkipComments", - "String", - "TokenString", - }, - "text/tabwriter": { - "AlignRight", - "Debug", - "DiscardEmptyColumns", - "Escape", - "FilterHTML", - "NewWriter", - "StripEscape", - "TabIndent", - "Writer", - }, - "text/template": { - "ExecError", - "FuncMap", - "HTMLEscape", - "HTMLEscapeString", - "HTMLEscaper", - "IsTrue", - "JSEscape", - "JSEscapeString", - "JSEscaper", - "Must", - "New", - "ParseFS", - "ParseFiles", - "ParseGlob", - "Template", - "URLQueryEscaper", - }, - "text/template/parse": { - "ActionNode", - "BoolNode", - "BranchNode", - "BreakNode", - "ChainNode", - "CommandNode", - "CommentNode", - "ContinueNode", - "DotNode", - "FieldNode", - "IdentifierNode", - "IfNode", - "IsEmptyTree", - "ListNode", - "Mode", - "New", - "NewIdentifier", - "NilNode", - "Node", - "NodeAction", - "NodeBool", - "NodeBreak", - "NodeChain", - "NodeCommand", - "NodeComment", - "NodeContinue", - "NodeDot", - "NodeField", - "NodeIdentifier", - "NodeIf", - "NodeList", - "NodeNil", - "NodeNumber", - "NodePipe", - "NodeRange", - "NodeString", - "NodeTemplate", - "NodeText", - "NodeType", - "NodeVariable", - "NodeWith", - "NumberNode", - "Parse", - "ParseComments", - "PipeNode", - "Pos", - "RangeNode", - "SkipFuncCheck", - "StringNode", - "TemplateNode", - "TextNode", - "Tree", - "VariableNode", - "WithNode", - }, - "time": { - "ANSIC", - "After", - "AfterFunc", - "April", - "August", - "Date", - "DateOnly", - "DateTime", - "December", - "Duration", - "February", - "FixedZone", - "Friday", - "Hour", - "January", - "July", - "June", - "Kitchen", - "Layout", - "LoadLocation", - "LoadLocationFromTZData", - "Local", - "Location", - "March", - "May", - "Microsecond", - "Millisecond", - "Minute", - "Monday", - "Month", - "Nanosecond", - "NewTicker", - "NewTimer", - "November", - "Now", - "October", - "Parse", - "ParseDuration", - "ParseError", - "ParseInLocation", - "RFC1123", - "RFC1123Z", - "RFC3339", - "RFC3339Nano", - "RFC822", - "RFC822Z", - "RFC850", - "RubyDate", - "Saturday", - "Second", - "September", - "Since", - "Sleep", - "Stamp", - "StampMicro", - "StampMilli", - "StampNano", - "Sunday", - "Thursday", - "Tick", - "Ticker", - "Time", - "TimeOnly", - "Timer", - "Tuesday", - "UTC", - "Unix", - "UnixDate", - "UnixMicro", - "UnixMilli", - "Until", - "Wednesday", - "Weekday", - }, - "unicode": { - "ASCII_Hex_Digit", - "Adlam", - "Ahom", - "Anatolian_Hieroglyphs", - "Arabic", - "Armenian", - "Avestan", - "AzeriCase", - "Balinese", - "Bamum", - "Bassa_Vah", - "Batak", - "Bengali", - "Bhaiksuki", - "Bidi_Control", - "Bopomofo", - "Brahmi", - "Braille", - "Buginese", - "Buhid", - "C", - "Canadian_Aboriginal", - "Carian", - "CaseRange", - "CaseRanges", - "Categories", - "Caucasian_Albanian", - "Cc", - "Cf", - "Chakma", - "Cham", - "Cherokee", - "Chorasmian", - "Co", - "Common", - "Coptic", - "Cs", - "Cuneiform", - "Cypriot", - "Cypro_Minoan", - "Cyrillic", - "Dash", - "Deprecated", - "Deseret", - "Devanagari", - "Diacritic", - "Digit", - "Dives_Akuru", - "Dogra", - "Duployan", - "Egyptian_Hieroglyphs", - "Elbasan", - "Elymaic", - "Ethiopic", - "Extender", - "FoldCategory", - "FoldScript", - "Georgian", - "Glagolitic", - "Gothic", - "Grantha", - "GraphicRanges", - "Greek", - "Gujarati", - "Gunjala_Gondi", - "Gurmukhi", - "Han", - "Hangul", - "Hanifi_Rohingya", - "Hanunoo", - "Hatran", - "Hebrew", - "Hex_Digit", - "Hiragana", - "Hyphen", - "IDS_Binary_Operator", - "IDS_Trinary_Operator", - "Ideographic", - "Imperial_Aramaic", - "In", - "Inherited", - "Inscriptional_Pahlavi", - "Inscriptional_Parthian", - "Is", - "IsControl", - "IsDigit", - "IsGraphic", - "IsLetter", - "IsLower", - "IsMark", - "IsNumber", - "IsOneOf", - "IsPrint", - "IsPunct", - "IsSpace", - "IsSymbol", - "IsTitle", - "IsUpper", - "Javanese", - "Join_Control", - "Kaithi", - "Kannada", - "Katakana", - "Kawi", - "Kayah_Li", - "Kharoshthi", - "Khitan_Small_Script", - "Khmer", - "Khojki", - "Khudawadi", - "L", - "Lao", - "Latin", - "Lepcha", - "Letter", - "Limbu", - "Linear_A", - "Linear_B", - "Lisu", - "Ll", - "Lm", - "Lo", - "Logical_Order_Exception", - "Lower", - "LowerCase", - "Lt", - "Lu", - "Lycian", - "Lydian", - "M", - "Mahajani", - "Makasar", - "Malayalam", - "Mandaic", - "Manichaean", - "Marchen", - "Mark", - "Masaram_Gondi", - "MaxASCII", - "MaxCase", - "MaxLatin1", - "MaxRune", - "Mc", - "Me", - "Medefaidrin", - "Meetei_Mayek", - "Mende_Kikakui", - "Meroitic_Cursive", - "Meroitic_Hieroglyphs", - "Miao", - "Mn", - "Modi", - "Mongolian", - "Mro", - "Multani", - "Myanmar", - "N", - "Nabataean", - "Nag_Mundari", - "Nandinagari", - "Nd", - "New_Tai_Lue", - "Newa", - "Nko", - "Nl", - "No", - "Noncharacter_Code_Point", - "Number", - "Nushu", - "Nyiakeng_Puachue_Hmong", - "Ogham", - "Ol_Chiki", - "Old_Hungarian", - "Old_Italic", - "Old_North_Arabian", - "Old_Permic", - "Old_Persian", - "Old_Sogdian", - "Old_South_Arabian", - "Old_Turkic", - "Old_Uyghur", - "Oriya", - "Osage", - "Osmanya", - "Other", - "Other_Alphabetic", - "Other_Default_Ignorable_Code_Point", - "Other_Grapheme_Extend", - "Other_ID_Continue", - "Other_ID_Start", - "Other_Lowercase", - "Other_Math", - "Other_Uppercase", - "P", - "Pahawh_Hmong", - "Palmyrene", - "Pattern_Syntax", - "Pattern_White_Space", - "Pau_Cin_Hau", - "Pc", - "Pd", - "Pe", - "Pf", - "Phags_Pa", - "Phoenician", - "Pi", - "Po", - "Prepended_Concatenation_Mark", - "PrintRanges", - "Properties", - "Ps", - "Psalter_Pahlavi", - "Punct", - "Quotation_Mark", - "Radical", - "Range16", - "Range32", - "RangeTable", - "Regional_Indicator", - "Rejang", - "ReplacementChar", - "Runic", - "S", - "STerm", - "Samaritan", - "Saurashtra", - "Sc", - "Scripts", - "Sentence_Terminal", - "Sharada", - "Shavian", - "Siddham", - "SignWriting", - "SimpleFold", - "Sinhala", - "Sk", - "Sm", - "So", - "Soft_Dotted", - "Sogdian", - "Sora_Sompeng", - "Soyombo", - "Space", - "SpecialCase", - "Sundanese", - "Syloti_Nagri", - "Symbol", - "Syriac", - "Tagalog", - "Tagbanwa", - "Tai_Le", - "Tai_Tham", - "Tai_Viet", - "Takri", - "Tamil", - "Tangsa", - "Tangut", - "Telugu", - "Terminal_Punctuation", - "Thaana", - "Thai", - "Tibetan", - "Tifinagh", - "Tirhuta", - "Title", - "TitleCase", - "To", - "ToLower", - "ToTitle", - "ToUpper", - "Toto", - "TurkishCase", - "Ugaritic", - "Unified_Ideograph", - "Upper", - "UpperCase", - "UpperLower", - "Vai", - "Variation_Selector", - "Version", - "Vithkuqi", - "Wancho", - "Warang_Citi", - "White_Space", - "Yezidi", - "Yi", - "Z", - "Zanabazar_Square", - "Zl", - "Zp", - "Zs", - }, - "unicode/utf16": { - "AppendRune", - "Decode", - "DecodeRune", - "Encode", - "EncodeRune", - "IsSurrogate", - }, - "unicode/utf8": { - "AppendRune", - "DecodeLastRune", - "DecodeLastRuneInString", - "DecodeRune", - "DecodeRuneInString", - "EncodeRune", - "FullRune", - "FullRuneInString", - "MaxRune", - "RuneCount", - "RuneCountInString", - "RuneError", - "RuneLen", - "RuneSelf", - "RuneStart", - "UTFMax", - "Valid", - "ValidRune", - "ValidString", - }, - "unsafe": { - "Add", - "Alignof", - "Offsetof", - "Pointer", - "Sizeof", - "Slice", - "SliceData", - "String", - "StringData", - }, -} diff --git a/vendor/golang.org/x/tools/internal/stdlib/manifest.go b/vendor/golang.org/x/tools/internal/stdlib/manifest.go new file mode 100644 index 000000000000..fd6892075ee4 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/stdlib/manifest.go @@ -0,0 +1,17320 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Code generated by generate.go. DO NOT EDIT. + +package stdlib + +var PackageSymbols = map[string][]Symbol{ + "archive/tar": { + {"(*Header).FileInfo", Method, 1}, + {"(*Reader).Next", Method, 0}, + {"(*Reader).Read", Method, 0}, + {"(*Writer).AddFS", Method, 22}, + {"(*Writer).Close", Method, 0}, + {"(*Writer).Flush", Method, 0}, + {"(*Writer).Write", Method, 0}, + {"(*Writer).WriteHeader", Method, 0}, + {"(Format).String", Method, 10}, + {"ErrFieldTooLong", Var, 0}, + {"ErrHeader", Var, 0}, + {"ErrInsecurePath", Var, 20}, + {"ErrWriteAfterClose", Var, 0}, + {"ErrWriteTooLong", Var, 0}, + {"FileInfoHeader", Func, 1}, + {"Format", Type, 10}, + {"FormatGNU", Const, 10}, + {"FormatPAX", Const, 10}, + {"FormatUSTAR", Const, 10}, + {"FormatUnknown", Const, 10}, + {"Header", Type, 0}, + {"Header.AccessTime", Field, 0}, + {"Header.ChangeTime", Field, 0}, + {"Header.Devmajor", Field, 0}, + {"Header.Devminor", Field, 0}, + {"Header.Format", Field, 10}, + {"Header.Gid", Field, 0}, + {"Header.Gname", Field, 0}, + {"Header.Linkname", Field, 0}, + {"Header.ModTime", Field, 0}, + {"Header.Mode", Field, 0}, + {"Header.Name", Field, 0}, + {"Header.PAXRecords", Field, 10}, + {"Header.Size", Field, 0}, + {"Header.Typeflag", Field, 0}, + {"Header.Uid", Field, 0}, + {"Header.Uname", Field, 0}, + {"Header.Xattrs", Field, 3}, + {"NewReader", Func, 0}, + {"NewWriter", Func, 0}, + {"Reader", Type, 0}, + {"TypeBlock", Const, 0}, + {"TypeChar", Const, 0}, + {"TypeCont", Const, 0}, + {"TypeDir", Const, 0}, + {"TypeFifo", Const, 0}, + {"TypeGNULongLink", Const, 1}, + {"TypeGNULongName", Const, 1}, + {"TypeGNUSparse", Const, 3}, + {"TypeLink", Const, 0}, + {"TypeReg", Const, 0}, + {"TypeRegA", Const, 0}, + {"TypeSymlink", Const, 0}, + {"TypeXGlobalHeader", Const, 0}, + {"TypeXHeader", Const, 0}, + {"Writer", Type, 0}, + }, + "archive/zip": { + {"(*File).DataOffset", Method, 2}, + {"(*File).FileInfo", Method, 0}, + {"(*File).ModTime", Method, 0}, + {"(*File).Mode", Method, 0}, + {"(*File).Open", Method, 0}, + {"(*File).OpenRaw", Method, 17}, + {"(*File).SetModTime", Method, 0}, + {"(*File).SetMode", Method, 0}, + {"(*FileHeader).FileInfo", Method, 0}, + {"(*FileHeader).ModTime", Method, 0}, + {"(*FileHeader).Mode", Method, 0}, + {"(*FileHeader).SetModTime", Method, 0}, + {"(*FileHeader).SetMode", Method, 0}, + {"(*ReadCloser).Close", Method, 0}, + {"(*ReadCloser).Open", Method, 16}, + {"(*ReadCloser).RegisterDecompressor", Method, 6}, + {"(*Reader).Open", Method, 16}, + {"(*Reader).RegisterDecompressor", Method, 6}, + {"(*Writer).AddFS", Method, 22}, + {"(*Writer).Close", Method, 0}, + {"(*Writer).Copy", Method, 17}, + {"(*Writer).Create", Method, 0}, + {"(*Writer).CreateHeader", Method, 0}, + {"(*Writer).CreateRaw", Method, 17}, + {"(*Writer).Flush", Method, 4}, + {"(*Writer).RegisterCompressor", Method, 6}, + {"(*Writer).SetComment", Method, 10}, + {"(*Writer).SetOffset", Method, 5}, + {"Compressor", Type, 2}, + {"Decompressor", Type, 2}, + {"Deflate", Const, 0}, + {"ErrAlgorithm", Var, 0}, + {"ErrChecksum", Var, 0}, + {"ErrFormat", Var, 0}, + {"ErrInsecurePath", Var, 20}, + {"File", Type, 0}, + {"File.FileHeader", Field, 0}, + {"FileHeader", Type, 0}, + {"FileHeader.CRC32", Field, 0}, + {"FileHeader.Comment", Field, 0}, + {"FileHeader.CompressedSize", Field, 0}, + {"FileHeader.CompressedSize64", Field, 1}, + {"FileHeader.CreatorVersion", Field, 0}, + {"FileHeader.ExternalAttrs", Field, 0}, + {"FileHeader.Extra", Field, 0}, + {"FileHeader.Flags", Field, 0}, + {"FileHeader.Method", Field, 0}, + {"FileHeader.Modified", Field, 10}, + {"FileHeader.ModifiedDate", Field, 0}, + {"FileHeader.ModifiedTime", Field, 0}, + {"FileHeader.Name", Field, 0}, + {"FileHeader.NonUTF8", Field, 10}, + {"FileHeader.ReaderVersion", Field, 0}, + {"FileHeader.UncompressedSize", Field, 0}, + {"FileHeader.UncompressedSize64", Field, 1}, + {"FileInfoHeader", Func, 0}, + {"NewReader", Func, 0}, + {"NewWriter", Func, 0}, + {"OpenReader", Func, 0}, + {"ReadCloser", Type, 0}, + {"ReadCloser.Reader", Field, 0}, + {"Reader", Type, 0}, + {"Reader.Comment", Field, 0}, + {"Reader.File", Field, 0}, + {"RegisterCompressor", Func, 2}, + {"RegisterDecompressor", Func, 2}, + {"Store", Const, 0}, + {"Writer", Type, 0}, + }, + "bufio": { + {"(*Reader).Buffered", Method, 0}, + {"(*Reader).Discard", Method, 5}, + {"(*Reader).Peek", Method, 0}, + {"(*Reader).Read", Method, 0}, + {"(*Reader).ReadByte", Method, 0}, + {"(*Reader).ReadBytes", Method, 0}, + {"(*Reader).ReadLine", Method, 0}, + {"(*Reader).ReadRune", Method, 0}, + {"(*Reader).ReadSlice", Method, 0}, + {"(*Reader).ReadString", Method, 0}, + {"(*Reader).Reset", Method, 2}, + {"(*Reader).Size", Method, 10}, + {"(*Reader).UnreadByte", Method, 0}, + {"(*Reader).UnreadRune", Method, 0}, + {"(*Reader).WriteTo", Method, 1}, + {"(*Scanner).Buffer", Method, 6}, + {"(*Scanner).Bytes", Method, 1}, + {"(*Scanner).Err", Method, 1}, + {"(*Scanner).Scan", Method, 1}, + {"(*Scanner).Split", Method, 1}, + {"(*Scanner).Text", Method, 1}, + {"(*Writer).Available", Method, 0}, + {"(*Writer).AvailableBuffer", Method, 18}, + {"(*Writer).Buffered", Method, 0}, + {"(*Writer).Flush", Method, 0}, + {"(*Writer).ReadFrom", Method, 1}, + {"(*Writer).Reset", Method, 2}, + {"(*Writer).Size", Method, 10}, + {"(*Writer).Write", Method, 0}, + {"(*Writer).WriteByte", Method, 0}, + {"(*Writer).WriteRune", Method, 0}, + {"(*Writer).WriteString", Method, 0}, + {"(ReadWriter).Available", Method, 0}, + {"(ReadWriter).AvailableBuffer", Method, 18}, + {"(ReadWriter).Discard", Method, 5}, + {"(ReadWriter).Flush", Method, 0}, + {"(ReadWriter).Peek", Method, 0}, + {"(ReadWriter).Read", Method, 0}, + {"(ReadWriter).ReadByte", Method, 0}, + {"(ReadWriter).ReadBytes", Method, 0}, + {"(ReadWriter).ReadFrom", Method, 1}, + {"(ReadWriter).ReadLine", Method, 0}, + {"(ReadWriter).ReadRune", Method, 0}, + {"(ReadWriter).ReadSlice", Method, 0}, + {"(ReadWriter).ReadString", Method, 0}, + {"(ReadWriter).UnreadByte", Method, 0}, + {"(ReadWriter).UnreadRune", Method, 0}, + {"(ReadWriter).Write", Method, 0}, + {"(ReadWriter).WriteByte", Method, 0}, + {"(ReadWriter).WriteRune", Method, 0}, + {"(ReadWriter).WriteString", Method, 0}, + {"(ReadWriter).WriteTo", Method, 1}, + {"ErrAdvanceTooFar", Var, 1}, + {"ErrBadReadCount", Var, 15}, + {"ErrBufferFull", Var, 0}, + {"ErrFinalToken", Var, 6}, + {"ErrInvalidUnreadByte", Var, 0}, + {"ErrInvalidUnreadRune", Var, 0}, + {"ErrNegativeAdvance", Var, 1}, + {"ErrNegativeCount", Var, 0}, + {"ErrTooLong", Var, 1}, + {"MaxScanTokenSize", Const, 1}, + {"NewReadWriter", Func, 0}, + {"NewReader", Func, 0}, + {"NewReaderSize", Func, 0}, + {"NewScanner", Func, 1}, + {"NewWriter", Func, 0}, + {"NewWriterSize", Func, 0}, + {"ReadWriter", Type, 0}, + {"ReadWriter.Reader", Field, 0}, + {"ReadWriter.Writer", Field, 0}, + {"Reader", Type, 0}, + {"ScanBytes", Func, 1}, + {"ScanLines", Func, 1}, + {"ScanRunes", Func, 1}, + {"ScanWords", Func, 1}, + {"Scanner", Type, 1}, + {"SplitFunc", Type, 1}, + {"Writer", Type, 0}, + }, + "bytes": { + {"(*Buffer).Available", Method, 21}, + {"(*Buffer).AvailableBuffer", Method, 21}, + {"(*Buffer).Bytes", Method, 0}, + {"(*Buffer).Cap", Method, 5}, + {"(*Buffer).Grow", Method, 1}, + {"(*Buffer).Len", Method, 0}, + {"(*Buffer).Next", Method, 0}, + {"(*Buffer).Read", Method, 0}, + {"(*Buffer).ReadByte", Method, 0}, + {"(*Buffer).ReadBytes", Method, 0}, + {"(*Buffer).ReadFrom", Method, 0}, + {"(*Buffer).ReadRune", Method, 0}, + {"(*Buffer).ReadString", Method, 0}, + {"(*Buffer).Reset", Method, 0}, + {"(*Buffer).String", Method, 0}, + {"(*Buffer).Truncate", Method, 0}, + {"(*Buffer).UnreadByte", Method, 0}, + {"(*Buffer).UnreadRune", Method, 0}, + {"(*Buffer).Write", Method, 0}, + {"(*Buffer).WriteByte", Method, 0}, + {"(*Buffer).WriteRune", Method, 0}, + {"(*Buffer).WriteString", Method, 0}, + {"(*Buffer).WriteTo", Method, 0}, + {"(*Reader).Len", Method, 0}, + {"(*Reader).Read", Method, 0}, + {"(*Reader).ReadAt", Method, 0}, + {"(*Reader).ReadByte", Method, 0}, + {"(*Reader).ReadRune", Method, 0}, + {"(*Reader).Reset", Method, 7}, + {"(*Reader).Seek", Method, 0}, + {"(*Reader).Size", Method, 5}, + {"(*Reader).UnreadByte", Method, 0}, + {"(*Reader).UnreadRune", Method, 0}, + {"(*Reader).WriteTo", Method, 1}, + {"Buffer", Type, 0}, + {"Clone", Func, 20}, + {"Compare", Func, 0}, + {"Contains", Func, 0}, + {"ContainsAny", Func, 7}, + {"ContainsFunc", Func, 21}, + {"ContainsRune", Func, 7}, + {"Count", Func, 0}, + {"Cut", Func, 18}, + {"CutPrefix", Func, 20}, + {"CutSuffix", Func, 20}, + {"Equal", Func, 0}, + {"EqualFold", Func, 0}, + {"ErrTooLarge", Var, 0}, + {"Fields", Func, 0}, + {"FieldsFunc", Func, 0}, + {"HasPrefix", Func, 0}, + {"HasSuffix", Func, 0}, + {"Index", Func, 0}, + {"IndexAny", Func, 0}, + {"IndexByte", Func, 0}, + {"IndexFunc", Func, 0}, + {"IndexRune", Func, 0}, + {"Join", Func, 0}, + {"LastIndex", Func, 0}, + {"LastIndexAny", Func, 0}, + {"LastIndexByte", Func, 5}, + {"LastIndexFunc", Func, 0}, + {"Map", Func, 0}, + {"MinRead", Const, 0}, + {"NewBuffer", Func, 0}, + {"NewBufferString", Func, 0}, + {"NewReader", Func, 0}, + {"Reader", Type, 0}, + {"Repeat", Func, 0}, + {"Replace", Func, 0}, + {"ReplaceAll", Func, 12}, + {"Runes", Func, 0}, + {"Split", Func, 0}, + {"SplitAfter", Func, 0}, + {"SplitAfterN", Func, 0}, + {"SplitN", Func, 0}, + {"Title", Func, 0}, + {"ToLower", Func, 0}, + {"ToLowerSpecial", Func, 0}, + {"ToTitle", Func, 0}, + {"ToTitleSpecial", Func, 0}, + {"ToUpper", Func, 0}, + {"ToUpperSpecial", Func, 0}, + {"ToValidUTF8", Func, 13}, + {"Trim", Func, 0}, + {"TrimFunc", Func, 0}, + {"TrimLeft", Func, 0}, + {"TrimLeftFunc", Func, 0}, + {"TrimPrefix", Func, 1}, + {"TrimRight", Func, 0}, + {"TrimRightFunc", Func, 0}, + {"TrimSpace", Func, 0}, + {"TrimSuffix", Func, 1}, + }, + "cmp": { + {"Compare", Func, 21}, + {"Less", Func, 21}, + {"Or", Func, 22}, + {"Ordered", Type, 21}, + }, + "compress/bzip2": { + {"(StructuralError).Error", Method, 0}, + {"NewReader", Func, 0}, + {"StructuralError", Type, 0}, + }, + "compress/flate": { + {"(*ReadError).Error", Method, 0}, + {"(*WriteError).Error", Method, 0}, + {"(*Writer).Close", Method, 0}, + {"(*Writer).Flush", Method, 0}, + {"(*Writer).Reset", Method, 2}, + {"(*Writer).Write", Method, 0}, + {"(CorruptInputError).Error", Method, 0}, + {"(InternalError).Error", Method, 0}, + {"BestCompression", Const, 0}, + {"BestSpeed", Const, 0}, + {"CorruptInputError", Type, 0}, + {"DefaultCompression", Const, 0}, + {"HuffmanOnly", Const, 7}, + {"InternalError", Type, 0}, + {"NewReader", Func, 0}, + {"NewReaderDict", Func, 0}, + {"NewWriter", Func, 0}, + {"NewWriterDict", Func, 0}, + {"NoCompression", Const, 0}, + {"ReadError", Type, 0}, + {"ReadError.Err", Field, 0}, + {"ReadError.Offset", Field, 0}, + {"Reader", Type, 0}, + {"Resetter", Type, 4}, + {"WriteError", Type, 0}, + {"WriteError.Err", Field, 0}, + {"WriteError.Offset", Field, 0}, + {"Writer", Type, 0}, + }, + "compress/gzip": { + {"(*Reader).Close", Method, 0}, + {"(*Reader).Multistream", Method, 4}, + {"(*Reader).Read", Method, 0}, + {"(*Reader).Reset", Method, 3}, + {"(*Writer).Close", Method, 0}, + {"(*Writer).Flush", Method, 1}, + {"(*Writer).Reset", Method, 2}, + {"(*Writer).Write", Method, 0}, + {"BestCompression", Const, 0}, + {"BestSpeed", Const, 0}, + {"DefaultCompression", Const, 0}, + {"ErrChecksum", Var, 0}, + {"ErrHeader", Var, 0}, + {"Header", Type, 0}, + {"Header.Comment", Field, 0}, + {"Header.Extra", Field, 0}, + {"Header.ModTime", Field, 0}, + {"Header.Name", Field, 0}, + {"Header.OS", Field, 0}, + {"HuffmanOnly", Const, 8}, + {"NewReader", Func, 0}, + {"NewWriter", Func, 0}, + {"NewWriterLevel", Func, 0}, + {"NoCompression", Const, 0}, + {"Reader", Type, 0}, + {"Reader.Header", Field, 0}, + {"Writer", Type, 0}, + {"Writer.Header", Field, 0}, + }, + "compress/lzw": { + {"(*Reader).Close", Method, 17}, + {"(*Reader).Read", Method, 17}, + {"(*Reader).Reset", Method, 17}, + {"(*Writer).Close", Method, 17}, + {"(*Writer).Reset", Method, 17}, + {"(*Writer).Write", Method, 17}, + {"LSB", Const, 0}, + {"MSB", Const, 0}, + {"NewReader", Func, 0}, + {"NewWriter", Func, 0}, + {"Order", Type, 0}, + {"Reader", Type, 17}, + {"Writer", Type, 17}, + }, + "compress/zlib": { + {"(*Writer).Close", Method, 0}, + {"(*Writer).Flush", Method, 0}, + {"(*Writer).Reset", Method, 2}, + {"(*Writer).Write", Method, 0}, + {"BestCompression", Const, 0}, + {"BestSpeed", Const, 0}, + {"DefaultCompression", Const, 0}, + {"ErrChecksum", Var, 0}, + {"ErrDictionary", Var, 0}, + {"ErrHeader", Var, 0}, + {"HuffmanOnly", Const, 8}, + {"NewReader", Func, 0}, + {"NewReaderDict", Func, 0}, + {"NewWriter", Func, 0}, + {"NewWriterLevel", Func, 0}, + {"NewWriterLevelDict", Func, 0}, + {"NoCompression", Const, 0}, + {"Resetter", Type, 4}, + {"Writer", Type, 0}, + }, + "container/heap": { + {"Fix", Func, 2}, + {"Init", Func, 0}, + {"Interface", Type, 0}, + {"Pop", Func, 0}, + {"Push", Func, 0}, + {"Remove", Func, 0}, + }, + "container/list": { + {"(*Element).Next", Method, 0}, + {"(*Element).Prev", Method, 0}, + {"(*List).Back", Method, 0}, + {"(*List).Front", Method, 0}, + {"(*List).Init", Method, 0}, + {"(*List).InsertAfter", Method, 0}, + {"(*List).InsertBefore", Method, 0}, + {"(*List).Len", Method, 0}, + {"(*List).MoveAfter", Method, 2}, + {"(*List).MoveBefore", Method, 2}, + {"(*List).MoveToBack", Method, 0}, + {"(*List).MoveToFront", Method, 0}, + {"(*List).PushBack", Method, 0}, + {"(*List).PushBackList", Method, 0}, + {"(*List).PushFront", Method, 0}, + {"(*List).PushFrontList", Method, 0}, + {"(*List).Remove", Method, 0}, + {"Element", Type, 0}, + {"Element.Value", Field, 0}, + {"List", Type, 0}, + {"New", Func, 0}, + }, + "container/ring": { + {"(*Ring).Do", Method, 0}, + {"(*Ring).Len", Method, 0}, + {"(*Ring).Link", Method, 0}, + {"(*Ring).Move", Method, 0}, + {"(*Ring).Next", Method, 0}, + {"(*Ring).Prev", Method, 0}, + {"(*Ring).Unlink", Method, 0}, + {"New", Func, 0}, + {"Ring", Type, 0}, + {"Ring.Value", Field, 0}, + }, + "context": { + {"AfterFunc", Func, 21}, + {"Background", Func, 7}, + {"CancelCauseFunc", Type, 20}, + {"CancelFunc", Type, 7}, + {"Canceled", Var, 7}, + {"Cause", Func, 20}, + {"Context", Type, 7}, + {"DeadlineExceeded", Var, 7}, + {"TODO", Func, 7}, + {"WithCancel", Func, 7}, + {"WithCancelCause", Func, 20}, + {"WithDeadline", Func, 7}, + {"WithDeadlineCause", Func, 21}, + {"WithTimeout", Func, 7}, + {"WithTimeoutCause", Func, 21}, + {"WithValue", Func, 7}, + {"WithoutCancel", Func, 21}, + }, + "crypto": { + {"(Hash).Available", Method, 0}, + {"(Hash).HashFunc", Method, 4}, + {"(Hash).New", Method, 0}, + {"(Hash).Size", Method, 0}, + {"(Hash).String", Method, 15}, + {"BLAKE2b_256", Const, 9}, + {"BLAKE2b_384", Const, 9}, + {"BLAKE2b_512", Const, 9}, + {"BLAKE2s_256", Const, 9}, + {"Decrypter", Type, 5}, + {"DecrypterOpts", Type, 5}, + {"Hash", Type, 0}, + {"MD4", Const, 0}, + {"MD5", Const, 0}, + {"MD5SHA1", Const, 0}, + {"PrivateKey", Type, 0}, + {"PublicKey", Type, 2}, + {"RIPEMD160", Const, 0}, + {"RegisterHash", Func, 0}, + {"SHA1", Const, 0}, + {"SHA224", Const, 0}, + {"SHA256", Const, 0}, + {"SHA384", Const, 0}, + {"SHA3_224", Const, 4}, + {"SHA3_256", Const, 4}, + {"SHA3_384", Const, 4}, + {"SHA3_512", Const, 4}, + {"SHA512", Const, 0}, + {"SHA512_224", Const, 5}, + {"SHA512_256", Const, 5}, + {"Signer", Type, 4}, + {"SignerOpts", Type, 4}, + }, + "crypto/aes": { + {"(KeySizeError).Error", Method, 0}, + {"BlockSize", Const, 0}, + {"KeySizeError", Type, 0}, + {"NewCipher", Func, 0}, + }, + "crypto/cipher": { + {"(StreamReader).Read", Method, 0}, + {"(StreamWriter).Close", Method, 0}, + {"(StreamWriter).Write", Method, 0}, + {"AEAD", Type, 2}, + {"Block", Type, 0}, + {"BlockMode", Type, 0}, + {"NewCBCDecrypter", Func, 0}, + {"NewCBCEncrypter", Func, 0}, + {"NewCFBDecrypter", Func, 0}, + {"NewCFBEncrypter", Func, 0}, + {"NewCTR", Func, 0}, + {"NewGCM", Func, 2}, + {"NewGCMWithNonceSize", Func, 5}, + {"NewGCMWithTagSize", Func, 11}, + {"NewOFB", Func, 0}, + {"Stream", Type, 0}, + {"StreamReader", Type, 0}, + {"StreamReader.R", Field, 0}, + {"StreamReader.S", Field, 0}, + {"StreamWriter", Type, 0}, + {"StreamWriter.Err", Field, 0}, + {"StreamWriter.S", Field, 0}, + {"StreamWriter.W", Field, 0}, + }, + "crypto/des": { + {"(KeySizeError).Error", Method, 0}, + {"BlockSize", Const, 0}, + {"KeySizeError", Type, 0}, + {"NewCipher", Func, 0}, + {"NewTripleDESCipher", Func, 0}, + }, + "crypto/dsa": { + {"ErrInvalidPublicKey", Var, 0}, + {"GenerateKey", Func, 0}, + {"GenerateParameters", Func, 0}, + {"L1024N160", Const, 0}, + {"L2048N224", Const, 0}, + {"L2048N256", Const, 0}, + {"L3072N256", Const, 0}, + {"ParameterSizes", Type, 0}, + {"Parameters", Type, 0}, + {"Parameters.G", Field, 0}, + {"Parameters.P", Field, 0}, + {"Parameters.Q", Field, 0}, + {"PrivateKey", Type, 0}, + {"PrivateKey.PublicKey", Field, 0}, + {"PrivateKey.X", Field, 0}, + {"PublicKey", Type, 0}, + {"PublicKey.Parameters", Field, 0}, + {"PublicKey.Y", Field, 0}, + {"Sign", Func, 0}, + {"Verify", Func, 0}, + }, + "crypto/ecdh": { + {"(*PrivateKey).Bytes", Method, 20}, + {"(*PrivateKey).Curve", Method, 20}, + {"(*PrivateKey).ECDH", Method, 20}, + {"(*PrivateKey).Equal", Method, 20}, + {"(*PrivateKey).Public", Method, 20}, + {"(*PrivateKey).PublicKey", Method, 20}, + {"(*PublicKey).Bytes", Method, 20}, + {"(*PublicKey).Curve", Method, 20}, + {"(*PublicKey).Equal", Method, 20}, + {"Curve", Type, 20}, + {"P256", Func, 20}, + {"P384", Func, 20}, + {"P521", Func, 20}, + {"PrivateKey", Type, 20}, + {"PublicKey", Type, 20}, + {"X25519", Func, 20}, + }, + "crypto/ecdsa": { + {"(*PrivateKey).ECDH", Method, 20}, + {"(*PrivateKey).Equal", Method, 15}, + {"(*PrivateKey).Public", Method, 4}, + {"(*PrivateKey).Sign", Method, 4}, + {"(*PublicKey).ECDH", Method, 20}, + {"(*PublicKey).Equal", Method, 15}, + {"(PrivateKey).Add", Method, 0}, + {"(PrivateKey).Double", Method, 0}, + {"(PrivateKey).IsOnCurve", Method, 0}, + {"(PrivateKey).Params", Method, 0}, + {"(PrivateKey).ScalarBaseMult", Method, 0}, + {"(PrivateKey).ScalarMult", Method, 0}, + {"(PublicKey).Add", Method, 0}, + {"(PublicKey).Double", Method, 0}, + {"(PublicKey).IsOnCurve", Method, 0}, + {"(PublicKey).Params", Method, 0}, + {"(PublicKey).ScalarBaseMult", Method, 0}, + {"(PublicKey).ScalarMult", Method, 0}, + {"GenerateKey", Func, 0}, + {"PrivateKey", Type, 0}, + {"PrivateKey.D", Field, 0}, + {"PrivateKey.PublicKey", Field, 0}, + {"PublicKey", Type, 0}, + {"PublicKey.Curve", Field, 0}, + {"PublicKey.X", Field, 0}, + {"PublicKey.Y", Field, 0}, + {"Sign", Func, 0}, + {"SignASN1", Func, 15}, + {"Verify", Func, 0}, + {"VerifyASN1", Func, 15}, + }, + "crypto/ed25519": { + {"(*Options).HashFunc", Method, 20}, + {"(PrivateKey).Equal", Method, 15}, + {"(PrivateKey).Public", Method, 13}, + {"(PrivateKey).Seed", Method, 13}, + {"(PrivateKey).Sign", Method, 13}, + {"(PublicKey).Equal", Method, 15}, + {"GenerateKey", Func, 13}, + {"NewKeyFromSeed", Func, 13}, + {"Options", Type, 20}, + {"Options.Context", Field, 20}, + {"Options.Hash", Field, 20}, + {"PrivateKey", Type, 13}, + {"PrivateKeySize", Const, 13}, + {"PublicKey", Type, 13}, + {"PublicKeySize", Const, 13}, + {"SeedSize", Const, 13}, + {"Sign", Func, 13}, + {"SignatureSize", Const, 13}, + {"Verify", Func, 13}, + {"VerifyWithOptions", Func, 20}, + }, + "crypto/elliptic": { + {"(*CurveParams).Add", Method, 0}, + {"(*CurveParams).Double", Method, 0}, + {"(*CurveParams).IsOnCurve", Method, 0}, + {"(*CurveParams).Params", Method, 0}, + {"(*CurveParams).ScalarBaseMult", Method, 0}, + {"(*CurveParams).ScalarMult", Method, 0}, + {"Curve", Type, 0}, + {"CurveParams", Type, 0}, + {"CurveParams.B", Field, 0}, + {"CurveParams.BitSize", Field, 0}, + {"CurveParams.Gx", Field, 0}, + {"CurveParams.Gy", Field, 0}, + {"CurveParams.N", Field, 0}, + {"CurveParams.Name", Field, 5}, + {"CurveParams.P", Field, 0}, + {"GenerateKey", Func, 0}, + {"Marshal", Func, 0}, + {"MarshalCompressed", Func, 15}, + {"P224", Func, 0}, + {"P256", Func, 0}, + {"P384", Func, 0}, + {"P521", Func, 0}, + {"Unmarshal", Func, 0}, + {"UnmarshalCompressed", Func, 15}, + }, + "crypto/hmac": { + {"Equal", Func, 1}, + {"New", Func, 0}, + }, + "crypto/md5": { + {"BlockSize", Const, 0}, + {"New", Func, 0}, + {"Size", Const, 0}, + {"Sum", Func, 2}, + }, + "crypto/rand": { + {"Int", Func, 0}, + {"Prime", Func, 0}, + {"Read", Func, 0}, + {"Reader", Var, 0}, + }, + "crypto/rc4": { + {"(*Cipher).Reset", Method, 0}, + {"(*Cipher).XORKeyStream", Method, 0}, + {"(KeySizeError).Error", Method, 0}, + {"Cipher", Type, 0}, + {"KeySizeError", Type, 0}, + {"NewCipher", Func, 0}, + }, + "crypto/rsa": { + {"(*PSSOptions).HashFunc", Method, 4}, + {"(*PrivateKey).Decrypt", Method, 5}, + {"(*PrivateKey).Equal", Method, 15}, + {"(*PrivateKey).Precompute", Method, 0}, + {"(*PrivateKey).Public", Method, 4}, + {"(*PrivateKey).Sign", Method, 4}, + {"(*PrivateKey).Size", Method, 11}, + {"(*PrivateKey).Validate", Method, 0}, + {"(*PublicKey).Equal", Method, 15}, + {"(*PublicKey).Size", Method, 11}, + {"CRTValue", Type, 0}, + {"CRTValue.Coeff", Field, 0}, + {"CRTValue.Exp", Field, 0}, + {"CRTValue.R", Field, 0}, + {"DecryptOAEP", Func, 0}, + {"DecryptPKCS1v15", Func, 0}, + {"DecryptPKCS1v15SessionKey", Func, 0}, + {"EncryptOAEP", Func, 0}, + {"EncryptPKCS1v15", Func, 0}, + {"ErrDecryption", Var, 0}, + {"ErrMessageTooLong", Var, 0}, + {"ErrVerification", Var, 0}, + {"GenerateKey", Func, 0}, + {"GenerateMultiPrimeKey", Func, 0}, + {"OAEPOptions", Type, 5}, + {"OAEPOptions.Hash", Field, 5}, + {"OAEPOptions.Label", Field, 5}, + {"OAEPOptions.MGFHash", Field, 20}, + {"PKCS1v15DecryptOptions", Type, 5}, + {"PKCS1v15DecryptOptions.SessionKeyLen", Field, 5}, + {"PSSOptions", Type, 2}, + {"PSSOptions.Hash", Field, 4}, + {"PSSOptions.SaltLength", Field, 2}, + {"PSSSaltLengthAuto", Const, 2}, + {"PSSSaltLengthEqualsHash", Const, 2}, + {"PrecomputedValues", Type, 0}, + {"PrecomputedValues.CRTValues", Field, 0}, + {"PrecomputedValues.Dp", Field, 0}, + {"PrecomputedValues.Dq", Field, 0}, + {"PrecomputedValues.Qinv", Field, 0}, + {"PrivateKey", Type, 0}, + {"PrivateKey.D", Field, 0}, + {"PrivateKey.Precomputed", Field, 0}, + {"PrivateKey.Primes", Field, 0}, + {"PrivateKey.PublicKey", Field, 0}, + {"PublicKey", Type, 0}, + {"PublicKey.E", Field, 0}, + {"PublicKey.N", Field, 0}, + {"SignPKCS1v15", Func, 0}, + {"SignPSS", Func, 2}, + {"VerifyPKCS1v15", Func, 0}, + {"VerifyPSS", Func, 2}, + }, + "crypto/sha1": { + {"BlockSize", Const, 0}, + {"New", Func, 0}, + {"Size", Const, 0}, + {"Sum", Func, 2}, + }, + "crypto/sha256": { + {"BlockSize", Const, 0}, + {"New", Func, 0}, + {"New224", Func, 0}, + {"Size", Const, 0}, + {"Size224", Const, 0}, + {"Sum224", Func, 2}, + {"Sum256", Func, 2}, + }, + "crypto/sha512": { + {"BlockSize", Const, 0}, + {"New", Func, 0}, + {"New384", Func, 0}, + {"New512_224", Func, 5}, + {"New512_256", Func, 5}, + {"Size", Const, 0}, + {"Size224", Const, 5}, + {"Size256", Const, 5}, + {"Size384", Const, 0}, + {"Sum384", Func, 2}, + {"Sum512", Func, 2}, + {"Sum512_224", Func, 5}, + {"Sum512_256", Func, 5}, + }, + "crypto/subtle": { + {"ConstantTimeByteEq", Func, 0}, + {"ConstantTimeCompare", Func, 0}, + {"ConstantTimeCopy", Func, 0}, + {"ConstantTimeEq", Func, 0}, + {"ConstantTimeLessOrEq", Func, 2}, + {"ConstantTimeSelect", Func, 0}, + {"XORBytes", Func, 20}, + }, + "crypto/tls": { + {"(*CertificateRequestInfo).Context", Method, 17}, + {"(*CertificateRequestInfo).SupportsCertificate", Method, 14}, + {"(*CertificateVerificationError).Error", Method, 20}, + {"(*CertificateVerificationError).Unwrap", Method, 20}, + {"(*ClientHelloInfo).Context", Method, 17}, + {"(*ClientHelloInfo).SupportsCertificate", Method, 14}, + {"(*ClientSessionState).ResumptionState", Method, 21}, + {"(*Config).BuildNameToCertificate", Method, 0}, + {"(*Config).Clone", Method, 8}, + {"(*Config).DecryptTicket", Method, 21}, + {"(*Config).EncryptTicket", Method, 21}, + {"(*Config).SetSessionTicketKeys", Method, 5}, + {"(*Conn).Close", Method, 0}, + {"(*Conn).CloseWrite", Method, 8}, + {"(*Conn).ConnectionState", Method, 0}, + {"(*Conn).Handshake", Method, 0}, + {"(*Conn).HandshakeContext", Method, 17}, + {"(*Conn).LocalAddr", Method, 0}, + {"(*Conn).NetConn", Method, 18}, + {"(*Conn).OCSPResponse", Method, 0}, + {"(*Conn).Read", Method, 0}, + {"(*Conn).RemoteAddr", Method, 0}, + {"(*Conn).SetDeadline", Method, 0}, + {"(*Conn).SetReadDeadline", Method, 0}, + {"(*Conn).SetWriteDeadline", Method, 0}, + {"(*Conn).VerifyHostname", Method, 0}, + {"(*Conn).Write", Method, 0}, + {"(*ConnectionState).ExportKeyingMaterial", Method, 11}, + {"(*Dialer).Dial", Method, 15}, + {"(*Dialer).DialContext", Method, 15}, + {"(*QUICConn).Close", Method, 21}, + {"(*QUICConn).ConnectionState", Method, 21}, + {"(*QUICConn).HandleData", Method, 21}, + {"(*QUICConn).NextEvent", Method, 21}, + {"(*QUICConn).SendSessionTicket", Method, 21}, + {"(*QUICConn).SetTransportParameters", Method, 21}, + {"(*QUICConn).Start", Method, 21}, + {"(*SessionState).Bytes", Method, 21}, + {"(AlertError).Error", Method, 21}, + {"(ClientAuthType).String", Method, 15}, + {"(CurveID).String", Method, 15}, + {"(QUICEncryptionLevel).String", Method, 21}, + {"(RecordHeaderError).Error", Method, 6}, + {"(SignatureScheme).String", Method, 15}, + {"AlertError", Type, 21}, + {"Certificate", Type, 0}, + {"Certificate.Certificate", Field, 0}, + {"Certificate.Leaf", Field, 0}, + {"Certificate.OCSPStaple", Field, 0}, + {"Certificate.PrivateKey", Field, 0}, + {"Certificate.SignedCertificateTimestamps", Field, 5}, + {"Certificate.SupportedSignatureAlgorithms", Field, 14}, + {"CertificateRequestInfo", Type, 8}, + {"CertificateRequestInfo.AcceptableCAs", Field, 8}, + {"CertificateRequestInfo.SignatureSchemes", Field, 8}, + {"CertificateRequestInfo.Version", Field, 14}, + {"CertificateVerificationError", Type, 20}, + {"CertificateVerificationError.Err", Field, 20}, + {"CertificateVerificationError.UnverifiedCertificates", Field, 20}, + {"CipherSuite", Type, 14}, + {"CipherSuite.ID", Field, 14}, + {"CipherSuite.Insecure", Field, 14}, + {"CipherSuite.Name", Field, 14}, + {"CipherSuite.SupportedVersions", Field, 14}, + {"CipherSuiteName", Func, 14}, + {"CipherSuites", Func, 14}, + {"Client", Func, 0}, + {"ClientAuthType", Type, 0}, + {"ClientHelloInfo", Type, 4}, + {"ClientHelloInfo.CipherSuites", Field, 4}, + {"ClientHelloInfo.Conn", Field, 8}, + {"ClientHelloInfo.ServerName", Field, 4}, + {"ClientHelloInfo.SignatureSchemes", Field, 8}, + {"ClientHelloInfo.SupportedCurves", Field, 4}, + {"ClientHelloInfo.SupportedPoints", Field, 4}, + {"ClientHelloInfo.SupportedProtos", Field, 8}, + {"ClientHelloInfo.SupportedVersions", Field, 8}, + {"ClientSessionCache", Type, 3}, + {"ClientSessionState", Type, 3}, + {"Config", Type, 0}, + {"Config.Certificates", Field, 0}, + {"Config.CipherSuites", Field, 0}, + {"Config.ClientAuth", Field, 0}, + {"Config.ClientCAs", Field, 0}, + {"Config.ClientSessionCache", Field, 3}, + {"Config.CurvePreferences", Field, 3}, + {"Config.DynamicRecordSizingDisabled", Field, 7}, + {"Config.GetCertificate", Field, 4}, + {"Config.GetClientCertificate", Field, 8}, + {"Config.GetConfigForClient", Field, 8}, + {"Config.InsecureSkipVerify", Field, 0}, + {"Config.KeyLogWriter", Field, 8}, + {"Config.MaxVersion", Field, 2}, + {"Config.MinVersion", Field, 2}, + {"Config.NameToCertificate", Field, 0}, + {"Config.NextProtos", Field, 0}, + {"Config.PreferServerCipherSuites", Field, 1}, + {"Config.Rand", Field, 0}, + {"Config.Renegotiation", Field, 7}, + {"Config.RootCAs", Field, 0}, + {"Config.ServerName", Field, 0}, + {"Config.SessionTicketKey", Field, 1}, + {"Config.SessionTicketsDisabled", Field, 1}, + {"Config.Time", Field, 0}, + {"Config.UnwrapSession", Field, 21}, + {"Config.VerifyConnection", Field, 15}, + {"Config.VerifyPeerCertificate", Field, 8}, + {"Config.WrapSession", Field, 21}, + {"Conn", Type, 0}, + {"ConnectionState", Type, 0}, + {"ConnectionState.CipherSuite", Field, 0}, + {"ConnectionState.DidResume", Field, 1}, + {"ConnectionState.HandshakeComplete", Field, 0}, + {"ConnectionState.NegotiatedProtocol", Field, 0}, + {"ConnectionState.NegotiatedProtocolIsMutual", Field, 0}, + {"ConnectionState.OCSPResponse", Field, 5}, + {"ConnectionState.PeerCertificates", Field, 0}, + {"ConnectionState.ServerName", Field, 0}, + {"ConnectionState.SignedCertificateTimestamps", Field, 5}, + {"ConnectionState.TLSUnique", Field, 4}, + {"ConnectionState.VerifiedChains", Field, 0}, + {"ConnectionState.Version", Field, 3}, + {"CurveID", Type, 3}, + {"CurveP256", Const, 3}, + {"CurveP384", Const, 3}, + {"CurveP521", Const, 3}, + {"Dial", Func, 0}, + {"DialWithDialer", Func, 3}, + {"Dialer", Type, 15}, + {"Dialer.Config", Field, 15}, + {"Dialer.NetDialer", Field, 15}, + {"ECDSAWithP256AndSHA256", Const, 8}, + {"ECDSAWithP384AndSHA384", Const, 8}, + {"ECDSAWithP521AndSHA512", Const, 8}, + {"ECDSAWithSHA1", Const, 10}, + {"Ed25519", Const, 13}, + {"InsecureCipherSuites", Func, 14}, + {"Listen", Func, 0}, + {"LoadX509KeyPair", Func, 0}, + {"NewLRUClientSessionCache", Func, 3}, + {"NewListener", Func, 0}, + {"NewResumptionState", Func, 21}, + {"NoClientCert", Const, 0}, + {"PKCS1WithSHA1", Const, 8}, + {"PKCS1WithSHA256", Const, 8}, + {"PKCS1WithSHA384", Const, 8}, + {"PKCS1WithSHA512", Const, 8}, + {"PSSWithSHA256", Const, 8}, + {"PSSWithSHA384", Const, 8}, + {"PSSWithSHA512", Const, 8}, + {"ParseSessionState", Func, 21}, + {"QUICClient", Func, 21}, + {"QUICConfig", Type, 21}, + {"QUICConfig.TLSConfig", Field, 21}, + {"QUICConn", Type, 21}, + {"QUICEncryptionLevel", Type, 21}, + {"QUICEncryptionLevelApplication", Const, 21}, + {"QUICEncryptionLevelEarly", Const, 21}, + {"QUICEncryptionLevelHandshake", Const, 21}, + {"QUICEncryptionLevelInitial", Const, 21}, + {"QUICEvent", Type, 21}, + {"QUICEvent.Data", Field, 21}, + {"QUICEvent.Kind", Field, 21}, + {"QUICEvent.Level", Field, 21}, + {"QUICEvent.Suite", Field, 21}, + {"QUICEventKind", Type, 21}, + {"QUICHandshakeDone", Const, 21}, + {"QUICNoEvent", Const, 21}, + {"QUICRejectedEarlyData", Const, 21}, + {"QUICServer", Func, 21}, + {"QUICSessionTicketOptions", Type, 21}, + {"QUICSessionTicketOptions.EarlyData", Field, 21}, + {"QUICSetReadSecret", Const, 21}, + {"QUICSetWriteSecret", Const, 21}, + {"QUICTransportParameters", Const, 21}, + {"QUICTransportParametersRequired", Const, 21}, + {"QUICWriteData", Const, 21}, + {"RecordHeaderError", Type, 6}, + {"RecordHeaderError.Conn", Field, 12}, + {"RecordHeaderError.Msg", Field, 6}, + {"RecordHeaderError.RecordHeader", Field, 6}, + {"RenegotiateFreelyAsClient", Const, 7}, + {"RenegotiateNever", Const, 7}, + {"RenegotiateOnceAsClient", Const, 7}, + {"RenegotiationSupport", Type, 7}, + {"RequestClientCert", Const, 0}, + {"RequireAndVerifyClientCert", Const, 0}, + {"RequireAnyClientCert", Const, 0}, + {"Server", Func, 0}, + {"SessionState", Type, 21}, + {"SessionState.EarlyData", Field, 21}, + {"SessionState.Extra", Field, 21}, + {"SignatureScheme", Type, 8}, + {"TLS_AES_128_GCM_SHA256", Const, 12}, + {"TLS_AES_256_GCM_SHA384", Const, 12}, + {"TLS_CHACHA20_POLY1305_SHA256", Const, 12}, + {"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", Const, 2}, + {"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", Const, 8}, + {"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", Const, 2}, + {"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", Const, 2}, + {"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", Const, 5}, + {"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", Const, 8}, + {"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", Const, 14}, + {"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", Const, 2}, + {"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", Const, 0}, + {"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", Const, 0}, + {"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", Const, 8}, + {"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", Const, 2}, + {"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", Const, 1}, + {"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", Const, 5}, + {"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", Const, 8}, + {"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", Const, 14}, + {"TLS_ECDHE_RSA_WITH_RC4_128_SHA", Const, 0}, + {"TLS_FALLBACK_SCSV", Const, 4}, + {"TLS_RSA_WITH_3DES_EDE_CBC_SHA", Const, 0}, + {"TLS_RSA_WITH_AES_128_CBC_SHA", Const, 0}, + {"TLS_RSA_WITH_AES_128_CBC_SHA256", Const, 8}, + {"TLS_RSA_WITH_AES_128_GCM_SHA256", Const, 6}, + {"TLS_RSA_WITH_AES_256_CBC_SHA", Const, 1}, + {"TLS_RSA_WITH_AES_256_GCM_SHA384", Const, 6}, + {"TLS_RSA_WITH_RC4_128_SHA", Const, 0}, + {"VerifyClientCertIfGiven", Const, 0}, + {"VersionName", Func, 21}, + {"VersionSSL30", Const, 2}, + {"VersionTLS10", Const, 2}, + {"VersionTLS11", Const, 2}, + {"VersionTLS12", Const, 2}, + {"VersionTLS13", Const, 12}, + {"X25519", Const, 8}, + {"X509KeyPair", Func, 0}, + }, + "crypto/x509": { + {"(*CertPool).AddCert", Method, 0}, + {"(*CertPool).AddCertWithConstraint", Method, 22}, + {"(*CertPool).AppendCertsFromPEM", Method, 0}, + {"(*CertPool).Clone", Method, 19}, + {"(*CertPool).Equal", Method, 19}, + {"(*CertPool).Subjects", Method, 0}, + {"(*Certificate).CheckCRLSignature", Method, 0}, + {"(*Certificate).CheckSignature", Method, 0}, + {"(*Certificate).CheckSignatureFrom", Method, 0}, + {"(*Certificate).CreateCRL", Method, 0}, + {"(*Certificate).Equal", Method, 0}, + {"(*Certificate).Verify", Method, 0}, + {"(*Certificate).VerifyHostname", Method, 0}, + {"(*CertificateRequest).CheckSignature", Method, 5}, + {"(*RevocationList).CheckSignatureFrom", Method, 19}, + {"(CertificateInvalidError).Error", Method, 0}, + {"(ConstraintViolationError).Error", Method, 0}, + {"(HostnameError).Error", Method, 0}, + {"(InsecureAlgorithmError).Error", Method, 6}, + {"(OID).Equal", Method, 22}, + {"(OID).EqualASN1OID", Method, 22}, + {"(OID).String", Method, 22}, + {"(PublicKeyAlgorithm).String", Method, 10}, + {"(SignatureAlgorithm).String", Method, 6}, + {"(SystemRootsError).Error", Method, 1}, + {"(SystemRootsError).Unwrap", Method, 16}, + {"(UnhandledCriticalExtension).Error", Method, 0}, + {"(UnknownAuthorityError).Error", Method, 0}, + {"CANotAuthorizedForExtKeyUsage", Const, 10}, + {"CANotAuthorizedForThisName", Const, 0}, + {"CertPool", Type, 0}, + {"Certificate", Type, 0}, + {"Certificate.AuthorityKeyId", Field, 0}, + {"Certificate.BasicConstraintsValid", Field, 0}, + {"Certificate.CRLDistributionPoints", Field, 2}, + {"Certificate.DNSNames", Field, 0}, + {"Certificate.EmailAddresses", Field, 0}, + {"Certificate.ExcludedDNSDomains", Field, 9}, + {"Certificate.ExcludedEmailAddresses", Field, 10}, + {"Certificate.ExcludedIPRanges", Field, 10}, + {"Certificate.ExcludedURIDomains", Field, 10}, + {"Certificate.ExtKeyUsage", Field, 0}, + {"Certificate.Extensions", Field, 2}, + {"Certificate.ExtraExtensions", Field, 2}, + {"Certificate.IPAddresses", Field, 1}, + {"Certificate.IsCA", Field, 0}, + {"Certificate.Issuer", Field, 0}, + {"Certificate.IssuingCertificateURL", Field, 2}, + {"Certificate.KeyUsage", Field, 0}, + {"Certificate.MaxPathLen", Field, 0}, + {"Certificate.MaxPathLenZero", Field, 4}, + {"Certificate.NotAfter", Field, 0}, + {"Certificate.NotBefore", Field, 0}, + {"Certificate.OCSPServer", Field, 2}, + {"Certificate.PermittedDNSDomains", Field, 0}, + {"Certificate.PermittedDNSDomainsCritical", Field, 0}, + {"Certificate.PermittedEmailAddresses", Field, 10}, + {"Certificate.PermittedIPRanges", Field, 10}, + {"Certificate.PermittedURIDomains", Field, 10}, + {"Certificate.Policies", Field, 22}, + {"Certificate.PolicyIdentifiers", Field, 0}, + {"Certificate.PublicKey", Field, 0}, + {"Certificate.PublicKeyAlgorithm", Field, 0}, + {"Certificate.Raw", Field, 0}, + {"Certificate.RawIssuer", Field, 0}, + {"Certificate.RawSubject", Field, 0}, + {"Certificate.RawSubjectPublicKeyInfo", Field, 0}, + {"Certificate.RawTBSCertificate", Field, 0}, + {"Certificate.SerialNumber", Field, 0}, + {"Certificate.Signature", Field, 0}, + {"Certificate.SignatureAlgorithm", Field, 0}, + {"Certificate.Subject", Field, 0}, + {"Certificate.SubjectKeyId", Field, 0}, + {"Certificate.URIs", Field, 10}, + {"Certificate.UnhandledCriticalExtensions", Field, 5}, + {"Certificate.UnknownExtKeyUsage", Field, 0}, + {"Certificate.Version", Field, 0}, + {"CertificateInvalidError", Type, 0}, + {"CertificateInvalidError.Cert", Field, 0}, + {"CertificateInvalidError.Detail", Field, 10}, + {"CertificateInvalidError.Reason", Field, 0}, + {"CertificateRequest", Type, 3}, + {"CertificateRequest.Attributes", Field, 3}, + {"CertificateRequest.DNSNames", Field, 3}, + {"CertificateRequest.EmailAddresses", Field, 3}, + {"CertificateRequest.Extensions", Field, 3}, + {"CertificateRequest.ExtraExtensions", Field, 3}, + {"CertificateRequest.IPAddresses", Field, 3}, + {"CertificateRequest.PublicKey", Field, 3}, + {"CertificateRequest.PublicKeyAlgorithm", Field, 3}, + {"CertificateRequest.Raw", Field, 3}, + {"CertificateRequest.RawSubject", Field, 3}, + {"CertificateRequest.RawSubjectPublicKeyInfo", Field, 3}, + {"CertificateRequest.RawTBSCertificateRequest", Field, 3}, + {"CertificateRequest.Signature", Field, 3}, + {"CertificateRequest.SignatureAlgorithm", Field, 3}, + {"CertificateRequest.Subject", Field, 3}, + {"CertificateRequest.URIs", Field, 10}, + {"CertificateRequest.Version", Field, 3}, + {"ConstraintViolationError", Type, 0}, + {"CreateCertificate", Func, 0}, + {"CreateCertificateRequest", Func, 3}, + {"CreateRevocationList", Func, 15}, + {"DSA", Const, 0}, + {"DSAWithSHA1", Const, 0}, + {"DSAWithSHA256", Const, 0}, + {"DecryptPEMBlock", Func, 1}, + {"ECDSA", Const, 1}, + {"ECDSAWithSHA1", Const, 1}, + {"ECDSAWithSHA256", Const, 1}, + {"ECDSAWithSHA384", Const, 1}, + {"ECDSAWithSHA512", Const, 1}, + {"Ed25519", Const, 13}, + {"EncryptPEMBlock", Func, 1}, + {"ErrUnsupportedAlgorithm", Var, 0}, + {"Expired", Const, 0}, + {"ExtKeyUsage", Type, 0}, + {"ExtKeyUsageAny", Const, 0}, + {"ExtKeyUsageClientAuth", Const, 0}, + {"ExtKeyUsageCodeSigning", Const, 0}, + {"ExtKeyUsageEmailProtection", Const, 0}, + {"ExtKeyUsageIPSECEndSystem", Const, 1}, + {"ExtKeyUsageIPSECTunnel", Const, 1}, + {"ExtKeyUsageIPSECUser", Const, 1}, + {"ExtKeyUsageMicrosoftCommercialCodeSigning", Const, 10}, + {"ExtKeyUsageMicrosoftKernelCodeSigning", Const, 10}, + {"ExtKeyUsageMicrosoftServerGatedCrypto", Const, 1}, + {"ExtKeyUsageNetscapeServerGatedCrypto", Const, 1}, + {"ExtKeyUsageOCSPSigning", Const, 0}, + {"ExtKeyUsageServerAuth", Const, 0}, + {"ExtKeyUsageTimeStamping", Const, 0}, + {"HostnameError", Type, 0}, + {"HostnameError.Certificate", Field, 0}, + {"HostnameError.Host", Field, 0}, + {"IncompatibleUsage", Const, 1}, + {"IncorrectPasswordError", Var, 1}, + {"InsecureAlgorithmError", Type, 6}, + {"InvalidReason", Type, 0}, + {"IsEncryptedPEMBlock", Func, 1}, + {"KeyUsage", Type, 0}, + {"KeyUsageCRLSign", Const, 0}, + {"KeyUsageCertSign", Const, 0}, + {"KeyUsageContentCommitment", Const, 0}, + {"KeyUsageDataEncipherment", Const, 0}, + {"KeyUsageDecipherOnly", Const, 0}, + {"KeyUsageDigitalSignature", Const, 0}, + {"KeyUsageEncipherOnly", Const, 0}, + {"KeyUsageKeyAgreement", Const, 0}, + {"KeyUsageKeyEncipherment", Const, 0}, + {"MD2WithRSA", Const, 0}, + {"MD5WithRSA", Const, 0}, + {"MarshalECPrivateKey", Func, 2}, + {"MarshalPKCS1PrivateKey", Func, 0}, + {"MarshalPKCS1PublicKey", Func, 10}, + {"MarshalPKCS8PrivateKey", Func, 10}, + {"MarshalPKIXPublicKey", Func, 0}, + {"NameConstraintsWithoutSANs", Const, 10}, + {"NameMismatch", Const, 8}, + {"NewCertPool", Func, 0}, + {"NotAuthorizedToSign", Const, 0}, + {"OID", Type, 22}, + {"OIDFromInts", Func, 22}, + {"PEMCipher", Type, 1}, + {"PEMCipher3DES", Const, 1}, + {"PEMCipherAES128", Const, 1}, + {"PEMCipherAES192", Const, 1}, + {"PEMCipherAES256", Const, 1}, + {"PEMCipherDES", Const, 1}, + {"ParseCRL", Func, 0}, + {"ParseCertificate", Func, 0}, + {"ParseCertificateRequest", Func, 3}, + {"ParseCertificates", Func, 0}, + {"ParseDERCRL", Func, 0}, + {"ParseECPrivateKey", Func, 1}, + {"ParsePKCS1PrivateKey", Func, 0}, + {"ParsePKCS1PublicKey", Func, 10}, + {"ParsePKCS8PrivateKey", Func, 0}, + {"ParsePKIXPublicKey", Func, 0}, + {"ParseRevocationList", Func, 19}, + {"PublicKeyAlgorithm", Type, 0}, + {"PureEd25519", Const, 13}, + {"RSA", Const, 0}, + {"RevocationList", Type, 15}, + {"RevocationList.AuthorityKeyId", Field, 19}, + {"RevocationList.Extensions", Field, 19}, + {"RevocationList.ExtraExtensions", Field, 15}, + {"RevocationList.Issuer", Field, 19}, + {"RevocationList.NextUpdate", Field, 15}, + {"RevocationList.Number", Field, 15}, + {"RevocationList.Raw", Field, 19}, + {"RevocationList.RawIssuer", Field, 19}, + {"RevocationList.RawTBSRevocationList", Field, 19}, + {"RevocationList.RevokedCertificateEntries", Field, 21}, + {"RevocationList.RevokedCertificates", Field, 15}, + {"RevocationList.Signature", Field, 19}, + {"RevocationList.SignatureAlgorithm", Field, 15}, + {"RevocationList.ThisUpdate", Field, 15}, + {"RevocationListEntry", Type, 21}, + {"RevocationListEntry.Extensions", Field, 21}, + {"RevocationListEntry.ExtraExtensions", Field, 21}, + {"RevocationListEntry.Raw", Field, 21}, + {"RevocationListEntry.ReasonCode", Field, 21}, + {"RevocationListEntry.RevocationTime", Field, 21}, + {"RevocationListEntry.SerialNumber", Field, 21}, + {"SHA1WithRSA", Const, 0}, + {"SHA256WithRSA", Const, 0}, + {"SHA256WithRSAPSS", Const, 8}, + {"SHA384WithRSA", Const, 0}, + {"SHA384WithRSAPSS", Const, 8}, + {"SHA512WithRSA", Const, 0}, + {"SHA512WithRSAPSS", Const, 8}, + {"SetFallbackRoots", Func, 20}, + {"SignatureAlgorithm", Type, 0}, + {"SystemCertPool", Func, 7}, + {"SystemRootsError", Type, 1}, + {"SystemRootsError.Err", Field, 7}, + {"TooManyConstraints", Const, 10}, + {"TooManyIntermediates", Const, 0}, + {"UnconstrainedName", Const, 10}, + {"UnhandledCriticalExtension", Type, 0}, + {"UnknownAuthorityError", Type, 0}, + {"UnknownAuthorityError.Cert", Field, 8}, + {"UnknownPublicKeyAlgorithm", Const, 0}, + {"UnknownSignatureAlgorithm", Const, 0}, + {"VerifyOptions", Type, 0}, + {"VerifyOptions.CurrentTime", Field, 0}, + {"VerifyOptions.DNSName", Field, 0}, + {"VerifyOptions.Intermediates", Field, 0}, + {"VerifyOptions.KeyUsages", Field, 1}, + {"VerifyOptions.MaxConstraintComparisions", Field, 10}, + {"VerifyOptions.Roots", Field, 0}, + }, + "crypto/x509/pkix": { + {"(*CertificateList).HasExpired", Method, 0}, + {"(*Name).FillFromRDNSequence", Method, 0}, + {"(Name).String", Method, 10}, + {"(Name).ToRDNSequence", Method, 0}, + {"(RDNSequence).String", Method, 10}, + {"AlgorithmIdentifier", Type, 0}, + {"AlgorithmIdentifier.Algorithm", Field, 0}, + {"AlgorithmIdentifier.Parameters", Field, 0}, + {"AttributeTypeAndValue", Type, 0}, + {"AttributeTypeAndValue.Type", Field, 0}, + {"AttributeTypeAndValue.Value", Field, 0}, + {"AttributeTypeAndValueSET", Type, 3}, + {"AttributeTypeAndValueSET.Type", Field, 3}, + {"AttributeTypeAndValueSET.Value", Field, 3}, + {"CertificateList", Type, 0}, + {"CertificateList.SignatureAlgorithm", Field, 0}, + {"CertificateList.SignatureValue", Field, 0}, + {"CertificateList.TBSCertList", Field, 0}, + {"Extension", Type, 0}, + {"Extension.Critical", Field, 0}, + {"Extension.Id", Field, 0}, + {"Extension.Value", Field, 0}, + {"Name", Type, 0}, + {"Name.CommonName", Field, 0}, + {"Name.Country", Field, 0}, + {"Name.ExtraNames", Field, 5}, + {"Name.Locality", Field, 0}, + {"Name.Names", Field, 0}, + {"Name.Organization", Field, 0}, + {"Name.OrganizationalUnit", Field, 0}, + {"Name.PostalCode", Field, 0}, + {"Name.Province", Field, 0}, + {"Name.SerialNumber", Field, 0}, + {"Name.StreetAddress", Field, 0}, + {"RDNSequence", Type, 0}, + {"RelativeDistinguishedNameSET", Type, 0}, + {"RevokedCertificate", Type, 0}, + {"RevokedCertificate.Extensions", Field, 0}, + {"RevokedCertificate.RevocationTime", Field, 0}, + {"RevokedCertificate.SerialNumber", Field, 0}, + {"TBSCertificateList", Type, 0}, + {"TBSCertificateList.Extensions", Field, 0}, + {"TBSCertificateList.Issuer", Field, 0}, + {"TBSCertificateList.NextUpdate", Field, 0}, + {"TBSCertificateList.Raw", Field, 0}, + {"TBSCertificateList.RevokedCertificates", Field, 0}, + {"TBSCertificateList.Signature", Field, 0}, + {"TBSCertificateList.ThisUpdate", Field, 0}, + {"TBSCertificateList.Version", Field, 0}, + }, + "database/sql": { + {"(*ColumnType).DatabaseTypeName", Method, 8}, + {"(*ColumnType).DecimalSize", Method, 8}, + {"(*ColumnType).Length", Method, 8}, + {"(*ColumnType).Name", Method, 8}, + {"(*ColumnType).Nullable", Method, 8}, + {"(*ColumnType).ScanType", Method, 8}, + {"(*Conn).BeginTx", Method, 9}, + {"(*Conn).Close", Method, 9}, + {"(*Conn).ExecContext", Method, 9}, + {"(*Conn).PingContext", Method, 9}, + {"(*Conn).PrepareContext", Method, 9}, + {"(*Conn).QueryContext", Method, 9}, + {"(*Conn).QueryRowContext", Method, 9}, + {"(*Conn).Raw", Method, 13}, + {"(*DB).Begin", Method, 0}, + {"(*DB).BeginTx", Method, 8}, + {"(*DB).Close", Method, 0}, + {"(*DB).Conn", Method, 9}, + {"(*DB).Driver", Method, 0}, + {"(*DB).Exec", Method, 0}, + {"(*DB).ExecContext", Method, 8}, + {"(*DB).Ping", Method, 1}, + {"(*DB).PingContext", Method, 8}, + {"(*DB).Prepare", Method, 0}, + {"(*DB).PrepareContext", Method, 8}, + {"(*DB).Query", Method, 0}, + {"(*DB).QueryContext", Method, 8}, + {"(*DB).QueryRow", Method, 0}, + {"(*DB).QueryRowContext", Method, 8}, + {"(*DB).SetConnMaxIdleTime", Method, 15}, + {"(*DB).SetConnMaxLifetime", Method, 6}, + {"(*DB).SetMaxIdleConns", Method, 1}, + {"(*DB).SetMaxOpenConns", Method, 2}, + {"(*DB).Stats", Method, 5}, + {"(*Null).Scan", Method, 22}, + {"(*NullBool).Scan", Method, 0}, + {"(*NullByte).Scan", Method, 17}, + {"(*NullFloat64).Scan", Method, 0}, + {"(*NullInt16).Scan", Method, 17}, + {"(*NullInt32).Scan", Method, 13}, + {"(*NullInt64).Scan", Method, 0}, + {"(*NullString).Scan", Method, 0}, + {"(*NullTime).Scan", Method, 13}, + {"(*Row).Err", Method, 15}, + {"(*Row).Scan", Method, 0}, + {"(*Rows).Close", Method, 0}, + {"(*Rows).ColumnTypes", Method, 8}, + {"(*Rows).Columns", Method, 0}, + {"(*Rows).Err", Method, 0}, + {"(*Rows).Next", Method, 0}, + {"(*Rows).NextResultSet", Method, 8}, + {"(*Rows).Scan", Method, 0}, + {"(*Stmt).Close", Method, 0}, + {"(*Stmt).Exec", Method, 0}, + {"(*Stmt).ExecContext", Method, 8}, + {"(*Stmt).Query", Method, 0}, + {"(*Stmt).QueryContext", Method, 8}, + {"(*Stmt).QueryRow", Method, 0}, + {"(*Stmt).QueryRowContext", Method, 8}, + {"(*Tx).Commit", Method, 0}, + {"(*Tx).Exec", Method, 0}, + {"(*Tx).ExecContext", Method, 8}, + {"(*Tx).Prepare", Method, 0}, + {"(*Tx).PrepareContext", Method, 8}, + {"(*Tx).Query", Method, 0}, + {"(*Tx).QueryContext", Method, 8}, + {"(*Tx).QueryRow", Method, 0}, + {"(*Tx).QueryRowContext", Method, 8}, + {"(*Tx).Rollback", Method, 0}, + {"(*Tx).Stmt", Method, 0}, + {"(*Tx).StmtContext", Method, 8}, + {"(IsolationLevel).String", Method, 11}, + {"(Null).Value", Method, 22}, + {"(NullBool).Value", Method, 0}, + {"(NullByte).Value", Method, 17}, + {"(NullFloat64).Value", Method, 0}, + {"(NullInt16).Value", Method, 17}, + {"(NullInt32).Value", Method, 13}, + {"(NullInt64).Value", Method, 0}, + {"(NullString).Value", Method, 0}, + {"(NullTime).Value", Method, 13}, + {"ColumnType", Type, 8}, + {"Conn", Type, 9}, + {"DB", Type, 0}, + {"DBStats", Type, 5}, + {"DBStats.Idle", Field, 11}, + {"DBStats.InUse", Field, 11}, + {"DBStats.MaxIdleClosed", Field, 11}, + {"DBStats.MaxIdleTimeClosed", Field, 15}, + {"DBStats.MaxLifetimeClosed", Field, 11}, + {"DBStats.MaxOpenConnections", Field, 11}, + {"DBStats.OpenConnections", Field, 5}, + {"DBStats.WaitCount", Field, 11}, + {"DBStats.WaitDuration", Field, 11}, + {"Drivers", Func, 4}, + {"ErrConnDone", Var, 9}, + {"ErrNoRows", Var, 0}, + {"ErrTxDone", Var, 0}, + {"IsolationLevel", Type, 8}, + {"LevelDefault", Const, 8}, + {"LevelLinearizable", Const, 8}, + {"LevelReadCommitted", Const, 8}, + {"LevelReadUncommitted", Const, 8}, + {"LevelRepeatableRead", Const, 8}, + {"LevelSerializable", Const, 8}, + {"LevelSnapshot", Const, 8}, + {"LevelWriteCommitted", Const, 8}, + {"Named", Func, 8}, + {"NamedArg", Type, 8}, + {"NamedArg.Name", Field, 8}, + {"NamedArg.Value", Field, 8}, + {"Null", Type, 22}, + {"Null.V", Field, 22}, + {"Null.Valid", Field, 22}, + {"NullBool", Type, 0}, + {"NullBool.Bool", Field, 0}, + {"NullBool.Valid", Field, 0}, + {"NullByte", Type, 17}, + {"NullByte.Byte", Field, 17}, + {"NullByte.Valid", Field, 17}, + {"NullFloat64", Type, 0}, + {"NullFloat64.Float64", Field, 0}, + {"NullFloat64.Valid", Field, 0}, + {"NullInt16", Type, 17}, + {"NullInt16.Int16", Field, 17}, + {"NullInt16.Valid", Field, 17}, + {"NullInt32", Type, 13}, + {"NullInt32.Int32", Field, 13}, + {"NullInt32.Valid", Field, 13}, + {"NullInt64", Type, 0}, + {"NullInt64.Int64", Field, 0}, + {"NullInt64.Valid", Field, 0}, + {"NullString", Type, 0}, + {"NullString.String", Field, 0}, + {"NullString.Valid", Field, 0}, + {"NullTime", Type, 13}, + {"NullTime.Time", Field, 13}, + {"NullTime.Valid", Field, 13}, + {"Open", Func, 0}, + {"OpenDB", Func, 10}, + {"Out", Type, 9}, + {"Out.Dest", Field, 9}, + {"Out.In", Field, 9}, + {"RawBytes", Type, 0}, + {"Register", Func, 0}, + {"Result", Type, 0}, + {"Row", Type, 0}, + {"Rows", Type, 0}, + {"Scanner", Type, 0}, + {"Stmt", Type, 0}, + {"Tx", Type, 0}, + {"TxOptions", Type, 8}, + {"TxOptions.Isolation", Field, 8}, + {"TxOptions.ReadOnly", Field, 8}, + }, + "database/sql/driver": { + {"(NotNull).ConvertValue", Method, 0}, + {"(Null).ConvertValue", Method, 0}, + {"(RowsAffected).LastInsertId", Method, 0}, + {"(RowsAffected).RowsAffected", Method, 0}, + {"Bool", Var, 0}, + {"ColumnConverter", Type, 0}, + {"Conn", Type, 0}, + {"ConnBeginTx", Type, 8}, + {"ConnPrepareContext", Type, 8}, + {"Connector", Type, 10}, + {"DefaultParameterConverter", Var, 0}, + {"Driver", Type, 0}, + {"DriverContext", Type, 10}, + {"ErrBadConn", Var, 0}, + {"ErrRemoveArgument", Var, 9}, + {"ErrSkip", Var, 0}, + {"Execer", Type, 0}, + {"ExecerContext", Type, 8}, + {"Int32", Var, 0}, + {"IsScanValue", Func, 0}, + {"IsValue", Func, 0}, + {"IsolationLevel", Type, 8}, + {"NamedValue", Type, 8}, + {"NamedValue.Name", Field, 8}, + {"NamedValue.Ordinal", Field, 8}, + {"NamedValue.Value", Field, 8}, + {"NamedValueChecker", Type, 9}, + {"NotNull", Type, 0}, + {"NotNull.Converter", Field, 0}, + {"Null", Type, 0}, + {"Null.Converter", Field, 0}, + {"Pinger", Type, 8}, + {"Queryer", Type, 1}, + {"QueryerContext", Type, 8}, + {"Result", Type, 0}, + {"ResultNoRows", Var, 0}, + {"Rows", Type, 0}, + {"RowsAffected", Type, 0}, + {"RowsColumnTypeDatabaseTypeName", Type, 8}, + {"RowsColumnTypeLength", Type, 8}, + {"RowsColumnTypeNullable", Type, 8}, + {"RowsColumnTypePrecisionScale", Type, 8}, + {"RowsColumnTypeScanType", Type, 8}, + {"RowsNextResultSet", Type, 8}, + {"SessionResetter", Type, 10}, + {"Stmt", Type, 0}, + {"StmtExecContext", Type, 8}, + {"StmtQueryContext", Type, 8}, + {"String", Var, 0}, + {"Tx", Type, 0}, + {"TxOptions", Type, 8}, + {"TxOptions.Isolation", Field, 8}, + {"TxOptions.ReadOnly", Field, 8}, + {"Validator", Type, 15}, + {"Value", Type, 0}, + {"ValueConverter", Type, 0}, + {"Valuer", Type, 0}, + }, + "debug/buildinfo": { + {"BuildInfo", Type, 18}, + {"Read", Func, 18}, + {"ReadFile", Func, 18}, + }, + "debug/dwarf": { + {"(*AddrType).Basic", Method, 0}, + {"(*AddrType).Common", Method, 0}, + {"(*AddrType).Size", Method, 0}, + {"(*AddrType).String", Method, 0}, + {"(*ArrayType).Common", Method, 0}, + {"(*ArrayType).Size", Method, 0}, + {"(*ArrayType).String", Method, 0}, + {"(*BasicType).Basic", Method, 0}, + {"(*BasicType).Common", Method, 0}, + {"(*BasicType).Size", Method, 0}, + {"(*BasicType).String", Method, 0}, + {"(*BoolType).Basic", Method, 0}, + {"(*BoolType).Common", Method, 0}, + {"(*BoolType).Size", Method, 0}, + {"(*BoolType).String", Method, 0}, + {"(*CharType).Basic", Method, 0}, + {"(*CharType).Common", Method, 0}, + {"(*CharType).Size", Method, 0}, + {"(*CharType).String", Method, 0}, + {"(*CommonType).Common", Method, 0}, + {"(*CommonType).Size", Method, 0}, + {"(*ComplexType).Basic", Method, 0}, + {"(*ComplexType).Common", Method, 0}, + {"(*ComplexType).Size", Method, 0}, + {"(*ComplexType).String", Method, 0}, + {"(*Data).AddSection", Method, 14}, + {"(*Data).AddTypes", Method, 3}, + {"(*Data).LineReader", Method, 5}, + {"(*Data).Ranges", Method, 7}, + {"(*Data).Reader", Method, 0}, + {"(*Data).Type", Method, 0}, + {"(*DotDotDotType).Common", Method, 0}, + {"(*DotDotDotType).Size", Method, 0}, + {"(*DotDotDotType).String", Method, 0}, + {"(*Entry).AttrField", Method, 5}, + {"(*Entry).Val", Method, 0}, + {"(*EnumType).Common", Method, 0}, + {"(*EnumType).Size", Method, 0}, + {"(*EnumType).String", Method, 0}, + {"(*FloatType).Basic", Method, 0}, + {"(*FloatType).Common", Method, 0}, + {"(*FloatType).Size", Method, 0}, + {"(*FloatType).String", Method, 0}, + {"(*FuncType).Common", Method, 0}, + {"(*FuncType).Size", Method, 0}, + {"(*FuncType).String", Method, 0}, + {"(*IntType).Basic", Method, 0}, + {"(*IntType).Common", Method, 0}, + {"(*IntType).Size", Method, 0}, + {"(*IntType).String", Method, 0}, + {"(*LineReader).Files", Method, 14}, + {"(*LineReader).Next", Method, 5}, + {"(*LineReader).Reset", Method, 5}, + {"(*LineReader).Seek", Method, 5}, + {"(*LineReader).SeekPC", Method, 5}, + {"(*LineReader).Tell", Method, 5}, + {"(*PtrType).Common", Method, 0}, + {"(*PtrType).Size", Method, 0}, + {"(*PtrType).String", Method, 0}, + {"(*QualType).Common", Method, 0}, + {"(*QualType).Size", Method, 0}, + {"(*QualType).String", Method, 0}, + {"(*Reader).AddressSize", Method, 5}, + {"(*Reader).ByteOrder", Method, 14}, + {"(*Reader).Next", Method, 0}, + {"(*Reader).Seek", Method, 0}, + {"(*Reader).SeekPC", Method, 7}, + {"(*Reader).SkipChildren", Method, 0}, + {"(*StructType).Common", Method, 0}, + {"(*StructType).Defn", Method, 0}, + {"(*StructType).Size", Method, 0}, + {"(*StructType).String", Method, 0}, + {"(*TypedefType).Common", Method, 0}, + {"(*TypedefType).Size", Method, 0}, + {"(*TypedefType).String", Method, 0}, + {"(*UcharType).Basic", Method, 0}, + {"(*UcharType).Common", Method, 0}, + {"(*UcharType).Size", Method, 0}, + {"(*UcharType).String", Method, 0}, + {"(*UintType).Basic", Method, 0}, + {"(*UintType).Common", Method, 0}, + {"(*UintType).Size", Method, 0}, + {"(*UintType).String", Method, 0}, + {"(*UnspecifiedType).Basic", Method, 4}, + {"(*UnspecifiedType).Common", Method, 4}, + {"(*UnspecifiedType).Size", Method, 4}, + {"(*UnspecifiedType).String", Method, 4}, + {"(*UnsupportedType).Common", Method, 13}, + {"(*UnsupportedType).Size", Method, 13}, + {"(*UnsupportedType).String", Method, 13}, + {"(*VoidType).Common", Method, 0}, + {"(*VoidType).Size", Method, 0}, + {"(*VoidType).String", Method, 0}, + {"(Attr).GoString", Method, 0}, + {"(Attr).String", Method, 0}, + {"(Class).GoString", Method, 5}, + {"(Class).String", Method, 5}, + {"(DecodeError).Error", Method, 0}, + {"(Tag).GoString", Method, 0}, + {"(Tag).String", Method, 0}, + {"AddrType", Type, 0}, + {"AddrType.BasicType", Field, 0}, + {"ArrayType", Type, 0}, + {"ArrayType.CommonType", Field, 0}, + {"ArrayType.Count", Field, 0}, + {"ArrayType.StrideBitSize", Field, 0}, + {"ArrayType.Type", Field, 0}, + {"Attr", Type, 0}, + {"AttrAbstractOrigin", Const, 0}, + {"AttrAccessibility", Const, 0}, + {"AttrAddrBase", Const, 14}, + {"AttrAddrClass", Const, 0}, + {"AttrAlignment", Const, 14}, + {"AttrAllocated", Const, 0}, + {"AttrArtificial", Const, 0}, + {"AttrAssociated", Const, 0}, + {"AttrBaseTypes", Const, 0}, + {"AttrBinaryScale", Const, 14}, + {"AttrBitOffset", Const, 0}, + {"AttrBitSize", Const, 0}, + {"AttrByteSize", Const, 0}, + {"AttrCallAllCalls", Const, 14}, + {"AttrCallAllSourceCalls", Const, 14}, + {"AttrCallAllTailCalls", Const, 14}, + {"AttrCallColumn", Const, 0}, + {"AttrCallDataLocation", Const, 14}, + {"AttrCallDataValue", Const, 14}, + {"AttrCallFile", Const, 0}, + {"AttrCallLine", Const, 0}, + {"AttrCallOrigin", Const, 14}, + {"AttrCallPC", Const, 14}, + {"AttrCallParameter", Const, 14}, + {"AttrCallReturnPC", Const, 14}, + {"AttrCallTailCall", Const, 14}, + {"AttrCallTarget", Const, 14}, + {"AttrCallTargetClobbered", Const, 14}, + {"AttrCallValue", Const, 14}, + {"AttrCalling", Const, 0}, + {"AttrCommonRef", Const, 0}, + {"AttrCompDir", Const, 0}, + {"AttrConstExpr", Const, 14}, + {"AttrConstValue", Const, 0}, + {"AttrContainingType", Const, 0}, + {"AttrCount", Const, 0}, + {"AttrDataBitOffset", Const, 14}, + {"AttrDataLocation", Const, 0}, + {"AttrDataMemberLoc", Const, 0}, + {"AttrDecimalScale", Const, 14}, + {"AttrDecimalSign", Const, 14}, + {"AttrDeclColumn", Const, 0}, + {"AttrDeclFile", Const, 0}, + {"AttrDeclLine", Const, 0}, + {"AttrDeclaration", Const, 0}, + {"AttrDefaultValue", Const, 0}, + {"AttrDefaulted", Const, 14}, + {"AttrDeleted", Const, 14}, + {"AttrDescription", Const, 0}, + {"AttrDigitCount", Const, 14}, + {"AttrDiscr", Const, 0}, + {"AttrDiscrList", Const, 0}, + {"AttrDiscrValue", Const, 0}, + {"AttrDwoName", Const, 14}, + {"AttrElemental", Const, 14}, + {"AttrEncoding", Const, 0}, + {"AttrEndianity", Const, 14}, + {"AttrEntrypc", Const, 0}, + {"AttrEnumClass", Const, 14}, + {"AttrExplicit", Const, 14}, + {"AttrExportSymbols", Const, 14}, + {"AttrExtension", Const, 0}, + {"AttrExternal", Const, 0}, + {"AttrFrameBase", Const, 0}, + {"AttrFriend", Const, 0}, + {"AttrHighpc", Const, 0}, + {"AttrIdentifierCase", Const, 0}, + {"AttrImport", Const, 0}, + {"AttrInline", Const, 0}, + {"AttrIsOptional", Const, 0}, + {"AttrLanguage", Const, 0}, + {"AttrLinkageName", Const, 14}, + {"AttrLocation", Const, 0}, + {"AttrLoclistsBase", Const, 14}, + {"AttrLowerBound", Const, 0}, + {"AttrLowpc", Const, 0}, + {"AttrMacroInfo", Const, 0}, + {"AttrMacros", Const, 14}, + {"AttrMainSubprogram", Const, 14}, + {"AttrMutable", Const, 14}, + {"AttrName", Const, 0}, + {"AttrNamelistItem", Const, 0}, + {"AttrNoreturn", Const, 14}, + {"AttrObjectPointer", Const, 14}, + {"AttrOrdering", Const, 0}, + {"AttrPictureString", Const, 14}, + {"AttrPriority", Const, 0}, + {"AttrProducer", Const, 0}, + {"AttrPrototyped", Const, 0}, + {"AttrPure", Const, 14}, + {"AttrRanges", Const, 0}, + {"AttrRank", Const, 14}, + {"AttrRecursive", Const, 14}, + {"AttrReference", Const, 14}, + {"AttrReturnAddr", Const, 0}, + {"AttrRnglistsBase", Const, 14}, + {"AttrRvalueReference", Const, 14}, + {"AttrSegment", Const, 0}, + {"AttrSibling", Const, 0}, + {"AttrSignature", Const, 14}, + {"AttrSmall", Const, 14}, + {"AttrSpecification", Const, 0}, + {"AttrStartScope", Const, 0}, + {"AttrStaticLink", Const, 0}, + {"AttrStmtList", Const, 0}, + {"AttrStrOffsetsBase", Const, 14}, + {"AttrStride", Const, 0}, + {"AttrStrideSize", Const, 0}, + {"AttrStringLength", Const, 0}, + {"AttrStringLengthBitSize", Const, 14}, + {"AttrStringLengthByteSize", Const, 14}, + {"AttrThreadsScaled", Const, 14}, + {"AttrTrampoline", Const, 0}, + {"AttrType", Const, 0}, + {"AttrUpperBound", Const, 0}, + {"AttrUseLocation", Const, 0}, + {"AttrUseUTF8", Const, 0}, + {"AttrVarParam", Const, 0}, + {"AttrVirtuality", Const, 0}, + {"AttrVisibility", Const, 0}, + {"AttrVtableElemLoc", Const, 0}, + {"BasicType", Type, 0}, + {"BasicType.BitOffset", Field, 0}, + {"BasicType.BitSize", Field, 0}, + {"BasicType.CommonType", Field, 0}, + {"BasicType.DataBitOffset", Field, 18}, + {"BoolType", Type, 0}, + {"BoolType.BasicType", Field, 0}, + {"CharType", Type, 0}, + {"CharType.BasicType", Field, 0}, + {"Class", Type, 5}, + {"ClassAddrPtr", Const, 14}, + {"ClassAddress", Const, 5}, + {"ClassBlock", Const, 5}, + {"ClassConstant", Const, 5}, + {"ClassExprLoc", Const, 5}, + {"ClassFlag", Const, 5}, + {"ClassLinePtr", Const, 5}, + {"ClassLocList", Const, 14}, + {"ClassLocListPtr", Const, 5}, + {"ClassMacPtr", Const, 5}, + {"ClassRangeListPtr", Const, 5}, + {"ClassReference", Const, 5}, + {"ClassReferenceAlt", Const, 5}, + {"ClassReferenceSig", Const, 5}, + {"ClassRngList", Const, 14}, + {"ClassRngListsPtr", Const, 14}, + {"ClassStrOffsetsPtr", Const, 14}, + {"ClassString", Const, 5}, + {"ClassStringAlt", Const, 5}, + {"ClassUnknown", Const, 6}, + {"CommonType", Type, 0}, + {"CommonType.ByteSize", Field, 0}, + {"CommonType.Name", Field, 0}, + {"ComplexType", Type, 0}, + {"ComplexType.BasicType", Field, 0}, + {"Data", Type, 0}, + {"DecodeError", Type, 0}, + {"DecodeError.Err", Field, 0}, + {"DecodeError.Name", Field, 0}, + {"DecodeError.Offset", Field, 0}, + {"DotDotDotType", Type, 0}, + {"DotDotDotType.CommonType", Field, 0}, + {"Entry", Type, 0}, + {"Entry.Children", Field, 0}, + {"Entry.Field", Field, 0}, + {"Entry.Offset", Field, 0}, + {"Entry.Tag", Field, 0}, + {"EnumType", Type, 0}, + {"EnumType.CommonType", Field, 0}, + {"EnumType.EnumName", Field, 0}, + {"EnumType.Val", Field, 0}, + {"EnumValue", Type, 0}, + {"EnumValue.Name", Field, 0}, + {"EnumValue.Val", Field, 0}, + {"ErrUnknownPC", Var, 5}, + {"Field", Type, 0}, + {"Field.Attr", Field, 0}, + {"Field.Class", Field, 5}, + {"Field.Val", Field, 0}, + {"FloatType", Type, 0}, + {"FloatType.BasicType", Field, 0}, + {"FuncType", Type, 0}, + {"FuncType.CommonType", Field, 0}, + {"FuncType.ParamType", Field, 0}, + {"FuncType.ReturnType", Field, 0}, + {"IntType", Type, 0}, + {"IntType.BasicType", Field, 0}, + {"LineEntry", Type, 5}, + {"LineEntry.Address", Field, 5}, + {"LineEntry.BasicBlock", Field, 5}, + {"LineEntry.Column", Field, 5}, + {"LineEntry.Discriminator", Field, 5}, + {"LineEntry.EndSequence", Field, 5}, + {"LineEntry.EpilogueBegin", Field, 5}, + {"LineEntry.File", Field, 5}, + {"LineEntry.ISA", Field, 5}, + {"LineEntry.IsStmt", Field, 5}, + {"LineEntry.Line", Field, 5}, + {"LineEntry.OpIndex", Field, 5}, + {"LineEntry.PrologueEnd", Field, 5}, + {"LineFile", Type, 5}, + {"LineFile.Length", Field, 5}, + {"LineFile.Mtime", Field, 5}, + {"LineFile.Name", Field, 5}, + {"LineReader", Type, 5}, + {"LineReaderPos", Type, 5}, + {"New", Func, 0}, + {"Offset", Type, 0}, + {"PtrType", Type, 0}, + {"PtrType.CommonType", Field, 0}, + {"PtrType.Type", Field, 0}, + {"QualType", Type, 0}, + {"QualType.CommonType", Field, 0}, + {"QualType.Qual", Field, 0}, + {"QualType.Type", Field, 0}, + {"Reader", Type, 0}, + {"StructField", Type, 0}, + {"StructField.BitOffset", Field, 0}, + {"StructField.BitSize", Field, 0}, + {"StructField.ByteOffset", Field, 0}, + {"StructField.ByteSize", Field, 0}, + {"StructField.DataBitOffset", Field, 18}, + {"StructField.Name", Field, 0}, + {"StructField.Type", Field, 0}, + {"StructType", Type, 0}, + {"StructType.CommonType", Field, 0}, + {"StructType.Field", Field, 0}, + {"StructType.Incomplete", Field, 0}, + {"StructType.Kind", Field, 0}, + {"StructType.StructName", Field, 0}, + {"Tag", Type, 0}, + {"TagAccessDeclaration", Const, 0}, + {"TagArrayType", Const, 0}, + {"TagAtomicType", Const, 14}, + {"TagBaseType", Const, 0}, + {"TagCallSite", Const, 14}, + {"TagCallSiteParameter", Const, 14}, + {"TagCatchDwarfBlock", Const, 0}, + {"TagClassType", Const, 0}, + {"TagCoarrayType", Const, 14}, + {"TagCommonDwarfBlock", Const, 0}, + {"TagCommonInclusion", Const, 0}, + {"TagCompileUnit", Const, 0}, + {"TagCondition", Const, 3}, + {"TagConstType", Const, 0}, + {"TagConstant", Const, 0}, + {"TagDwarfProcedure", Const, 0}, + {"TagDynamicType", Const, 14}, + {"TagEntryPoint", Const, 0}, + {"TagEnumerationType", Const, 0}, + {"TagEnumerator", Const, 0}, + {"TagFileType", Const, 0}, + {"TagFormalParameter", Const, 0}, + {"TagFriend", Const, 0}, + {"TagGenericSubrange", Const, 14}, + {"TagImmutableType", Const, 14}, + {"TagImportedDeclaration", Const, 0}, + {"TagImportedModule", Const, 0}, + {"TagImportedUnit", Const, 0}, + {"TagInheritance", Const, 0}, + {"TagInlinedSubroutine", Const, 0}, + {"TagInterfaceType", Const, 0}, + {"TagLabel", Const, 0}, + {"TagLexDwarfBlock", Const, 0}, + {"TagMember", Const, 0}, + {"TagModule", Const, 0}, + {"TagMutableType", Const, 0}, + {"TagNamelist", Const, 0}, + {"TagNamelistItem", Const, 0}, + {"TagNamespace", Const, 0}, + {"TagPackedType", Const, 0}, + {"TagPartialUnit", Const, 0}, + {"TagPointerType", Const, 0}, + {"TagPtrToMemberType", Const, 0}, + {"TagReferenceType", Const, 0}, + {"TagRestrictType", Const, 0}, + {"TagRvalueReferenceType", Const, 3}, + {"TagSetType", Const, 0}, + {"TagSharedType", Const, 3}, + {"TagSkeletonUnit", Const, 14}, + {"TagStringType", Const, 0}, + {"TagStructType", Const, 0}, + {"TagSubprogram", Const, 0}, + {"TagSubrangeType", Const, 0}, + {"TagSubroutineType", Const, 0}, + {"TagTemplateAlias", Const, 3}, + {"TagTemplateTypeParameter", Const, 0}, + {"TagTemplateValueParameter", Const, 0}, + {"TagThrownType", Const, 0}, + {"TagTryDwarfBlock", Const, 0}, + {"TagTypeUnit", Const, 3}, + {"TagTypedef", Const, 0}, + {"TagUnionType", Const, 0}, + {"TagUnspecifiedParameters", Const, 0}, + {"TagUnspecifiedType", Const, 0}, + {"TagVariable", Const, 0}, + {"TagVariant", Const, 0}, + {"TagVariantPart", Const, 0}, + {"TagVolatileType", Const, 0}, + {"TagWithStmt", Const, 0}, + {"Type", Type, 0}, + {"TypedefType", Type, 0}, + {"TypedefType.CommonType", Field, 0}, + {"TypedefType.Type", Field, 0}, + {"UcharType", Type, 0}, + {"UcharType.BasicType", Field, 0}, + {"UintType", Type, 0}, + {"UintType.BasicType", Field, 0}, + {"UnspecifiedType", Type, 4}, + {"UnspecifiedType.BasicType", Field, 4}, + {"UnsupportedType", Type, 13}, + {"UnsupportedType.CommonType", Field, 13}, + {"UnsupportedType.Tag", Field, 13}, + {"VoidType", Type, 0}, + {"VoidType.CommonType", Field, 0}, + }, + "debug/elf": { + {"(*File).Close", Method, 0}, + {"(*File).DWARF", Method, 0}, + {"(*File).DynString", Method, 1}, + {"(*File).DynValue", Method, 21}, + {"(*File).DynamicSymbols", Method, 4}, + {"(*File).ImportedLibraries", Method, 0}, + {"(*File).ImportedSymbols", Method, 0}, + {"(*File).Section", Method, 0}, + {"(*File).SectionByType", Method, 0}, + {"(*File).Symbols", Method, 0}, + {"(*FormatError).Error", Method, 0}, + {"(*Prog).Open", Method, 0}, + {"(*Section).Data", Method, 0}, + {"(*Section).Open", Method, 0}, + {"(Class).GoString", Method, 0}, + {"(Class).String", Method, 0}, + {"(CompressionType).GoString", Method, 6}, + {"(CompressionType).String", Method, 6}, + {"(Data).GoString", Method, 0}, + {"(Data).String", Method, 0}, + {"(DynFlag).GoString", Method, 0}, + {"(DynFlag).String", Method, 0}, + {"(DynFlag1).GoString", Method, 21}, + {"(DynFlag1).String", Method, 21}, + {"(DynTag).GoString", Method, 0}, + {"(DynTag).String", Method, 0}, + {"(Machine).GoString", Method, 0}, + {"(Machine).String", Method, 0}, + {"(NType).GoString", Method, 0}, + {"(NType).String", Method, 0}, + {"(OSABI).GoString", Method, 0}, + {"(OSABI).String", Method, 0}, + {"(Prog).ReadAt", Method, 0}, + {"(ProgFlag).GoString", Method, 0}, + {"(ProgFlag).String", Method, 0}, + {"(ProgType).GoString", Method, 0}, + {"(ProgType).String", Method, 0}, + {"(R_386).GoString", Method, 0}, + {"(R_386).String", Method, 0}, + {"(R_390).GoString", Method, 7}, + {"(R_390).String", Method, 7}, + {"(R_AARCH64).GoString", Method, 4}, + {"(R_AARCH64).String", Method, 4}, + {"(R_ALPHA).GoString", Method, 0}, + {"(R_ALPHA).String", Method, 0}, + {"(R_ARM).GoString", Method, 0}, + {"(R_ARM).String", Method, 0}, + {"(R_LARCH).GoString", Method, 19}, + {"(R_LARCH).String", Method, 19}, + {"(R_MIPS).GoString", Method, 6}, + {"(R_MIPS).String", Method, 6}, + {"(R_PPC).GoString", Method, 0}, + {"(R_PPC).String", Method, 0}, + {"(R_PPC64).GoString", Method, 5}, + {"(R_PPC64).String", Method, 5}, + {"(R_RISCV).GoString", Method, 11}, + {"(R_RISCV).String", Method, 11}, + {"(R_SPARC).GoString", Method, 0}, + {"(R_SPARC).String", Method, 0}, + {"(R_X86_64).GoString", Method, 0}, + {"(R_X86_64).String", Method, 0}, + {"(Section).ReadAt", Method, 0}, + {"(SectionFlag).GoString", Method, 0}, + {"(SectionFlag).String", Method, 0}, + {"(SectionIndex).GoString", Method, 0}, + {"(SectionIndex).String", Method, 0}, + {"(SectionType).GoString", Method, 0}, + {"(SectionType).String", Method, 0}, + {"(SymBind).GoString", Method, 0}, + {"(SymBind).String", Method, 0}, + {"(SymType).GoString", Method, 0}, + {"(SymType).String", Method, 0}, + {"(SymVis).GoString", Method, 0}, + {"(SymVis).String", Method, 0}, + {"(Type).GoString", Method, 0}, + {"(Type).String", Method, 0}, + {"(Version).GoString", Method, 0}, + {"(Version).String", Method, 0}, + {"ARM_MAGIC_TRAMP_NUMBER", Const, 0}, + {"COMPRESS_HIOS", Const, 6}, + {"COMPRESS_HIPROC", Const, 6}, + {"COMPRESS_LOOS", Const, 6}, + {"COMPRESS_LOPROC", Const, 6}, + {"COMPRESS_ZLIB", Const, 6}, + {"COMPRESS_ZSTD", Const, 21}, + {"Chdr32", Type, 6}, + {"Chdr32.Addralign", Field, 6}, + {"Chdr32.Size", Field, 6}, + {"Chdr32.Type", Field, 6}, + {"Chdr64", Type, 6}, + {"Chdr64.Addralign", Field, 6}, + {"Chdr64.Size", Field, 6}, + {"Chdr64.Type", Field, 6}, + {"Class", Type, 0}, + {"CompressionType", Type, 6}, + {"DF_1_CONFALT", Const, 21}, + {"DF_1_DIRECT", Const, 21}, + {"DF_1_DISPRELDNE", Const, 21}, + {"DF_1_DISPRELPND", Const, 21}, + {"DF_1_EDITED", Const, 21}, + {"DF_1_ENDFILTEE", Const, 21}, + {"DF_1_GLOBAL", Const, 21}, + {"DF_1_GLOBAUDIT", Const, 21}, + {"DF_1_GROUP", Const, 21}, + {"DF_1_IGNMULDEF", Const, 21}, + {"DF_1_INITFIRST", Const, 21}, + {"DF_1_INTERPOSE", Const, 21}, + {"DF_1_KMOD", Const, 21}, + {"DF_1_LOADFLTR", Const, 21}, + {"DF_1_NOCOMMON", Const, 21}, + {"DF_1_NODEFLIB", Const, 21}, + {"DF_1_NODELETE", Const, 21}, + {"DF_1_NODIRECT", Const, 21}, + {"DF_1_NODUMP", Const, 21}, + {"DF_1_NOHDR", Const, 21}, + {"DF_1_NOKSYMS", Const, 21}, + {"DF_1_NOOPEN", Const, 21}, + {"DF_1_NORELOC", Const, 21}, + {"DF_1_NOW", Const, 21}, + {"DF_1_ORIGIN", Const, 21}, + {"DF_1_PIE", Const, 21}, + {"DF_1_SINGLETON", Const, 21}, + {"DF_1_STUB", Const, 21}, + {"DF_1_SYMINTPOSE", Const, 21}, + {"DF_1_TRANS", Const, 21}, + {"DF_1_WEAKFILTER", Const, 21}, + {"DF_BIND_NOW", Const, 0}, + {"DF_ORIGIN", Const, 0}, + {"DF_STATIC_TLS", Const, 0}, + {"DF_SYMBOLIC", Const, 0}, + {"DF_TEXTREL", Const, 0}, + {"DT_ADDRRNGHI", Const, 16}, + {"DT_ADDRRNGLO", Const, 16}, + {"DT_AUDIT", Const, 16}, + {"DT_AUXILIARY", Const, 16}, + {"DT_BIND_NOW", Const, 0}, + {"DT_CHECKSUM", Const, 16}, + {"DT_CONFIG", Const, 16}, + {"DT_DEBUG", Const, 0}, + {"DT_DEPAUDIT", Const, 16}, + {"DT_ENCODING", Const, 0}, + {"DT_FEATURE", Const, 16}, + {"DT_FILTER", Const, 16}, + {"DT_FINI", Const, 0}, + {"DT_FINI_ARRAY", Const, 0}, + {"DT_FINI_ARRAYSZ", Const, 0}, + {"DT_FLAGS", Const, 0}, + {"DT_FLAGS_1", Const, 16}, + {"DT_GNU_CONFLICT", Const, 16}, + {"DT_GNU_CONFLICTSZ", Const, 16}, + {"DT_GNU_HASH", Const, 16}, + {"DT_GNU_LIBLIST", Const, 16}, + {"DT_GNU_LIBLISTSZ", Const, 16}, + {"DT_GNU_PRELINKED", Const, 16}, + {"DT_HASH", Const, 0}, + {"DT_HIOS", Const, 0}, + {"DT_HIPROC", Const, 0}, + {"DT_INIT", Const, 0}, + {"DT_INIT_ARRAY", Const, 0}, + {"DT_INIT_ARRAYSZ", Const, 0}, + {"DT_JMPREL", Const, 0}, + {"DT_LOOS", Const, 0}, + {"DT_LOPROC", Const, 0}, + {"DT_MIPS_AUX_DYNAMIC", Const, 16}, + {"DT_MIPS_BASE_ADDRESS", Const, 16}, + {"DT_MIPS_COMPACT_SIZE", Const, 16}, + {"DT_MIPS_CONFLICT", Const, 16}, + {"DT_MIPS_CONFLICTNO", Const, 16}, + {"DT_MIPS_CXX_FLAGS", Const, 16}, + {"DT_MIPS_DELTA_CLASS", Const, 16}, + {"DT_MIPS_DELTA_CLASSSYM", Const, 16}, + {"DT_MIPS_DELTA_CLASSSYM_NO", Const, 16}, + {"DT_MIPS_DELTA_CLASS_NO", Const, 16}, + {"DT_MIPS_DELTA_INSTANCE", Const, 16}, + {"DT_MIPS_DELTA_INSTANCE_NO", Const, 16}, + {"DT_MIPS_DELTA_RELOC", Const, 16}, + {"DT_MIPS_DELTA_RELOC_NO", Const, 16}, + {"DT_MIPS_DELTA_SYM", Const, 16}, + {"DT_MIPS_DELTA_SYM_NO", Const, 16}, + {"DT_MIPS_DYNSTR_ALIGN", Const, 16}, + {"DT_MIPS_FLAGS", Const, 16}, + {"DT_MIPS_GOTSYM", Const, 16}, + {"DT_MIPS_GP_VALUE", Const, 16}, + {"DT_MIPS_HIDDEN_GOTIDX", Const, 16}, + {"DT_MIPS_HIPAGENO", Const, 16}, + {"DT_MIPS_ICHECKSUM", Const, 16}, + {"DT_MIPS_INTERFACE", Const, 16}, + {"DT_MIPS_INTERFACE_SIZE", Const, 16}, + {"DT_MIPS_IVERSION", Const, 16}, + {"DT_MIPS_LIBLIST", Const, 16}, + {"DT_MIPS_LIBLISTNO", Const, 16}, + {"DT_MIPS_LOCALPAGE_GOTIDX", Const, 16}, + {"DT_MIPS_LOCAL_GOTIDX", Const, 16}, + {"DT_MIPS_LOCAL_GOTNO", Const, 16}, + {"DT_MIPS_MSYM", Const, 16}, + {"DT_MIPS_OPTIONS", Const, 16}, + {"DT_MIPS_PERF_SUFFIX", Const, 16}, + {"DT_MIPS_PIXIE_INIT", Const, 16}, + {"DT_MIPS_PLTGOT", Const, 16}, + {"DT_MIPS_PROTECTED_GOTIDX", Const, 16}, + {"DT_MIPS_RLD_MAP", Const, 16}, + {"DT_MIPS_RLD_MAP_REL", Const, 16}, + {"DT_MIPS_RLD_TEXT_RESOLVE_ADDR", Const, 16}, + {"DT_MIPS_RLD_VERSION", Const, 16}, + {"DT_MIPS_RWPLT", Const, 16}, + {"DT_MIPS_SYMBOL_LIB", Const, 16}, + {"DT_MIPS_SYMTABNO", Const, 16}, + {"DT_MIPS_TIME_STAMP", Const, 16}, + {"DT_MIPS_UNREFEXTNO", Const, 16}, + {"DT_MOVEENT", Const, 16}, + {"DT_MOVESZ", Const, 16}, + {"DT_MOVETAB", Const, 16}, + {"DT_NEEDED", Const, 0}, + {"DT_NULL", Const, 0}, + {"DT_PLTGOT", Const, 0}, + {"DT_PLTPAD", Const, 16}, + {"DT_PLTPADSZ", Const, 16}, + {"DT_PLTREL", Const, 0}, + {"DT_PLTRELSZ", Const, 0}, + {"DT_POSFLAG_1", Const, 16}, + {"DT_PPC64_GLINK", Const, 16}, + {"DT_PPC64_OPD", Const, 16}, + {"DT_PPC64_OPDSZ", Const, 16}, + {"DT_PPC64_OPT", Const, 16}, + {"DT_PPC_GOT", Const, 16}, + {"DT_PPC_OPT", Const, 16}, + {"DT_PREINIT_ARRAY", Const, 0}, + {"DT_PREINIT_ARRAYSZ", Const, 0}, + {"DT_REL", Const, 0}, + {"DT_RELA", Const, 0}, + {"DT_RELACOUNT", Const, 16}, + {"DT_RELAENT", Const, 0}, + {"DT_RELASZ", Const, 0}, + {"DT_RELCOUNT", Const, 16}, + {"DT_RELENT", Const, 0}, + {"DT_RELSZ", Const, 0}, + {"DT_RPATH", Const, 0}, + {"DT_RUNPATH", Const, 0}, + {"DT_SONAME", Const, 0}, + {"DT_SPARC_REGISTER", Const, 16}, + {"DT_STRSZ", Const, 0}, + {"DT_STRTAB", Const, 0}, + {"DT_SYMBOLIC", Const, 0}, + {"DT_SYMENT", Const, 0}, + {"DT_SYMINENT", Const, 16}, + {"DT_SYMINFO", Const, 16}, + {"DT_SYMINSZ", Const, 16}, + {"DT_SYMTAB", Const, 0}, + {"DT_SYMTAB_SHNDX", Const, 16}, + {"DT_TEXTREL", Const, 0}, + {"DT_TLSDESC_GOT", Const, 16}, + {"DT_TLSDESC_PLT", Const, 16}, + {"DT_USED", Const, 16}, + {"DT_VALRNGHI", Const, 16}, + {"DT_VALRNGLO", Const, 16}, + {"DT_VERDEF", Const, 16}, + {"DT_VERDEFNUM", Const, 16}, + {"DT_VERNEED", Const, 0}, + {"DT_VERNEEDNUM", Const, 0}, + {"DT_VERSYM", Const, 0}, + {"Data", Type, 0}, + {"Dyn32", Type, 0}, + {"Dyn32.Tag", Field, 0}, + {"Dyn32.Val", Field, 0}, + {"Dyn64", Type, 0}, + {"Dyn64.Tag", Field, 0}, + {"Dyn64.Val", Field, 0}, + {"DynFlag", Type, 0}, + {"DynFlag1", Type, 21}, + {"DynTag", Type, 0}, + {"EI_ABIVERSION", Const, 0}, + {"EI_CLASS", Const, 0}, + {"EI_DATA", Const, 0}, + {"EI_NIDENT", Const, 0}, + {"EI_OSABI", Const, 0}, + {"EI_PAD", Const, 0}, + {"EI_VERSION", Const, 0}, + {"ELFCLASS32", Const, 0}, + {"ELFCLASS64", Const, 0}, + {"ELFCLASSNONE", Const, 0}, + {"ELFDATA2LSB", Const, 0}, + {"ELFDATA2MSB", Const, 0}, + {"ELFDATANONE", Const, 0}, + {"ELFMAG", Const, 0}, + {"ELFOSABI_86OPEN", Const, 0}, + {"ELFOSABI_AIX", Const, 0}, + {"ELFOSABI_ARM", Const, 0}, + {"ELFOSABI_AROS", Const, 11}, + {"ELFOSABI_CLOUDABI", Const, 11}, + {"ELFOSABI_FENIXOS", Const, 11}, + {"ELFOSABI_FREEBSD", Const, 0}, + {"ELFOSABI_HPUX", Const, 0}, + {"ELFOSABI_HURD", Const, 0}, + {"ELFOSABI_IRIX", Const, 0}, + {"ELFOSABI_LINUX", Const, 0}, + {"ELFOSABI_MODESTO", Const, 0}, + {"ELFOSABI_NETBSD", Const, 0}, + {"ELFOSABI_NONE", Const, 0}, + {"ELFOSABI_NSK", Const, 0}, + {"ELFOSABI_OPENBSD", Const, 0}, + {"ELFOSABI_OPENVMS", Const, 0}, + {"ELFOSABI_SOLARIS", Const, 0}, + {"ELFOSABI_STANDALONE", Const, 0}, + {"ELFOSABI_TRU64", Const, 0}, + {"EM_386", Const, 0}, + {"EM_486", Const, 0}, + {"EM_56800EX", Const, 11}, + {"EM_68HC05", Const, 11}, + {"EM_68HC08", Const, 11}, + {"EM_68HC11", Const, 11}, + {"EM_68HC12", Const, 0}, + {"EM_68HC16", Const, 11}, + {"EM_68K", Const, 0}, + {"EM_78KOR", Const, 11}, + {"EM_8051", Const, 11}, + {"EM_860", Const, 0}, + {"EM_88K", Const, 0}, + {"EM_960", Const, 0}, + {"EM_AARCH64", Const, 4}, + {"EM_ALPHA", Const, 0}, + {"EM_ALPHA_STD", Const, 0}, + {"EM_ALTERA_NIOS2", Const, 11}, + {"EM_AMDGPU", Const, 11}, + {"EM_ARC", Const, 0}, + {"EM_ARCA", Const, 11}, + {"EM_ARC_COMPACT", Const, 11}, + {"EM_ARC_COMPACT2", Const, 11}, + {"EM_ARM", Const, 0}, + {"EM_AVR", Const, 11}, + {"EM_AVR32", Const, 11}, + {"EM_BA1", Const, 11}, + {"EM_BA2", Const, 11}, + {"EM_BLACKFIN", Const, 11}, + {"EM_BPF", Const, 11}, + {"EM_C166", Const, 11}, + {"EM_CDP", Const, 11}, + {"EM_CE", Const, 11}, + {"EM_CLOUDSHIELD", Const, 11}, + {"EM_COGE", Const, 11}, + {"EM_COLDFIRE", Const, 0}, + {"EM_COOL", Const, 11}, + {"EM_COREA_1ST", Const, 11}, + {"EM_COREA_2ND", Const, 11}, + {"EM_CR", Const, 11}, + {"EM_CR16", Const, 11}, + {"EM_CRAYNV2", Const, 11}, + {"EM_CRIS", Const, 11}, + {"EM_CRX", Const, 11}, + {"EM_CSR_KALIMBA", Const, 11}, + {"EM_CUDA", Const, 11}, + {"EM_CYPRESS_M8C", Const, 11}, + {"EM_D10V", Const, 11}, + {"EM_D30V", Const, 11}, + {"EM_DSP24", Const, 11}, + {"EM_DSPIC30F", Const, 11}, + {"EM_DXP", Const, 11}, + {"EM_ECOG1", Const, 11}, + {"EM_ECOG16", Const, 11}, + {"EM_ECOG1X", Const, 11}, + {"EM_ECOG2", Const, 11}, + {"EM_ETPU", Const, 11}, + {"EM_EXCESS", Const, 11}, + {"EM_F2MC16", Const, 11}, + {"EM_FIREPATH", Const, 11}, + {"EM_FR20", Const, 0}, + {"EM_FR30", Const, 11}, + {"EM_FT32", Const, 11}, + {"EM_FX66", Const, 11}, + {"EM_H8S", Const, 0}, + {"EM_H8_300", Const, 0}, + {"EM_H8_300H", Const, 0}, + {"EM_H8_500", Const, 0}, + {"EM_HUANY", Const, 11}, + {"EM_IA_64", Const, 0}, + {"EM_INTEL205", Const, 11}, + {"EM_INTEL206", Const, 11}, + {"EM_INTEL207", Const, 11}, + {"EM_INTEL208", Const, 11}, + {"EM_INTEL209", Const, 11}, + {"EM_IP2K", Const, 11}, + {"EM_JAVELIN", Const, 11}, + {"EM_K10M", Const, 11}, + {"EM_KM32", Const, 11}, + {"EM_KMX16", Const, 11}, + {"EM_KMX32", Const, 11}, + {"EM_KMX8", Const, 11}, + {"EM_KVARC", Const, 11}, + {"EM_L10M", Const, 11}, + {"EM_LANAI", Const, 11}, + {"EM_LATTICEMICO32", Const, 11}, + {"EM_LOONGARCH", Const, 19}, + {"EM_M16C", Const, 11}, + {"EM_M32", Const, 0}, + {"EM_M32C", Const, 11}, + {"EM_M32R", Const, 11}, + {"EM_MANIK", Const, 11}, + {"EM_MAX", Const, 11}, + {"EM_MAXQ30", Const, 11}, + {"EM_MCHP_PIC", Const, 11}, + {"EM_MCST_ELBRUS", Const, 11}, + {"EM_ME16", Const, 0}, + {"EM_METAG", Const, 11}, + {"EM_MICROBLAZE", Const, 11}, + {"EM_MIPS", Const, 0}, + {"EM_MIPS_RS3_LE", Const, 0}, + {"EM_MIPS_RS4_BE", Const, 0}, + {"EM_MIPS_X", Const, 0}, + {"EM_MMA", Const, 0}, + {"EM_MMDSP_PLUS", Const, 11}, + {"EM_MMIX", Const, 11}, + {"EM_MN10200", Const, 11}, + {"EM_MN10300", Const, 11}, + {"EM_MOXIE", Const, 11}, + {"EM_MSP430", Const, 11}, + {"EM_NCPU", Const, 0}, + {"EM_NDR1", Const, 0}, + {"EM_NDS32", Const, 11}, + {"EM_NONE", Const, 0}, + {"EM_NORC", Const, 11}, + {"EM_NS32K", Const, 11}, + {"EM_OPEN8", Const, 11}, + {"EM_OPENRISC", Const, 11}, + {"EM_PARISC", Const, 0}, + {"EM_PCP", Const, 0}, + {"EM_PDP10", Const, 11}, + {"EM_PDP11", Const, 11}, + {"EM_PDSP", Const, 11}, + {"EM_PJ", Const, 11}, + {"EM_PPC", Const, 0}, + {"EM_PPC64", Const, 0}, + {"EM_PRISM", Const, 11}, + {"EM_QDSP6", Const, 11}, + {"EM_R32C", Const, 11}, + {"EM_RCE", Const, 0}, + {"EM_RH32", Const, 0}, + {"EM_RISCV", Const, 11}, + {"EM_RL78", Const, 11}, + {"EM_RS08", Const, 11}, + {"EM_RX", Const, 11}, + {"EM_S370", Const, 0}, + {"EM_S390", Const, 0}, + {"EM_SCORE7", Const, 11}, + {"EM_SEP", Const, 11}, + {"EM_SE_C17", Const, 11}, + {"EM_SE_C33", Const, 11}, + {"EM_SH", Const, 0}, + {"EM_SHARC", Const, 11}, + {"EM_SLE9X", Const, 11}, + {"EM_SNP1K", Const, 11}, + {"EM_SPARC", Const, 0}, + {"EM_SPARC32PLUS", Const, 0}, + {"EM_SPARCV9", Const, 0}, + {"EM_ST100", Const, 0}, + {"EM_ST19", Const, 11}, + {"EM_ST200", Const, 11}, + {"EM_ST7", Const, 11}, + {"EM_ST9PLUS", Const, 11}, + {"EM_STARCORE", Const, 0}, + {"EM_STM8", Const, 11}, + {"EM_STXP7X", Const, 11}, + {"EM_SVX", Const, 11}, + {"EM_TILE64", Const, 11}, + {"EM_TILEGX", Const, 11}, + {"EM_TILEPRO", Const, 11}, + {"EM_TINYJ", Const, 0}, + {"EM_TI_ARP32", Const, 11}, + {"EM_TI_C2000", Const, 11}, + {"EM_TI_C5500", Const, 11}, + {"EM_TI_C6000", Const, 11}, + {"EM_TI_PRU", Const, 11}, + {"EM_TMM_GPP", Const, 11}, + {"EM_TPC", Const, 11}, + {"EM_TRICORE", Const, 0}, + {"EM_TRIMEDIA", Const, 11}, + {"EM_TSK3000", Const, 11}, + {"EM_UNICORE", Const, 11}, + {"EM_V800", Const, 0}, + {"EM_V850", Const, 11}, + {"EM_VAX", Const, 11}, + {"EM_VIDEOCORE", Const, 11}, + {"EM_VIDEOCORE3", Const, 11}, + {"EM_VIDEOCORE5", Const, 11}, + {"EM_VISIUM", Const, 11}, + {"EM_VPP500", Const, 0}, + {"EM_X86_64", Const, 0}, + {"EM_XCORE", Const, 11}, + {"EM_XGATE", Const, 11}, + {"EM_XIMO16", Const, 11}, + {"EM_XTENSA", Const, 11}, + {"EM_Z80", Const, 11}, + {"EM_ZSP", Const, 11}, + {"ET_CORE", Const, 0}, + {"ET_DYN", Const, 0}, + {"ET_EXEC", Const, 0}, + {"ET_HIOS", Const, 0}, + {"ET_HIPROC", Const, 0}, + {"ET_LOOS", Const, 0}, + {"ET_LOPROC", Const, 0}, + {"ET_NONE", Const, 0}, + {"ET_REL", Const, 0}, + {"EV_CURRENT", Const, 0}, + {"EV_NONE", Const, 0}, + {"ErrNoSymbols", Var, 4}, + {"File", Type, 0}, + {"File.FileHeader", Field, 0}, + {"File.Progs", Field, 0}, + {"File.Sections", Field, 0}, + {"FileHeader", Type, 0}, + {"FileHeader.ABIVersion", Field, 0}, + {"FileHeader.ByteOrder", Field, 0}, + {"FileHeader.Class", Field, 0}, + {"FileHeader.Data", Field, 0}, + {"FileHeader.Entry", Field, 1}, + {"FileHeader.Machine", Field, 0}, + {"FileHeader.OSABI", Field, 0}, + {"FileHeader.Type", Field, 0}, + {"FileHeader.Version", Field, 0}, + {"FormatError", Type, 0}, + {"Header32", Type, 0}, + {"Header32.Ehsize", Field, 0}, + {"Header32.Entry", Field, 0}, + {"Header32.Flags", Field, 0}, + {"Header32.Ident", Field, 0}, + {"Header32.Machine", Field, 0}, + {"Header32.Phentsize", Field, 0}, + {"Header32.Phnum", Field, 0}, + {"Header32.Phoff", Field, 0}, + {"Header32.Shentsize", Field, 0}, + {"Header32.Shnum", Field, 0}, + {"Header32.Shoff", Field, 0}, + {"Header32.Shstrndx", Field, 0}, + {"Header32.Type", Field, 0}, + {"Header32.Version", Field, 0}, + {"Header64", Type, 0}, + {"Header64.Ehsize", Field, 0}, + {"Header64.Entry", Field, 0}, + {"Header64.Flags", Field, 0}, + {"Header64.Ident", Field, 0}, + {"Header64.Machine", Field, 0}, + {"Header64.Phentsize", Field, 0}, + {"Header64.Phnum", Field, 0}, + {"Header64.Phoff", Field, 0}, + {"Header64.Shentsize", Field, 0}, + {"Header64.Shnum", Field, 0}, + {"Header64.Shoff", Field, 0}, + {"Header64.Shstrndx", Field, 0}, + {"Header64.Type", Field, 0}, + {"Header64.Version", Field, 0}, + {"ImportedSymbol", Type, 0}, + {"ImportedSymbol.Library", Field, 0}, + {"ImportedSymbol.Name", Field, 0}, + {"ImportedSymbol.Version", Field, 0}, + {"Machine", Type, 0}, + {"NT_FPREGSET", Const, 0}, + {"NT_PRPSINFO", Const, 0}, + {"NT_PRSTATUS", Const, 0}, + {"NType", Type, 0}, + {"NewFile", Func, 0}, + {"OSABI", Type, 0}, + {"Open", Func, 0}, + {"PF_MASKOS", Const, 0}, + {"PF_MASKPROC", Const, 0}, + {"PF_R", Const, 0}, + {"PF_W", Const, 0}, + {"PF_X", Const, 0}, + {"PT_AARCH64_ARCHEXT", Const, 16}, + {"PT_AARCH64_UNWIND", Const, 16}, + {"PT_ARM_ARCHEXT", Const, 16}, + {"PT_ARM_EXIDX", Const, 16}, + {"PT_DYNAMIC", Const, 0}, + {"PT_GNU_EH_FRAME", Const, 16}, + {"PT_GNU_MBIND_HI", Const, 16}, + {"PT_GNU_MBIND_LO", Const, 16}, + {"PT_GNU_PROPERTY", Const, 16}, + {"PT_GNU_RELRO", Const, 16}, + {"PT_GNU_STACK", Const, 16}, + {"PT_HIOS", Const, 0}, + {"PT_HIPROC", Const, 0}, + {"PT_INTERP", Const, 0}, + {"PT_LOAD", Const, 0}, + {"PT_LOOS", Const, 0}, + {"PT_LOPROC", Const, 0}, + {"PT_MIPS_ABIFLAGS", Const, 16}, + {"PT_MIPS_OPTIONS", Const, 16}, + {"PT_MIPS_REGINFO", Const, 16}, + {"PT_MIPS_RTPROC", Const, 16}, + {"PT_NOTE", Const, 0}, + {"PT_NULL", Const, 0}, + {"PT_OPENBSD_BOOTDATA", Const, 16}, + {"PT_OPENBSD_RANDOMIZE", Const, 16}, + {"PT_OPENBSD_WXNEEDED", Const, 16}, + {"PT_PAX_FLAGS", Const, 16}, + {"PT_PHDR", Const, 0}, + {"PT_S390_PGSTE", Const, 16}, + {"PT_SHLIB", Const, 0}, + {"PT_SUNWSTACK", Const, 16}, + {"PT_SUNW_EH_FRAME", Const, 16}, + {"PT_TLS", Const, 0}, + {"Prog", Type, 0}, + {"Prog.ProgHeader", Field, 0}, + {"Prog.ReaderAt", Field, 0}, + {"Prog32", Type, 0}, + {"Prog32.Align", Field, 0}, + {"Prog32.Filesz", Field, 0}, + {"Prog32.Flags", Field, 0}, + {"Prog32.Memsz", Field, 0}, + {"Prog32.Off", Field, 0}, + {"Prog32.Paddr", Field, 0}, + {"Prog32.Type", Field, 0}, + {"Prog32.Vaddr", Field, 0}, + {"Prog64", Type, 0}, + {"Prog64.Align", Field, 0}, + {"Prog64.Filesz", Field, 0}, + {"Prog64.Flags", Field, 0}, + {"Prog64.Memsz", Field, 0}, + {"Prog64.Off", Field, 0}, + {"Prog64.Paddr", Field, 0}, + {"Prog64.Type", Field, 0}, + {"Prog64.Vaddr", Field, 0}, + {"ProgFlag", Type, 0}, + {"ProgHeader", Type, 0}, + {"ProgHeader.Align", Field, 0}, + {"ProgHeader.Filesz", Field, 0}, + {"ProgHeader.Flags", Field, 0}, + {"ProgHeader.Memsz", Field, 0}, + {"ProgHeader.Off", Field, 0}, + {"ProgHeader.Paddr", Field, 0}, + {"ProgHeader.Type", Field, 0}, + {"ProgHeader.Vaddr", Field, 0}, + {"ProgType", Type, 0}, + {"R_386", Type, 0}, + {"R_386_16", Const, 10}, + {"R_386_32", Const, 0}, + {"R_386_32PLT", Const, 10}, + {"R_386_8", Const, 10}, + {"R_386_COPY", Const, 0}, + {"R_386_GLOB_DAT", Const, 0}, + {"R_386_GOT32", Const, 0}, + {"R_386_GOT32X", Const, 10}, + {"R_386_GOTOFF", Const, 0}, + {"R_386_GOTPC", Const, 0}, + {"R_386_IRELATIVE", Const, 10}, + {"R_386_JMP_SLOT", Const, 0}, + {"R_386_NONE", Const, 0}, + {"R_386_PC16", Const, 10}, + {"R_386_PC32", Const, 0}, + {"R_386_PC8", Const, 10}, + {"R_386_PLT32", Const, 0}, + {"R_386_RELATIVE", Const, 0}, + {"R_386_SIZE32", Const, 10}, + {"R_386_TLS_DESC", Const, 10}, + {"R_386_TLS_DESC_CALL", Const, 10}, + {"R_386_TLS_DTPMOD32", Const, 0}, + {"R_386_TLS_DTPOFF32", Const, 0}, + {"R_386_TLS_GD", Const, 0}, + {"R_386_TLS_GD_32", Const, 0}, + {"R_386_TLS_GD_CALL", Const, 0}, + {"R_386_TLS_GD_POP", Const, 0}, + {"R_386_TLS_GD_PUSH", Const, 0}, + {"R_386_TLS_GOTDESC", Const, 10}, + {"R_386_TLS_GOTIE", Const, 0}, + {"R_386_TLS_IE", Const, 0}, + {"R_386_TLS_IE_32", Const, 0}, + {"R_386_TLS_LDM", Const, 0}, + {"R_386_TLS_LDM_32", Const, 0}, + {"R_386_TLS_LDM_CALL", Const, 0}, + {"R_386_TLS_LDM_POP", Const, 0}, + {"R_386_TLS_LDM_PUSH", Const, 0}, + {"R_386_TLS_LDO_32", Const, 0}, + {"R_386_TLS_LE", Const, 0}, + {"R_386_TLS_LE_32", Const, 0}, + {"R_386_TLS_TPOFF", Const, 0}, + {"R_386_TLS_TPOFF32", Const, 0}, + {"R_390", Type, 7}, + {"R_390_12", Const, 7}, + {"R_390_16", Const, 7}, + {"R_390_20", Const, 7}, + {"R_390_32", Const, 7}, + {"R_390_64", Const, 7}, + {"R_390_8", Const, 7}, + {"R_390_COPY", Const, 7}, + {"R_390_GLOB_DAT", Const, 7}, + {"R_390_GOT12", Const, 7}, + {"R_390_GOT16", Const, 7}, + {"R_390_GOT20", Const, 7}, + {"R_390_GOT32", Const, 7}, + {"R_390_GOT64", Const, 7}, + {"R_390_GOTENT", Const, 7}, + {"R_390_GOTOFF", Const, 7}, + {"R_390_GOTOFF16", Const, 7}, + {"R_390_GOTOFF64", Const, 7}, + {"R_390_GOTPC", Const, 7}, + {"R_390_GOTPCDBL", Const, 7}, + {"R_390_GOTPLT12", Const, 7}, + {"R_390_GOTPLT16", Const, 7}, + {"R_390_GOTPLT20", Const, 7}, + {"R_390_GOTPLT32", Const, 7}, + {"R_390_GOTPLT64", Const, 7}, + {"R_390_GOTPLTENT", Const, 7}, + {"R_390_GOTPLTOFF16", Const, 7}, + {"R_390_GOTPLTOFF32", Const, 7}, + {"R_390_GOTPLTOFF64", Const, 7}, + {"R_390_JMP_SLOT", Const, 7}, + {"R_390_NONE", Const, 7}, + {"R_390_PC16", Const, 7}, + {"R_390_PC16DBL", Const, 7}, + {"R_390_PC32", Const, 7}, + {"R_390_PC32DBL", Const, 7}, + {"R_390_PC64", Const, 7}, + {"R_390_PLT16DBL", Const, 7}, + {"R_390_PLT32", Const, 7}, + {"R_390_PLT32DBL", Const, 7}, + {"R_390_PLT64", Const, 7}, + {"R_390_RELATIVE", Const, 7}, + {"R_390_TLS_DTPMOD", Const, 7}, + {"R_390_TLS_DTPOFF", Const, 7}, + {"R_390_TLS_GD32", Const, 7}, + {"R_390_TLS_GD64", Const, 7}, + {"R_390_TLS_GDCALL", Const, 7}, + {"R_390_TLS_GOTIE12", Const, 7}, + {"R_390_TLS_GOTIE20", Const, 7}, + {"R_390_TLS_GOTIE32", Const, 7}, + {"R_390_TLS_GOTIE64", Const, 7}, + {"R_390_TLS_IE32", Const, 7}, + {"R_390_TLS_IE64", Const, 7}, + {"R_390_TLS_IEENT", Const, 7}, + {"R_390_TLS_LDCALL", Const, 7}, + {"R_390_TLS_LDM32", Const, 7}, + {"R_390_TLS_LDM64", Const, 7}, + {"R_390_TLS_LDO32", Const, 7}, + {"R_390_TLS_LDO64", Const, 7}, + {"R_390_TLS_LE32", Const, 7}, + {"R_390_TLS_LE64", Const, 7}, + {"R_390_TLS_LOAD", Const, 7}, + {"R_390_TLS_TPOFF", Const, 7}, + {"R_AARCH64", Type, 4}, + {"R_AARCH64_ABS16", Const, 4}, + {"R_AARCH64_ABS32", Const, 4}, + {"R_AARCH64_ABS64", Const, 4}, + {"R_AARCH64_ADD_ABS_LO12_NC", Const, 4}, + {"R_AARCH64_ADR_GOT_PAGE", Const, 4}, + {"R_AARCH64_ADR_PREL_LO21", Const, 4}, + {"R_AARCH64_ADR_PREL_PG_HI21", Const, 4}, + {"R_AARCH64_ADR_PREL_PG_HI21_NC", Const, 4}, + {"R_AARCH64_CALL26", Const, 4}, + {"R_AARCH64_CONDBR19", Const, 4}, + {"R_AARCH64_COPY", Const, 4}, + {"R_AARCH64_GLOB_DAT", Const, 4}, + {"R_AARCH64_GOT_LD_PREL19", Const, 4}, + {"R_AARCH64_IRELATIVE", Const, 4}, + {"R_AARCH64_JUMP26", Const, 4}, + {"R_AARCH64_JUMP_SLOT", Const, 4}, + {"R_AARCH64_LD64_GOTOFF_LO15", Const, 10}, + {"R_AARCH64_LD64_GOTPAGE_LO15", Const, 10}, + {"R_AARCH64_LD64_GOT_LO12_NC", Const, 4}, + {"R_AARCH64_LDST128_ABS_LO12_NC", Const, 4}, + {"R_AARCH64_LDST16_ABS_LO12_NC", Const, 4}, + {"R_AARCH64_LDST32_ABS_LO12_NC", Const, 4}, + {"R_AARCH64_LDST64_ABS_LO12_NC", Const, 4}, + {"R_AARCH64_LDST8_ABS_LO12_NC", Const, 4}, + {"R_AARCH64_LD_PREL_LO19", Const, 4}, + {"R_AARCH64_MOVW_SABS_G0", Const, 4}, + {"R_AARCH64_MOVW_SABS_G1", Const, 4}, + {"R_AARCH64_MOVW_SABS_G2", Const, 4}, + {"R_AARCH64_MOVW_UABS_G0", Const, 4}, + {"R_AARCH64_MOVW_UABS_G0_NC", Const, 4}, + {"R_AARCH64_MOVW_UABS_G1", Const, 4}, + {"R_AARCH64_MOVW_UABS_G1_NC", Const, 4}, + {"R_AARCH64_MOVW_UABS_G2", Const, 4}, + {"R_AARCH64_MOVW_UABS_G2_NC", Const, 4}, + {"R_AARCH64_MOVW_UABS_G3", Const, 4}, + {"R_AARCH64_NONE", Const, 4}, + {"R_AARCH64_NULL", Const, 4}, + {"R_AARCH64_P32_ABS16", Const, 4}, + {"R_AARCH64_P32_ABS32", Const, 4}, + {"R_AARCH64_P32_ADD_ABS_LO12_NC", Const, 4}, + {"R_AARCH64_P32_ADR_GOT_PAGE", Const, 4}, + {"R_AARCH64_P32_ADR_PREL_LO21", Const, 4}, + {"R_AARCH64_P32_ADR_PREL_PG_HI21", Const, 4}, + {"R_AARCH64_P32_CALL26", Const, 4}, + {"R_AARCH64_P32_CONDBR19", Const, 4}, + {"R_AARCH64_P32_COPY", Const, 4}, + {"R_AARCH64_P32_GLOB_DAT", Const, 4}, + {"R_AARCH64_P32_GOT_LD_PREL19", Const, 4}, + {"R_AARCH64_P32_IRELATIVE", Const, 4}, + {"R_AARCH64_P32_JUMP26", Const, 4}, + {"R_AARCH64_P32_JUMP_SLOT", Const, 4}, + {"R_AARCH64_P32_LD32_GOT_LO12_NC", Const, 4}, + {"R_AARCH64_P32_LDST128_ABS_LO12_NC", Const, 4}, + {"R_AARCH64_P32_LDST16_ABS_LO12_NC", Const, 4}, + {"R_AARCH64_P32_LDST32_ABS_LO12_NC", Const, 4}, + {"R_AARCH64_P32_LDST64_ABS_LO12_NC", Const, 4}, + {"R_AARCH64_P32_LDST8_ABS_LO12_NC", Const, 4}, + {"R_AARCH64_P32_LD_PREL_LO19", Const, 4}, + {"R_AARCH64_P32_MOVW_SABS_G0", Const, 4}, + {"R_AARCH64_P32_MOVW_UABS_G0", Const, 4}, + {"R_AARCH64_P32_MOVW_UABS_G0_NC", Const, 4}, + {"R_AARCH64_P32_MOVW_UABS_G1", Const, 4}, + {"R_AARCH64_P32_PREL16", Const, 4}, + {"R_AARCH64_P32_PREL32", Const, 4}, + {"R_AARCH64_P32_RELATIVE", Const, 4}, + {"R_AARCH64_P32_TLSDESC", Const, 4}, + {"R_AARCH64_P32_TLSDESC_ADD_LO12_NC", Const, 4}, + {"R_AARCH64_P32_TLSDESC_ADR_PAGE21", Const, 4}, + {"R_AARCH64_P32_TLSDESC_ADR_PREL21", Const, 4}, + {"R_AARCH64_P32_TLSDESC_CALL", Const, 4}, + {"R_AARCH64_P32_TLSDESC_LD32_LO12_NC", Const, 4}, + {"R_AARCH64_P32_TLSDESC_LD_PREL19", Const, 4}, + {"R_AARCH64_P32_TLSGD_ADD_LO12_NC", Const, 4}, + {"R_AARCH64_P32_TLSGD_ADR_PAGE21", Const, 4}, + {"R_AARCH64_P32_TLSIE_ADR_GOTTPREL_PAGE21", Const, 4}, + {"R_AARCH64_P32_TLSIE_LD32_GOTTPREL_LO12_NC", Const, 4}, + {"R_AARCH64_P32_TLSIE_LD_GOTTPREL_PREL19", Const, 4}, + {"R_AARCH64_P32_TLSLE_ADD_TPREL_HI12", Const, 4}, + {"R_AARCH64_P32_TLSLE_ADD_TPREL_LO12", Const, 4}, + {"R_AARCH64_P32_TLSLE_ADD_TPREL_LO12_NC", Const, 4}, + {"R_AARCH64_P32_TLSLE_MOVW_TPREL_G0", Const, 4}, + {"R_AARCH64_P32_TLSLE_MOVW_TPREL_G0_NC", Const, 4}, + {"R_AARCH64_P32_TLSLE_MOVW_TPREL_G1", Const, 4}, + {"R_AARCH64_P32_TLS_DTPMOD", Const, 4}, + {"R_AARCH64_P32_TLS_DTPREL", Const, 4}, + {"R_AARCH64_P32_TLS_TPREL", Const, 4}, + {"R_AARCH64_P32_TSTBR14", Const, 4}, + {"R_AARCH64_PREL16", Const, 4}, + {"R_AARCH64_PREL32", Const, 4}, + {"R_AARCH64_PREL64", Const, 4}, + {"R_AARCH64_RELATIVE", Const, 4}, + {"R_AARCH64_TLSDESC", Const, 4}, + {"R_AARCH64_TLSDESC_ADD", Const, 4}, + {"R_AARCH64_TLSDESC_ADD_LO12_NC", Const, 4}, + {"R_AARCH64_TLSDESC_ADR_PAGE21", Const, 4}, + {"R_AARCH64_TLSDESC_ADR_PREL21", Const, 4}, + {"R_AARCH64_TLSDESC_CALL", Const, 4}, + {"R_AARCH64_TLSDESC_LD64_LO12_NC", Const, 4}, + {"R_AARCH64_TLSDESC_LDR", Const, 4}, + {"R_AARCH64_TLSDESC_LD_PREL19", Const, 4}, + {"R_AARCH64_TLSDESC_OFF_G0_NC", Const, 4}, + {"R_AARCH64_TLSDESC_OFF_G1", Const, 4}, + {"R_AARCH64_TLSGD_ADD_LO12_NC", Const, 4}, + {"R_AARCH64_TLSGD_ADR_PAGE21", Const, 4}, + {"R_AARCH64_TLSGD_ADR_PREL21", Const, 10}, + {"R_AARCH64_TLSGD_MOVW_G0_NC", Const, 10}, + {"R_AARCH64_TLSGD_MOVW_G1", Const, 10}, + {"R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21", Const, 4}, + {"R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC", Const, 4}, + {"R_AARCH64_TLSIE_LD_GOTTPREL_PREL19", Const, 4}, + {"R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC", Const, 4}, + {"R_AARCH64_TLSIE_MOVW_GOTTPREL_G1", Const, 4}, + {"R_AARCH64_TLSLD_ADR_PAGE21", Const, 10}, + {"R_AARCH64_TLSLD_ADR_PREL21", Const, 10}, + {"R_AARCH64_TLSLD_LDST128_DTPREL_LO12", Const, 10}, + {"R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC", Const, 10}, + {"R_AARCH64_TLSLE_ADD_TPREL_HI12", Const, 4}, + {"R_AARCH64_TLSLE_ADD_TPREL_LO12", Const, 4}, + {"R_AARCH64_TLSLE_ADD_TPREL_LO12_NC", Const, 4}, + {"R_AARCH64_TLSLE_LDST128_TPREL_LO12", Const, 10}, + {"R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC", Const, 10}, + {"R_AARCH64_TLSLE_MOVW_TPREL_G0", Const, 4}, + {"R_AARCH64_TLSLE_MOVW_TPREL_G0_NC", Const, 4}, + {"R_AARCH64_TLSLE_MOVW_TPREL_G1", Const, 4}, + {"R_AARCH64_TLSLE_MOVW_TPREL_G1_NC", Const, 4}, + {"R_AARCH64_TLSLE_MOVW_TPREL_G2", Const, 4}, + {"R_AARCH64_TLS_DTPMOD64", Const, 4}, + {"R_AARCH64_TLS_DTPREL64", Const, 4}, + {"R_AARCH64_TLS_TPREL64", Const, 4}, + {"R_AARCH64_TSTBR14", Const, 4}, + {"R_ALPHA", Type, 0}, + {"R_ALPHA_BRADDR", Const, 0}, + {"R_ALPHA_COPY", Const, 0}, + {"R_ALPHA_GLOB_DAT", Const, 0}, + {"R_ALPHA_GPDISP", Const, 0}, + {"R_ALPHA_GPREL32", Const, 0}, + {"R_ALPHA_GPRELHIGH", Const, 0}, + {"R_ALPHA_GPRELLOW", Const, 0}, + {"R_ALPHA_GPVALUE", Const, 0}, + {"R_ALPHA_HINT", Const, 0}, + {"R_ALPHA_IMMED_BR_HI32", Const, 0}, + {"R_ALPHA_IMMED_GP_16", Const, 0}, + {"R_ALPHA_IMMED_GP_HI32", Const, 0}, + {"R_ALPHA_IMMED_LO32", Const, 0}, + {"R_ALPHA_IMMED_SCN_HI32", Const, 0}, + {"R_ALPHA_JMP_SLOT", Const, 0}, + {"R_ALPHA_LITERAL", Const, 0}, + {"R_ALPHA_LITUSE", Const, 0}, + {"R_ALPHA_NONE", Const, 0}, + {"R_ALPHA_OP_PRSHIFT", Const, 0}, + {"R_ALPHA_OP_PSUB", Const, 0}, + {"R_ALPHA_OP_PUSH", Const, 0}, + {"R_ALPHA_OP_STORE", Const, 0}, + {"R_ALPHA_REFLONG", Const, 0}, + {"R_ALPHA_REFQUAD", Const, 0}, + {"R_ALPHA_RELATIVE", Const, 0}, + {"R_ALPHA_SREL16", Const, 0}, + {"R_ALPHA_SREL32", Const, 0}, + {"R_ALPHA_SREL64", Const, 0}, + {"R_ARM", Type, 0}, + {"R_ARM_ABS12", Const, 0}, + {"R_ARM_ABS16", Const, 0}, + {"R_ARM_ABS32", Const, 0}, + {"R_ARM_ABS32_NOI", Const, 10}, + {"R_ARM_ABS8", Const, 0}, + {"R_ARM_ALU_PCREL_15_8", Const, 10}, + {"R_ARM_ALU_PCREL_23_15", Const, 10}, + {"R_ARM_ALU_PCREL_7_0", Const, 10}, + {"R_ARM_ALU_PC_G0", Const, 10}, + {"R_ARM_ALU_PC_G0_NC", Const, 10}, + {"R_ARM_ALU_PC_G1", Const, 10}, + {"R_ARM_ALU_PC_G1_NC", Const, 10}, + {"R_ARM_ALU_PC_G2", Const, 10}, + {"R_ARM_ALU_SBREL_19_12_NC", Const, 10}, + {"R_ARM_ALU_SBREL_27_20_CK", Const, 10}, + {"R_ARM_ALU_SB_G0", Const, 10}, + {"R_ARM_ALU_SB_G0_NC", Const, 10}, + {"R_ARM_ALU_SB_G1", Const, 10}, + {"R_ARM_ALU_SB_G1_NC", Const, 10}, + {"R_ARM_ALU_SB_G2", Const, 10}, + {"R_ARM_AMP_VCALL9", Const, 0}, + {"R_ARM_BASE_ABS", Const, 10}, + {"R_ARM_CALL", Const, 10}, + {"R_ARM_COPY", Const, 0}, + {"R_ARM_GLOB_DAT", Const, 0}, + {"R_ARM_GNU_VTENTRY", Const, 0}, + {"R_ARM_GNU_VTINHERIT", Const, 0}, + {"R_ARM_GOT32", Const, 0}, + {"R_ARM_GOTOFF", Const, 0}, + {"R_ARM_GOTOFF12", Const, 10}, + {"R_ARM_GOTPC", Const, 0}, + {"R_ARM_GOTRELAX", Const, 10}, + {"R_ARM_GOT_ABS", Const, 10}, + {"R_ARM_GOT_BREL12", Const, 10}, + {"R_ARM_GOT_PREL", Const, 10}, + {"R_ARM_IRELATIVE", Const, 10}, + {"R_ARM_JUMP24", Const, 10}, + {"R_ARM_JUMP_SLOT", Const, 0}, + {"R_ARM_LDC_PC_G0", Const, 10}, + {"R_ARM_LDC_PC_G1", Const, 10}, + {"R_ARM_LDC_PC_G2", Const, 10}, + {"R_ARM_LDC_SB_G0", Const, 10}, + {"R_ARM_LDC_SB_G1", Const, 10}, + {"R_ARM_LDC_SB_G2", Const, 10}, + {"R_ARM_LDRS_PC_G0", Const, 10}, + {"R_ARM_LDRS_PC_G1", Const, 10}, + {"R_ARM_LDRS_PC_G2", Const, 10}, + {"R_ARM_LDRS_SB_G0", Const, 10}, + {"R_ARM_LDRS_SB_G1", Const, 10}, + {"R_ARM_LDRS_SB_G2", Const, 10}, + {"R_ARM_LDR_PC_G1", Const, 10}, + {"R_ARM_LDR_PC_G2", Const, 10}, + {"R_ARM_LDR_SBREL_11_10_NC", Const, 10}, + {"R_ARM_LDR_SB_G0", Const, 10}, + {"R_ARM_LDR_SB_G1", Const, 10}, + {"R_ARM_LDR_SB_G2", Const, 10}, + {"R_ARM_ME_TOO", Const, 10}, + {"R_ARM_MOVT_ABS", Const, 10}, + {"R_ARM_MOVT_BREL", Const, 10}, + {"R_ARM_MOVT_PREL", Const, 10}, + {"R_ARM_MOVW_ABS_NC", Const, 10}, + {"R_ARM_MOVW_BREL", Const, 10}, + {"R_ARM_MOVW_BREL_NC", Const, 10}, + {"R_ARM_MOVW_PREL_NC", Const, 10}, + {"R_ARM_NONE", Const, 0}, + {"R_ARM_PC13", Const, 0}, + {"R_ARM_PC24", Const, 0}, + {"R_ARM_PLT32", Const, 0}, + {"R_ARM_PLT32_ABS", Const, 10}, + {"R_ARM_PREL31", Const, 10}, + {"R_ARM_PRIVATE_0", Const, 10}, + {"R_ARM_PRIVATE_1", Const, 10}, + {"R_ARM_PRIVATE_10", Const, 10}, + {"R_ARM_PRIVATE_11", Const, 10}, + {"R_ARM_PRIVATE_12", Const, 10}, + {"R_ARM_PRIVATE_13", Const, 10}, + {"R_ARM_PRIVATE_14", Const, 10}, + {"R_ARM_PRIVATE_15", Const, 10}, + {"R_ARM_PRIVATE_2", Const, 10}, + {"R_ARM_PRIVATE_3", Const, 10}, + {"R_ARM_PRIVATE_4", Const, 10}, + {"R_ARM_PRIVATE_5", Const, 10}, + {"R_ARM_PRIVATE_6", Const, 10}, + {"R_ARM_PRIVATE_7", Const, 10}, + {"R_ARM_PRIVATE_8", Const, 10}, + {"R_ARM_PRIVATE_9", Const, 10}, + {"R_ARM_RABS32", Const, 0}, + {"R_ARM_RBASE", Const, 0}, + {"R_ARM_REL32", Const, 0}, + {"R_ARM_REL32_NOI", Const, 10}, + {"R_ARM_RELATIVE", Const, 0}, + {"R_ARM_RPC24", Const, 0}, + {"R_ARM_RREL32", Const, 0}, + {"R_ARM_RSBREL32", Const, 0}, + {"R_ARM_RXPC25", Const, 10}, + {"R_ARM_SBREL31", Const, 10}, + {"R_ARM_SBREL32", Const, 0}, + {"R_ARM_SWI24", Const, 0}, + {"R_ARM_TARGET1", Const, 10}, + {"R_ARM_TARGET2", Const, 10}, + {"R_ARM_THM_ABS5", Const, 0}, + {"R_ARM_THM_ALU_ABS_G0_NC", Const, 10}, + {"R_ARM_THM_ALU_ABS_G1_NC", Const, 10}, + {"R_ARM_THM_ALU_ABS_G2_NC", Const, 10}, + {"R_ARM_THM_ALU_ABS_G3", Const, 10}, + {"R_ARM_THM_ALU_PREL_11_0", Const, 10}, + {"R_ARM_THM_GOT_BREL12", Const, 10}, + {"R_ARM_THM_JUMP11", Const, 10}, + {"R_ARM_THM_JUMP19", Const, 10}, + {"R_ARM_THM_JUMP24", Const, 10}, + {"R_ARM_THM_JUMP6", Const, 10}, + {"R_ARM_THM_JUMP8", Const, 10}, + {"R_ARM_THM_MOVT_ABS", Const, 10}, + {"R_ARM_THM_MOVT_BREL", Const, 10}, + {"R_ARM_THM_MOVT_PREL", Const, 10}, + {"R_ARM_THM_MOVW_ABS_NC", Const, 10}, + {"R_ARM_THM_MOVW_BREL", Const, 10}, + {"R_ARM_THM_MOVW_BREL_NC", Const, 10}, + {"R_ARM_THM_MOVW_PREL_NC", Const, 10}, + {"R_ARM_THM_PC12", Const, 10}, + {"R_ARM_THM_PC22", Const, 0}, + {"R_ARM_THM_PC8", Const, 0}, + {"R_ARM_THM_RPC22", Const, 0}, + {"R_ARM_THM_SWI8", Const, 0}, + {"R_ARM_THM_TLS_CALL", Const, 10}, + {"R_ARM_THM_TLS_DESCSEQ16", Const, 10}, + {"R_ARM_THM_TLS_DESCSEQ32", Const, 10}, + {"R_ARM_THM_XPC22", Const, 0}, + {"R_ARM_TLS_CALL", Const, 10}, + {"R_ARM_TLS_DESCSEQ", Const, 10}, + {"R_ARM_TLS_DTPMOD32", Const, 10}, + {"R_ARM_TLS_DTPOFF32", Const, 10}, + {"R_ARM_TLS_GD32", Const, 10}, + {"R_ARM_TLS_GOTDESC", Const, 10}, + {"R_ARM_TLS_IE12GP", Const, 10}, + {"R_ARM_TLS_IE32", Const, 10}, + {"R_ARM_TLS_LDM32", Const, 10}, + {"R_ARM_TLS_LDO12", Const, 10}, + {"R_ARM_TLS_LDO32", Const, 10}, + {"R_ARM_TLS_LE12", Const, 10}, + {"R_ARM_TLS_LE32", Const, 10}, + {"R_ARM_TLS_TPOFF32", Const, 10}, + {"R_ARM_V4BX", Const, 10}, + {"R_ARM_XPC25", Const, 0}, + {"R_INFO", Func, 0}, + {"R_INFO32", Func, 0}, + {"R_LARCH", Type, 19}, + {"R_LARCH_32", Const, 19}, + {"R_LARCH_32_PCREL", Const, 20}, + {"R_LARCH_64", Const, 19}, + {"R_LARCH_64_PCREL", Const, 22}, + {"R_LARCH_ABS64_HI12", Const, 20}, + {"R_LARCH_ABS64_LO20", Const, 20}, + {"R_LARCH_ABS_HI20", Const, 20}, + {"R_LARCH_ABS_LO12", Const, 20}, + {"R_LARCH_ADD16", Const, 19}, + {"R_LARCH_ADD24", Const, 19}, + {"R_LARCH_ADD32", Const, 19}, + {"R_LARCH_ADD6", Const, 22}, + {"R_LARCH_ADD64", Const, 19}, + {"R_LARCH_ADD8", Const, 19}, + {"R_LARCH_ADD_ULEB128", Const, 22}, + {"R_LARCH_ALIGN", Const, 22}, + {"R_LARCH_B16", Const, 20}, + {"R_LARCH_B21", Const, 20}, + {"R_LARCH_B26", Const, 20}, + {"R_LARCH_CFA", Const, 22}, + {"R_LARCH_COPY", Const, 19}, + {"R_LARCH_DELETE", Const, 22}, + {"R_LARCH_GNU_VTENTRY", Const, 20}, + {"R_LARCH_GNU_VTINHERIT", Const, 20}, + {"R_LARCH_GOT64_HI12", Const, 20}, + {"R_LARCH_GOT64_LO20", Const, 20}, + {"R_LARCH_GOT64_PC_HI12", Const, 20}, + {"R_LARCH_GOT64_PC_LO20", Const, 20}, + {"R_LARCH_GOT_HI20", Const, 20}, + {"R_LARCH_GOT_LO12", Const, 20}, + {"R_LARCH_GOT_PC_HI20", Const, 20}, + {"R_LARCH_GOT_PC_LO12", Const, 20}, + {"R_LARCH_IRELATIVE", Const, 19}, + {"R_LARCH_JUMP_SLOT", Const, 19}, + {"R_LARCH_MARK_LA", Const, 19}, + {"R_LARCH_MARK_PCREL", Const, 19}, + {"R_LARCH_NONE", Const, 19}, + {"R_LARCH_PCALA64_HI12", Const, 20}, + {"R_LARCH_PCALA64_LO20", Const, 20}, + {"R_LARCH_PCALA_HI20", Const, 20}, + {"R_LARCH_PCALA_LO12", Const, 20}, + {"R_LARCH_PCREL20_S2", Const, 22}, + {"R_LARCH_RELATIVE", Const, 19}, + {"R_LARCH_RELAX", Const, 20}, + {"R_LARCH_SOP_ADD", Const, 19}, + {"R_LARCH_SOP_AND", Const, 19}, + {"R_LARCH_SOP_ASSERT", Const, 19}, + {"R_LARCH_SOP_IF_ELSE", Const, 19}, + {"R_LARCH_SOP_NOT", Const, 19}, + {"R_LARCH_SOP_POP_32_S_0_10_10_16_S2", Const, 19}, + {"R_LARCH_SOP_POP_32_S_0_5_10_16_S2", Const, 19}, + {"R_LARCH_SOP_POP_32_S_10_12", Const, 19}, + {"R_LARCH_SOP_POP_32_S_10_16", Const, 19}, + {"R_LARCH_SOP_POP_32_S_10_16_S2", Const, 19}, + {"R_LARCH_SOP_POP_32_S_10_5", Const, 19}, + {"R_LARCH_SOP_POP_32_S_5_20", Const, 19}, + {"R_LARCH_SOP_POP_32_U", Const, 19}, + {"R_LARCH_SOP_POP_32_U_10_12", Const, 19}, + {"R_LARCH_SOP_PUSH_ABSOLUTE", Const, 19}, + {"R_LARCH_SOP_PUSH_DUP", Const, 19}, + {"R_LARCH_SOP_PUSH_GPREL", Const, 19}, + {"R_LARCH_SOP_PUSH_PCREL", Const, 19}, + {"R_LARCH_SOP_PUSH_PLT_PCREL", Const, 19}, + {"R_LARCH_SOP_PUSH_TLS_GD", Const, 19}, + {"R_LARCH_SOP_PUSH_TLS_GOT", Const, 19}, + {"R_LARCH_SOP_PUSH_TLS_TPREL", Const, 19}, + {"R_LARCH_SOP_SL", Const, 19}, + {"R_LARCH_SOP_SR", Const, 19}, + {"R_LARCH_SOP_SUB", Const, 19}, + {"R_LARCH_SUB16", Const, 19}, + {"R_LARCH_SUB24", Const, 19}, + {"R_LARCH_SUB32", Const, 19}, + {"R_LARCH_SUB6", Const, 22}, + {"R_LARCH_SUB64", Const, 19}, + {"R_LARCH_SUB8", Const, 19}, + {"R_LARCH_SUB_ULEB128", Const, 22}, + {"R_LARCH_TLS_DTPMOD32", Const, 19}, + {"R_LARCH_TLS_DTPMOD64", Const, 19}, + {"R_LARCH_TLS_DTPREL32", Const, 19}, + {"R_LARCH_TLS_DTPREL64", Const, 19}, + {"R_LARCH_TLS_GD_HI20", Const, 20}, + {"R_LARCH_TLS_GD_PC_HI20", Const, 20}, + {"R_LARCH_TLS_IE64_HI12", Const, 20}, + {"R_LARCH_TLS_IE64_LO20", Const, 20}, + {"R_LARCH_TLS_IE64_PC_HI12", Const, 20}, + {"R_LARCH_TLS_IE64_PC_LO20", Const, 20}, + {"R_LARCH_TLS_IE_HI20", Const, 20}, + {"R_LARCH_TLS_IE_LO12", Const, 20}, + {"R_LARCH_TLS_IE_PC_HI20", Const, 20}, + {"R_LARCH_TLS_IE_PC_LO12", Const, 20}, + {"R_LARCH_TLS_LD_HI20", Const, 20}, + {"R_LARCH_TLS_LD_PC_HI20", Const, 20}, + {"R_LARCH_TLS_LE64_HI12", Const, 20}, + {"R_LARCH_TLS_LE64_LO20", Const, 20}, + {"R_LARCH_TLS_LE_HI20", Const, 20}, + {"R_LARCH_TLS_LE_LO12", Const, 20}, + {"R_LARCH_TLS_TPREL32", Const, 19}, + {"R_LARCH_TLS_TPREL64", Const, 19}, + {"R_MIPS", Type, 6}, + {"R_MIPS_16", Const, 6}, + {"R_MIPS_26", Const, 6}, + {"R_MIPS_32", Const, 6}, + {"R_MIPS_64", Const, 6}, + {"R_MIPS_ADD_IMMEDIATE", Const, 6}, + {"R_MIPS_CALL16", Const, 6}, + {"R_MIPS_CALL_HI16", Const, 6}, + {"R_MIPS_CALL_LO16", Const, 6}, + {"R_MIPS_DELETE", Const, 6}, + {"R_MIPS_GOT16", Const, 6}, + {"R_MIPS_GOT_DISP", Const, 6}, + {"R_MIPS_GOT_HI16", Const, 6}, + {"R_MIPS_GOT_LO16", Const, 6}, + {"R_MIPS_GOT_OFST", Const, 6}, + {"R_MIPS_GOT_PAGE", Const, 6}, + {"R_MIPS_GPREL16", Const, 6}, + {"R_MIPS_GPREL32", Const, 6}, + {"R_MIPS_HI16", Const, 6}, + {"R_MIPS_HIGHER", Const, 6}, + {"R_MIPS_HIGHEST", Const, 6}, + {"R_MIPS_INSERT_A", Const, 6}, + {"R_MIPS_INSERT_B", Const, 6}, + {"R_MIPS_JALR", Const, 6}, + {"R_MIPS_LITERAL", Const, 6}, + {"R_MIPS_LO16", Const, 6}, + {"R_MIPS_NONE", Const, 6}, + {"R_MIPS_PC16", Const, 6}, + {"R_MIPS_PC32", Const, 22}, + {"R_MIPS_PJUMP", Const, 6}, + {"R_MIPS_REL16", Const, 6}, + {"R_MIPS_REL32", Const, 6}, + {"R_MIPS_RELGOT", Const, 6}, + {"R_MIPS_SCN_DISP", Const, 6}, + {"R_MIPS_SHIFT5", Const, 6}, + {"R_MIPS_SHIFT6", Const, 6}, + {"R_MIPS_SUB", Const, 6}, + {"R_MIPS_TLS_DTPMOD32", Const, 6}, + {"R_MIPS_TLS_DTPMOD64", Const, 6}, + {"R_MIPS_TLS_DTPREL32", Const, 6}, + {"R_MIPS_TLS_DTPREL64", Const, 6}, + {"R_MIPS_TLS_DTPREL_HI16", Const, 6}, + {"R_MIPS_TLS_DTPREL_LO16", Const, 6}, + {"R_MIPS_TLS_GD", Const, 6}, + {"R_MIPS_TLS_GOTTPREL", Const, 6}, + {"R_MIPS_TLS_LDM", Const, 6}, + {"R_MIPS_TLS_TPREL32", Const, 6}, + {"R_MIPS_TLS_TPREL64", Const, 6}, + {"R_MIPS_TLS_TPREL_HI16", Const, 6}, + {"R_MIPS_TLS_TPREL_LO16", Const, 6}, + {"R_PPC", Type, 0}, + {"R_PPC64", Type, 5}, + {"R_PPC64_ADDR14", Const, 5}, + {"R_PPC64_ADDR14_BRNTAKEN", Const, 5}, + {"R_PPC64_ADDR14_BRTAKEN", Const, 5}, + {"R_PPC64_ADDR16", Const, 5}, + {"R_PPC64_ADDR16_DS", Const, 5}, + {"R_PPC64_ADDR16_HA", Const, 5}, + {"R_PPC64_ADDR16_HI", Const, 5}, + {"R_PPC64_ADDR16_HIGH", Const, 10}, + {"R_PPC64_ADDR16_HIGHA", Const, 10}, + {"R_PPC64_ADDR16_HIGHER", Const, 5}, + {"R_PPC64_ADDR16_HIGHER34", Const, 20}, + {"R_PPC64_ADDR16_HIGHERA", Const, 5}, + {"R_PPC64_ADDR16_HIGHERA34", Const, 20}, + {"R_PPC64_ADDR16_HIGHEST", Const, 5}, + {"R_PPC64_ADDR16_HIGHEST34", Const, 20}, + {"R_PPC64_ADDR16_HIGHESTA", Const, 5}, + {"R_PPC64_ADDR16_HIGHESTA34", Const, 20}, + {"R_PPC64_ADDR16_LO", Const, 5}, + {"R_PPC64_ADDR16_LO_DS", Const, 5}, + {"R_PPC64_ADDR24", Const, 5}, + {"R_PPC64_ADDR32", Const, 5}, + {"R_PPC64_ADDR64", Const, 5}, + {"R_PPC64_ADDR64_LOCAL", Const, 10}, + {"R_PPC64_COPY", Const, 20}, + {"R_PPC64_D28", Const, 20}, + {"R_PPC64_D34", Const, 20}, + {"R_PPC64_D34_HA30", Const, 20}, + {"R_PPC64_D34_HI30", Const, 20}, + {"R_PPC64_D34_LO", Const, 20}, + {"R_PPC64_DTPMOD64", Const, 5}, + {"R_PPC64_DTPREL16", Const, 5}, + {"R_PPC64_DTPREL16_DS", Const, 5}, + {"R_PPC64_DTPREL16_HA", Const, 5}, + {"R_PPC64_DTPREL16_HI", Const, 5}, + {"R_PPC64_DTPREL16_HIGH", Const, 10}, + {"R_PPC64_DTPREL16_HIGHA", Const, 10}, + {"R_PPC64_DTPREL16_HIGHER", Const, 5}, + {"R_PPC64_DTPREL16_HIGHERA", Const, 5}, + {"R_PPC64_DTPREL16_HIGHEST", Const, 5}, + {"R_PPC64_DTPREL16_HIGHESTA", Const, 5}, + {"R_PPC64_DTPREL16_LO", Const, 5}, + {"R_PPC64_DTPREL16_LO_DS", Const, 5}, + {"R_PPC64_DTPREL34", Const, 20}, + {"R_PPC64_DTPREL64", Const, 5}, + {"R_PPC64_ENTRY", Const, 10}, + {"R_PPC64_GLOB_DAT", Const, 20}, + {"R_PPC64_GNU_VTENTRY", Const, 20}, + {"R_PPC64_GNU_VTINHERIT", Const, 20}, + {"R_PPC64_GOT16", Const, 5}, + {"R_PPC64_GOT16_DS", Const, 5}, + {"R_PPC64_GOT16_HA", Const, 5}, + {"R_PPC64_GOT16_HI", Const, 5}, + {"R_PPC64_GOT16_LO", Const, 5}, + {"R_PPC64_GOT16_LO_DS", Const, 5}, + {"R_PPC64_GOT_DTPREL16_DS", Const, 5}, + {"R_PPC64_GOT_DTPREL16_HA", Const, 5}, + {"R_PPC64_GOT_DTPREL16_HI", Const, 5}, + {"R_PPC64_GOT_DTPREL16_LO_DS", Const, 5}, + {"R_PPC64_GOT_DTPREL_PCREL34", Const, 20}, + {"R_PPC64_GOT_PCREL34", Const, 20}, + {"R_PPC64_GOT_TLSGD16", Const, 5}, + {"R_PPC64_GOT_TLSGD16_HA", Const, 5}, + {"R_PPC64_GOT_TLSGD16_HI", Const, 5}, + {"R_PPC64_GOT_TLSGD16_LO", Const, 5}, + {"R_PPC64_GOT_TLSGD_PCREL34", Const, 20}, + {"R_PPC64_GOT_TLSLD16", Const, 5}, + {"R_PPC64_GOT_TLSLD16_HA", Const, 5}, + {"R_PPC64_GOT_TLSLD16_HI", Const, 5}, + {"R_PPC64_GOT_TLSLD16_LO", Const, 5}, + {"R_PPC64_GOT_TLSLD_PCREL34", Const, 20}, + {"R_PPC64_GOT_TPREL16_DS", Const, 5}, + {"R_PPC64_GOT_TPREL16_HA", Const, 5}, + {"R_PPC64_GOT_TPREL16_HI", Const, 5}, + {"R_PPC64_GOT_TPREL16_LO_DS", Const, 5}, + {"R_PPC64_GOT_TPREL_PCREL34", Const, 20}, + {"R_PPC64_IRELATIVE", Const, 10}, + {"R_PPC64_JMP_IREL", Const, 10}, + {"R_PPC64_JMP_SLOT", Const, 5}, + {"R_PPC64_NONE", Const, 5}, + {"R_PPC64_PCREL28", Const, 20}, + {"R_PPC64_PCREL34", Const, 20}, + {"R_PPC64_PCREL_OPT", Const, 20}, + {"R_PPC64_PLT16_HA", Const, 20}, + {"R_PPC64_PLT16_HI", Const, 20}, + {"R_PPC64_PLT16_LO", Const, 20}, + {"R_PPC64_PLT16_LO_DS", Const, 10}, + {"R_PPC64_PLT32", Const, 20}, + {"R_PPC64_PLT64", Const, 20}, + {"R_PPC64_PLTCALL", Const, 20}, + {"R_PPC64_PLTCALL_NOTOC", Const, 20}, + {"R_PPC64_PLTGOT16", Const, 10}, + {"R_PPC64_PLTGOT16_DS", Const, 10}, + {"R_PPC64_PLTGOT16_HA", Const, 10}, + {"R_PPC64_PLTGOT16_HI", Const, 10}, + {"R_PPC64_PLTGOT16_LO", Const, 10}, + {"R_PPC64_PLTGOT_LO_DS", Const, 10}, + {"R_PPC64_PLTREL32", Const, 20}, + {"R_PPC64_PLTREL64", Const, 20}, + {"R_PPC64_PLTSEQ", Const, 20}, + {"R_PPC64_PLTSEQ_NOTOC", Const, 20}, + {"R_PPC64_PLT_PCREL34", Const, 20}, + {"R_PPC64_PLT_PCREL34_NOTOC", Const, 20}, + {"R_PPC64_REL14", Const, 5}, + {"R_PPC64_REL14_BRNTAKEN", Const, 5}, + {"R_PPC64_REL14_BRTAKEN", Const, 5}, + {"R_PPC64_REL16", Const, 5}, + {"R_PPC64_REL16DX_HA", Const, 10}, + {"R_PPC64_REL16_HA", Const, 5}, + {"R_PPC64_REL16_HI", Const, 5}, + {"R_PPC64_REL16_HIGH", Const, 20}, + {"R_PPC64_REL16_HIGHA", Const, 20}, + {"R_PPC64_REL16_HIGHER", Const, 20}, + {"R_PPC64_REL16_HIGHER34", Const, 20}, + {"R_PPC64_REL16_HIGHERA", Const, 20}, + {"R_PPC64_REL16_HIGHERA34", Const, 20}, + {"R_PPC64_REL16_HIGHEST", Const, 20}, + {"R_PPC64_REL16_HIGHEST34", Const, 20}, + {"R_PPC64_REL16_HIGHESTA", Const, 20}, + {"R_PPC64_REL16_HIGHESTA34", Const, 20}, + {"R_PPC64_REL16_LO", Const, 5}, + {"R_PPC64_REL24", Const, 5}, + {"R_PPC64_REL24_NOTOC", Const, 10}, + {"R_PPC64_REL24_P9NOTOC", Const, 21}, + {"R_PPC64_REL30", Const, 20}, + {"R_PPC64_REL32", Const, 5}, + {"R_PPC64_REL64", Const, 5}, + {"R_PPC64_RELATIVE", Const, 18}, + {"R_PPC64_SECTOFF", Const, 20}, + {"R_PPC64_SECTOFF_DS", Const, 10}, + {"R_PPC64_SECTOFF_HA", Const, 20}, + {"R_PPC64_SECTOFF_HI", Const, 20}, + {"R_PPC64_SECTOFF_LO", Const, 20}, + {"R_PPC64_SECTOFF_LO_DS", Const, 10}, + {"R_PPC64_TLS", Const, 5}, + {"R_PPC64_TLSGD", Const, 5}, + {"R_PPC64_TLSLD", Const, 5}, + {"R_PPC64_TOC", Const, 5}, + {"R_PPC64_TOC16", Const, 5}, + {"R_PPC64_TOC16_DS", Const, 5}, + {"R_PPC64_TOC16_HA", Const, 5}, + {"R_PPC64_TOC16_HI", Const, 5}, + {"R_PPC64_TOC16_LO", Const, 5}, + {"R_PPC64_TOC16_LO_DS", Const, 5}, + {"R_PPC64_TOCSAVE", Const, 10}, + {"R_PPC64_TPREL16", Const, 5}, + {"R_PPC64_TPREL16_DS", Const, 5}, + {"R_PPC64_TPREL16_HA", Const, 5}, + {"R_PPC64_TPREL16_HI", Const, 5}, + {"R_PPC64_TPREL16_HIGH", Const, 10}, + {"R_PPC64_TPREL16_HIGHA", Const, 10}, + {"R_PPC64_TPREL16_HIGHER", Const, 5}, + {"R_PPC64_TPREL16_HIGHERA", Const, 5}, + {"R_PPC64_TPREL16_HIGHEST", Const, 5}, + {"R_PPC64_TPREL16_HIGHESTA", Const, 5}, + {"R_PPC64_TPREL16_LO", Const, 5}, + {"R_PPC64_TPREL16_LO_DS", Const, 5}, + {"R_PPC64_TPREL34", Const, 20}, + {"R_PPC64_TPREL64", Const, 5}, + {"R_PPC64_UADDR16", Const, 20}, + {"R_PPC64_UADDR32", Const, 20}, + {"R_PPC64_UADDR64", Const, 20}, + {"R_PPC_ADDR14", Const, 0}, + {"R_PPC_ADDR14_BRNTAKEN", Const, 0}, + {"R_PPC_ADDR14_BRTAKEN", Const, 0}, + {"R_PPC_ADDR16", Const, 0}, + {"R_PPC_ADDR16_HA", Const, 0}, + {"R_PPC_ADDR16_HI", Const, 0}, + {"R_PPC_ADDR16_LO", Const, 0}, + {"R_PPC_ADDR24", Const, 0}, + {"R_PPC_ADDR32", Const, 0}, + {"R_PPC_COPY", Const, 0}, + {"R_PPC_DTPMOD32", Const, 0}, + {"R_PPC_DTPREL16", Const, 0}, + {"R_PPC_DTPREL16_HA", Const, 0}, + {"R_PPC_DTPREL16_HI", Const, 0}, + {"R_PPC_DTPREL16_LO", Const, 0}, + {"R_PPC_DTPREL32", Const, 0}, + {"R_PPC_EMB_BIT_FLD", Const, 0}, + {"R_PPC_EMB_MRKREF", Const, 0}, + {"R_PPC_EMB_NADDR16", Const, 0}, + {"R_PPC_EMB_NADDR16_HA", Const, 0}, + {"R_PPC_EMB_NADDR16_HI", Const, 0}, + {"R_PPC_EMB_NADDR16_LO", Const, 0}, + {"R_PPC_EMB_NADDR32", Const, 0}, + {"R_PPC_EMB_RELSDA", Const, 0}, + {"R_PPC_EMB_RELSEC16", Const, 0}, + {"R_PPC_EMB_RELST_HA", Const, 0}, + {"R_PPC_EMB_RELST_HI", Const, 0}, + {"R_PPC_EMB_RELST_LO", Const, 0}, + {"R_PPC_EMB_SDA21", Const, 0}, + {"R_PPC_EMB_SDA2I16", Const, 0}, + {"R_PPC_EMB_SDA2REL", Const, 0}, + {"R_PPC_EMB_SDAI16", Const, 0}, + {"R_PPC_GLOB_DAT", Const, 0}, + {"R_PPC_GOT16", Const, 0}, + {"R_PPC_GOT16_HA", Const, 0}, + {"R_PPC_GOT16_HI", Const, 0}, + {"R_PPC_GOT16_LO", Const, 0}, + {"R_PPC_GOT_TLSGD16", Const, 0}, + {"R_PPC_GOT_TLSGD16_HA", Const, 0}, + {"R_PPC_GOT_TLSGD16_HI", Const, 0}, + {"R_PPC_GOT_TLSGD16_LO", Const, 0}, + {"R_PPC_GOT_TLSLD16", Const, 0}, + {"R_PPC_GOT_TLSLD16_HA", Const, 0}, + {"R_PPC_GOT_TLSLD16_HI", Const, 0}, + {"R_PPC_GOT_TLSLD16_LO", Const, 0}, + {"R_PPC_GOT_TPREL16", Const, 0}, + {"R_PPC_GOT_TPREL16_HA", Const, 0}, + {"R_PPC_GOT_TPREL16_HI", Const, 0}, + {"R_PPC_GOT_TPREL16_LO", Const, 0}, + {"R_PPC_JMP_SLOT", Const, 0}, + {"R_PPC_LOCAL24PC", Const, 0}, + {"R_PPC_NONE", Const, 0}, + {"R_PPC_PLT16_HA", Const, 0}, + {"R_PPC_PLT16_HI", Const, 0}, + {"R_PPC_PLT16_LO", Const, 0}, + {"R_PPC_PLT32", Const, 0}, + {"R_PPC_PLTREL24", Const, 0}, + {"R_PPC_PLTREL32", Const, 0}, + {"R_PPC_REL14", Const, 0}, + {"R_PPC_REL14_BRNTAKEN", Const, 0}, + {"R_PPC_REL14_BRTAKEN", Const, 0}, + {"R_PPC_REL24", Const, 0}, + {"R_PPC_REL32", Const, 0}, + {"R_PPC_RELATIVE", Const, 0}, + {"R_PPC_SDAREL16", Const, 0}, + {"R_PPC_SECTOFF", Const, 0}, + {"R_PPC_SECTOFF_HA", Const, 0}, + {"R_PPC_SECTOFF_HI", Const, 0}, + {"R_PPC_SECTOFF_LO", Const, 0}, + {"R_PPC_TLS", Const, 0}, + {"R_PPC_TPREL16", Const, 0}, + {"R_PPC_TPREL16_HA", Const, 0}, + {"R_PPC_TPREL16_HI", Const, 0}, + {"R_PPC_TPREL16_LO", Const, 0}, + {"R_PPC_TPREL32", Const, 0}, + {"R_PPC_UADDR16", Const, 0}, + {"R_PPC_UADDR32", Const, 0}, + {"R_RISCV", Type, 11}, + {"R_RISCV_32", Const, 11}, + {"R_RISCV_32_PCREL", Const, 12}, + {"R_RISCV_64", Const, 11}, + {"R_RISCV_ADD16", Const, 11}, + {"R_RISCV_ADD32", Const, 11}, + {"R_RISCV_ADD64", Const, 11}, + {"R_RISCV_ADD8", Const, 11}, + {"R_RISCV_ALIGN", Const, 11}, + {"R_RISCV_BRANCH", Const, 11}, + {"R_RISCV_CALL", Const, 11}, + {"R_RISCV_CALL_PLT", Const, 11}, + {"R_RISCV_COPY", Const, 11}, + {"R_RISCV_GNU_VTENTRY", Const, 11}, + {"R_RISCV_GNU_VTINHERIT", Const, 11}, + {"R_RISCV_GOT_HI20", Const, 11}, + {"R_RISCV_GPREL_I", Const, 11}, + {"R_RISCV_GPREL_S", Const, 11}, + {"R_RISCV_HI20", Const, 11}, + {"R_RISCV_JAL", Const, 11}, + {"R_RISCV_JUMP_SLOT", Const, 11}, + {"R_RISCV_LO12_I", Const, 11}, + {"R_RISCV_LO12_S", Const, 11}, + {"R_RISCV_NONE", Const, 11}, + {"R_RISCV_PCREL_HI20", Const, 11}, + {"R_RISCV_PCREL_LO12_I", Const, 11}, + {"R_RISCV_PCREL_LO12_S", Const, 11}, + {"R_RISCV_RELATIVE", Const, 11}, + {"R_RISCV_RELAX", Const, 11}, + {"R_RISCV_RVC_BRANCH", Const, 11}, + {"R_RISCV_RVC_JUMP", Const, 11}, + {"R_RISCV_RVC_LUI", Const, 11}, + {"R_RISCV_SET16", Const, 11}, + {"R_RISCV_SET32", Const, 11}, + {"R_RISCV_SET6", Const, 11}, + {"R_RISCV_SET8", Const, 11}, + {"R_RISCV_SUB16", Const, 11}, + {"R_RISCV_SUB32", Const, 11}, + {"R_RISCV_SUB6", Const, 11}, + {"R_RISCV_SUB64", Const, 11}, + {"R_RISCV_SUB8", Const, 11}, + {"R_RISCV_TLS_DTPMOD32", Const, 11}, + {"R_RISCV_TLS_DTPMOD64", Const, 11}, + {"R_RISCV_TLS_DTPREL32", Const, 11}, + {"R_RISCV_TLS_DTPREL64", Const, 11}, + {"R_RISCV_TLS_GD_HI20", Const, 11}, + {"R_RISCV_TLS_GOT_HI20", Const, 11}, + {"R_RISCV_TLS_TPREL32", Const, 11}, + {"R_RISCV_TLS_TPREL64", Const, 11}, + {"R_RISCV_TPREL_ADD", Const, 11}, + {"R_RISCV_TPREL_HI20", Const, 11}, + {"R_RISCV_TPREL_I", Const, 11}, + {"R_RISCV_TPREL_LO12_I", Const, 11}, + {"R_RISCV_TPREL_LO12_S", Const, 11}, + {"R_RISCV_TPREL_S", Const, 11}, + {"R_SPARC", Type, 0}, + {"R_SPARC_10", Const, 0}, + {"R_SPARC_11", Const, 0}, + {"R_SPARC_13", Const, 0}, + {"R_SPARC_16", Const, 0}, + {"R_SPARC_22", Const, 0}, + {"R_SPARC_32", Const, 0}, + {"R_SPARC_5", Const, 0}, + {"R_SPARC_6", Const, 0}, + {"R_SPARC_64", Const, 0}, + {"R_SPARC_7", Const, 0}, + {"R_SPARC_8", Const, 0}, + {"R_SPARC_COPY", Const, 0}, + {"R_SPARC_DISP16", Const, 0}, + {"R_SPARC_DISP32", Const, 0}, + {"R_SPARC_DISP64", Const, 0}, + {"R_SPARC_DISP8", Const, 0}, + {"R_SPARC_GLOB_DAT", Const, 0}, + {"R_SPARC_GLOB_JMP", Const, 0}, + {"R_SPARC_GOT10", Const, 0}, + {"R_SPARC_GOT13", Const, 0}, + {"R_SPARC_GOT22", Const, 0}, + {"R_SPARC_H44", Const, 0}, + {"R_SPARC_HH22", Const, 0}, + {"R_SPARC_HI22", Const, 0}, + {"R_SPARC_HIPLT22", Const, 0}, + {"R_SPARC_HIX22", Const, 0}, + {"R_SPARC_HM10", Const, 0}, + {"R_SPARC_JMP_SLOT", Const, 0}, + {"R_SPARC_L44", Const, 0}, + {"R_SPARC_LM22", Const, 0}, + {"R_SPARC_LO10", Const, 0}, + {"R_SPARC_LOPLT10", Const, 0}, + {"R_SPARC_LOX10", Const, 0}, + {"R_SPARC_M44", Const, 0}, + {"R_SPARC_NONE", Const, 0}, + {"R_SPARC_OLO10", Const, 0}, + {"R_SPARC_PC10", Const, 0}, + {"R_SPARC_PC22", Const, 0}, + {"R_SPARC_PCPLT10", Const, 0}, + {"R_SPARC_PCPLT22", Const, 0}, + {"R_SPARC_PCPLT32", Const, 0}, + {"R_SPARC_PC_HH22", Const, 0}, + {"R_SPARC_PC_HM10", Const, 0}, + {"R_SPARC_PC_LM22", Const, 0}, + {"R_SPARC_PLT32", Const, 0}, + {"R_SPARC_PLT64", Const, 0}, + {"R_SPARC_REGISTER", Const, 0}, + {"R_SPARC_RELATIVE", Const, 0}, + {"R_SPARC_UA16", Const, 0}, + {"R_SPARC_UA32", Const, 0}, + {"R_SPARC_UA64", Const, 0}, + {"R_SPARC_WDISP16", Const, 0}, + {"R_SPARC_WDISP19", Const, 0}, + {"R_SPARC_WDISP22", Const, 0}, + {"R_SPARC_WDISP30", Const, 0}, + {"R_SPARC_WPLT30", Const, 0}, + {"R_SYM32", Func, 0}, + {"R_SYM64", Func, 0}, + {"R_TYPE32", Func, 0}, + {"R_TYPE64", Func, 0}, + {"R_X86_64", Type, 0}, + {"R_X86_64_16", Const, 0}, + {"R_X86_64_32", Const, 0}, + {"R_X86_64_32S", Const, 0}, + {"R_X86_64_64", Const, 0}, + {"R_X86_64_8", Const, 0}, + {"R_X86_64_COPY", Const, 0}, + {"R_X86_64_DTPMOD64", Const, 0}, + {"R_X86_64_DTPOFF32", Const, 0}, + {"R_X86_64_DTPOFF64", Const, 0}, + {"R_X86_64_GLOB_DAT", Const, 0}, + {"R_X86_64_GOT32", Const, 0}, + {"R_X86_64_GOT64", Const, 10}, + {"R_X86_64_GOTOFF64", Const, 10}, + {"R_X86_64_GOTPC32", Const, 10}, + {"R_X86_64_GOTPC32_TLSDESC", Const, 10}, + {"R_X86_64_GOTPC64", Const, 10}, + {"R_X86_64_GOTPCREL", Const, 0}, + {"R_X86_64_GOTPCREL64", Const, 10}, + {"R_X86_64_GOTPCRELX", Const, 10}, + {"R_X86_64_GOTPLT64", Const, 10}, + {"R_X86_64_GOTTPOFF", Const, 0}, + {"R_X86_64_IRELATIVE", Const, 10}, + {"R_X86_64_JMP_SLOT", Const, 0}, + {"R_X86_64_NONE", Const, 0}, + {"R_X86_64_PC16", Const, 0}, + {"R_X86_64_PC32", Const, 0}, + {"R_X86_64_PC32_BND", Const, 10}, + {"R_X86_64_PC64", Const, 10}, + {"R_X86_64_PC8", Const, 0}, + {"R_X86_64_PLT32", Const, 0}, + {"R_X86_64_PLT32_BND", Const, 10}, + {"R_X86_64_PLTOFF64", Const, 10}, + {"R_X86_64_RELATIVE", Const, 0}, + {"R_X86_64_RELATIVE64", Const, 10}, + {"R_X86_64_REX_GOTPCRELX", Const, 10}, + {"R_X86_64_SIZE32", Const, 10}, + {"R_X86_64_SIZE64", Const, 10}, + {"R_X86_64_TLSDESC", Const, 10}, + {"R_X86_64_TLSDESC_CALL", Const, 10}, + {"R_X86_64_TLSGD", Const, 0}, + {"R_X86_64_TLSLD", Const, 0}, + {"R_X86_64_TPOFF32", Const, 0}, + {"R_X86_64_TPOFF64", Const, 0}, + {"Rel32", Type, 0}, + {"Rel32.Info", Field, 0}, + {"Rel32.Off", Field, 0}, + {"Rel64", Type, 0}, + {"Rel64.Info", Field, 0}, + {"Rel64.Off", Field, 0}, + {"Rela32", Type, 0}, + {"Rela32.Addend", Field, 0}, + {"Rela32.Info", Field, 0}, + {"Rela32.Off", Field, 0}, + {"Rela64", Type, 0}, + {"Rela64.Addend", Field, 0}, + {"Rela64.Info", Field, 0}, + {"Rela64.Off", Field, 0}, + {"SHF_ALLOC", Const, 0}, + {"SHF_COMPRESSED", Const, 6}, + {"SHF_EXECINSTR", Const, 0}, + {"SHF_GROUP", Const, 0}, + {"SHF_INFO_LINK", Const, 0}, + {"SHF_LINK_ORDER", Const, 0}, + {"SHF_MASKOS", Const, 0}, + {"SHF_MASKPROC", Const, 0}, + {"SHF_MERGE", Const, 0}, + {"SHF_OS_NONCONFORMING", Const, 0}, + {"SHF_STRINGS", Const, 0}, + {"SHF_TLS", Const, 0}, + {"SHF_WRITE", Const, 0}, + {"SHN_ABS", Const, 0}, + {"SHN_COMMON", Const, 0}, + {"SHN_HIOS", Const, 0}, + {"SHN_HIPROC", Const, 0}, + {"SHN_HIRESERVE", Const, 0}, + {"SHN_LOOS", Const, 0}, + {"SHN_LOPROC", Const, 0}, + {"SHN_LORESERVE", Const, 0}, + {"SHN_UNDEF", Const, 0}, + {"SHN_XINDEX", Const, 0}, + {"SHT_DYNAMIC", Const, 0}, + {"SHT_DYNSYM", Const, 0}, + {"SHT_FINI_ARRAY", Const, 0}, + {"SHT_GNU_ATTRIBUTES", Const, 0}, + {"SHT_GNU_HASH", Const, 0}, + {"SHT_GNU_LIBLIST", Const, 0}, + {"SHT_GNU_VERDEF", Const, 0}, + {"SHT_GNU_VERNEED", Const, 0}, + {"SHT_GNU_VERSYM", Const, 0}, + {"SHT_GROUP", Const, 0}, + {"SHT_HASH", Const, 0}, + {"SHT_HIOS", Const, 0}, + {"SHT_HIPROC", Const, 0}, + {"SHT_HIUSER", Const, 0}, + {"SHT_INIT_ARRAY", Const, 0}, + {"SHT_LOOS", Const, 0}, + {"SHT_LOPROC", Const, 0}, + {"SHT_LOUSER", Const, 0}, + {"SHT_MIPS_ABIFLAGS", Const, 17}, + {"SHT_NOBITS", Const, 0}, + {"SHT_NOTE", Const, 0}, + {"SHT_NULL", Const, 0}, + {"SHT_PREINIT_ARRAY", Const, 0}, + {"SHT_PROGBITS", Const, 0}, + {"SHT_REL", Const, 0}, + {"SHT_RELA", Const, 0}, + {"SHT_SHLIB", Const, 0}, + {"SHT_STRTAB", Const, 0}, + {"SHT_SYMTAB", Const, 0}, + {"SHT_SYMTAB_SHNDX", Const, 0}, + {"STB_GLOBAL", Const, 0}, + {"STB_HIOS", Const, 0}, + {"STB_HIPROC", Const, 0}, + {"STB_LOCAL", Const, 0}, + {"STB_LOOS", Const, 0}, + {"STB_LOPROC", Const, 0}, + {"STB_WEAK", Const, 0}, + {"STT_COMMON", Const, 0}, + {"STT_FILE", Const, 0}, + {"STT_FUNC", Const, 0}, + {"STT_HIOS", Const, 0}, + {"STT_HIPROC", Const, 0}, + {"STT_LOOS", Const, 0}, + {"STT_LOPROC", Const, 0}, + {"STT_NOTYPE", Const, 0}, + {"STT_OBJECT", Const, 0}, + {"STT_SECTION", Const, 0}, + {"STT_TLS", Const, 0}, + {"STV_DEFAULT", Const, 0}, + {"STV_HIDDEN", Const, 0}, + {"STV_INTERNAL", Const, 0}, + {"STV_PROTECTED", Const, 0}, + {"ST_BIND", Func, 0}, + {"ST_INFO", Func, 0}, + {"ST_TYPE", Func, 0}, + {"ST_VISIBILITY", Func, 0}, + {"Section", Type, 0}, + {"Section.ReaderAt", Field, 0}, + {"Section.SectionHeader", Field, 0}, + {"Section32", Type, 0}, + {"Section32.Addr", Field, 0}, + {"Section32.Addralign", Field, 0}, + {"Section32.Entsize", Field, 0}, + {"Section32.Flags", Field, 0}, + {"Section32.Info", Field, 0}, + {"Section32.Link", Field, 0}, + {"Section32.Name", Field, 0}, + {"Section32.Off", Field, 0}, + {"Section32.Size", Field, 0}, + {"Section32.Type", Field, 0}, + {"Section64", Type, 0}, + {"Section64.Addr", Field, 0}, + {"Section64.Addralign", Field, 0}, + {"Section64.Entsize", Field, 0}, + {"Section64.Flags", Field, 0}, + {"Section64.Info", Field, 0}, + {"Section64.Link", Field, 0}, + {"Section64.Name", Field, 0}, + {"Section64.Off", Field, 0}, + {"Section64.Size", Field, 0}, + {"Section64.Type", Field, 0}, + {"SectionFlag", Type, 0}, + {"SectionHeader", Type, 0}, + {"SectionHeader.Addr", Field, 0}, + {"SectionHeader.Addralign", Field, 0}, + {"SectionHeader.Entsize", Field, 0}, + {"SectionHeader.FileSize", Field, 6}, + {"SectionHeader.Flags", Field, 0}, + {"SectionHeader.Info", Field, 0}, + {"SectionHeader.Link", Field, 0}, + {"SectionHeader.Name", Field, 0}, + {"SectionHeader.Offset", Field, 0}, + {"SectionHeader.Size", Field, 0}, + {"SectionHeader.Type", Field, 0}, + {"SectionIndex", Type, 0}, + {"SectionType", Type, 0}, + {"Sym32", Type, 0}, + {"Sym32.Info", Field, 0}, + {"Sym32.Name", Field, 0}, + {"Sym32.Other", Field, 0}, + {"Sym32.Shndx", Field, 0}, + {"Sym32.Size", Field, 0}, + {"Sym32.Value", Field, 0}, + {"Sym32Size", Const, 0}, + {"Sym64", Type, 0}, + {"Sym64.Info", Field, 0}, + {"Sym64.Name", Field, 0}, + {"Sym64.Other", Field, 0}, + {"Sym64.Shndx", Field, 0}, + {"Sym64.Size", Field, 0}, + {"Sym64.Value", Field, 0}, + {"Sym64Size", Const, 0}, + {"SymBind", Type, 0}, + {"SymType", Type, 0}, + {"SymVis", Type, 0}, + {"Symbol", Type, 0}, + {"Symbol.Info", Field, 0}, + {"Symbol.Library", Field, 13}, + {"Symbol.Name", Field, 0}, + {"Symbol.Other", Field, 0}, + {"Symbol.Section", Field, 0}, + {"Symbol.Size", Field, 0}, + {"Symbol.Value", Field, 0}, + {"Symbol.Version", Field, 13}, + {"Type", Type, 0}, + {"Version", Type, 0}, + }, + "debug/gosym": { + {"(*DecodingError).Error", Method, 0}, + {"(*LineTable).LineToPC", Method, 0}, + {"(*LineTable).PCToLine", Method, 0}, + {"(*Sym).BaseName", Method, 0}, + {"(*Sym).PackageName", Method, 0}, + {"(*Sym).ReceiverName", Method, 0}, + {"(*Sym).Static", Method, 0}, + {"(*Table).LineToPC", Method, 0}, + {"(*Table).LookupFunc", Method, 0}, + {"(*Table).LookupSym", Method, 0}, + {"(*Table).PCToFunc", Method, 0}, + {"(*Table).PCToLine", Method, 0}, + {"(*Table).SymByAddr", Method, 0}, + {"(*UnknownLineError).Error", Method, 0}, + {"(Func).BaseName", Method, 0}, + {"(Func).PackageName", Method, 0}, + {"(Func).ReceiverName", Method, 0}, + {"(Func).Static", Method, 0}, + {"(UnknownFileError).Error", Method, 0}, + {"DecodingError", Type, 0}, + {"Func", Type, 0}, + {"Func.End", Field, 0}, + {"Func.Entry", Field, 0}, + {"Func.FrameSize", Field, 0}, + {"Func.LineTable", Field, 0}, + {"Func.Locals", Field, 0}, + {"Func.Obj", Field, 0}, + {"Func.Params", Field, 0}, + {"Func.Sym", Field, 0}, + {"LineTable", Type, 0}, + {"LineTable.Data", Field, 0}, + {"LineTable.Line", Field, 0}, + {"LineTable.PC", Field, 0}, + {"NewLineTable", Func, 0}, + {"NewTable", Func, 0}, + {"Obj", Type, 0}, + {"Obj.Funcs", Field, 0}, + {"Obj.Paths", Field, 0}, + {"Sym", Type, 0}, + {"Sym.Func", Field, 0}, + {"Sym.GoType", Field, 0}, + {"Sym.Name", Field, 0}, + {"Sym.Type", Field, 0}, + {"Sym.Value", Field, 0}, + {"Table", Type, 0}, + {"Table.Files", Field, 0}, + {"Table.Funcs", Field, 0}, + {"Table.Objs", Field, 0}, + {"Table.Syms", Field, 0}, + {"UnknownFileError", Type, 0}, + {"UnknownLineError", Type, 0}, + {"UnknownLineError.File", Field, 0}, + {"UnknownLineError.Line", Field, 0}, + }, + "debug/macho": { + {"(*FatFile).Close", Method, 3}, + {"(*File).Close", Method, 0}, + {"(*File).DWARF", Method, 0}, + {"(*File).ImportedLibraries", Method, 0}, + {"(*File).ImportedSymbols", Method, 0}, + {"(*File).Section", Method, 0}, + {"(*File).Segment", Method, 0}, + {"(*FormatError).Error", Method, 0}, + {"(*Section).Data", Method, 0}, + {"(*Section).Open", Method, 0}, + {"(*Segment).Data", Method, 0}, + {"(*Segment).Open", Method, 0}, + {"(Cpu).GoString", Method, 0}, + {"(Cpu).String", Method, 0}, + {"(Dylib).Raw", Method, 0}, + {"(Dysymtab).Raw", Method, 0}, + {"(FatArch).Close", Method, 3}, + {"(FatArch).DWARF", Method, 3}, + {"(FatArch).ImportedLibraries", Method, 3}, + {"(FatArch).ImportedSymbols", Method, 3}, + {"(FatArch).Section", Method, 3}, + {"(FatArch).Segment", Method, 3}, + {"(LoadBytes).Raw", Method, 0}, + {"(LoadCmd).GoString", Method, 0}, + {"(LoadCmd).String", Method, 0}, + {"(RelocTypeARM).GoString", Method, 10}, + {"(RelocTypeARM).String", Method, 10}, + {"(RelocTypeARM64).GoString", Method, 10}, + {"(RelocTypeARM64).String", Method, 10}, + {"(RelocTypeGeneric).GoString", Method, 10}, + {"(RelocTypeGeneric).String", Method, 10}, + {"(RelocTypeX86_64).GoString", Method, 10}, + {"(RelocTypeX86_64).String", Method, 10}, + {"(Rpath).Raw", Method, 10}, + {"(Section).ReadAt", Method, 0}, + {"(Segment).Raw", Method, 0}, + {"(Segment).ReadAt", Method, 0}, + {"(Symtab).Raw", Method, 0}, + {"(Type).GoString", Method, 10}, + {"(Type).String", Method, 10}, + {"ARM64_RELOC_ADDEND", Const, 10}, + {"ARM64_RELOC_BRANCH26", Const, 10}, + {"ARM64_RELOC_GOT_LOAD_PAGE21", Const, 10}, + {"ARM64_RELOC_GOT_LOAD_PAGEOFF12", Const, 10}, + {"ARM64_RELOC_PAGE21", Const, 10}, + {"ARM64_RELOC_PAGEOFF12", Const, 10}, + {"ARM64_RELOC_POINTER_TO_GOT", Const, 10}, + {"ARM64_RELOC_SUBTRACTOR", Const, 10}, + {"ARM64_RELOC_TLVP_LOAD_PAGE21", Const, 10}, + {"ARM64_RELOC_TLVP_LOAD_PAGEOFF12", Const, 10}, + {"ARM64_RELOC_UNSIGNED", Const, 10}, + {"ARM_RELOC_BR24", Const, 10}, + {"ARM_RELOC_HALF", Const, 10}, + {"ARM_RELOC_HALF_SECTDIFF", Const, 10}, + {"ARM_RELOC_LOCAL_SECTDIFF", Const, 10}, + {"ARM_RELOC_PAIR", Const, 10}, + {"ARM_RELOC_PB_LA_PTR", Const, 10}, + {"ARM_RELOC_SECTDIFF", Const, 10}, + {"ARM_RELOC_VANILLA", Const, 10}, + {"ARM_THUMB_32BIT_BRANCH", Const, 10}, + {"ARM_THUMB_RELOC_BR22", Const, 10}, + {"Cpu", Type, 0}, + {"Cpu386", Const, 0}, + {"CpuAmd64", Const, 0}, + {"CpuArm", Const, 3}, + {"CpuArm64", Const, 11}, + {"CpuPpc", Const, 3}, + {"CpuPpc64", Const, 3}, + {"Dylib", Type, 0}, + {"Dylib.CompatVersion", Field, 0}, + {"Dylib.CurrentVersion", Field, 0}, + {"Dylib.LoadBytes", Field, 0}, + {"Dylib.Name", Field, 0}, + {"Dylib.Time", Field, 0}, + {"DylibCmd", Type, 0}, + {"DylibCmd.Cmd", Field, 0}, + {"DylibCmd.CompatVersion", Field, 0}, + {"DylibCmd.CurrentVersion", Field, 0}, + {"DylibCmd.Len", Field, 0}, + {"DylibCmd.Name", Field, 0}, + {"DylibCmd.Time", Field, 0}, + {"Dysymtab", Type, 0}, + {"Dysymtab.DysymtabCmd", Field, 0}, + {"Dysymtab.IndirectSyms", Field, 0}, + {"Dysymtab.LoadBytes", Field, 0}, + {"DysymtabCmd", Type, 0}, + {"DysymtabCmd.Cmd", Field, 0}, + {"DysymtabCmd.Extrefsymoff", Field, 0}, + {"DysymtabCmd.Extreloff", Field, 0}, + {"DysymtabCmd.Iextdefsym", Field, 0}, + {"DysymtabCmd.Ilocalsym", Field, 0}, + {"DysymtabCmd.Indirectsymoff", Field, 0}, + {"DysymtabCmd.Iundefsym", Field, 0}, + {"DysymtabCmd.Len", Field, 0}, + {"DysymtabCmd.Locreloff", Field, 0}, + {"DysymtabCmd.Modtaboff", Field, 0}, + {"DysymtabCmd.Nextdefsym", Field, 0}, + {"DysymtabCmd.Nextrefsyms", Field, 0}, + {"DysymtabCmd.Nextrel", Field, 0}, + {"DysymtabCmd.Nindirectsyms", Field, 0}, + {"DysymtabCmd.Nlocalsym", Field, 0}, + {"DysymtabCmd.Nlocrel", Field, 0}, + {"DysymtabCmd.Nmodtab", Field, 0}, + {"DysymtabCmd.Ntoc", Field, 0}, + {"DysymtabCmd.Nundefsym", Field, 0}, + {"DysymtabCmd.Tocoffset", Field, 0}, + {"ErrNotFat", Var, 3}, + {"FatArch", Type, 3}, + {"FatArch.FatArchHeader", Field, 3}, + {"FatArch.File", Field, 3}, + {"FatArchHeader", Type, 3}, + {"FatArchHeader.Align", Field, 3}, + {"FatArchHeader.Cpu", Field, 3}, + {"FatArchHeader.Offset", Field, 3}, + {"FatArchHeader.Size", Field, 3}, + {"FatArchHeader.SubCpu", Field, 3}, + {"FatFile", Type, 3}, + {"FatFile.Arches", Field, 3}, + {"FatFile.Magic", Field, 3}, + {"File", Type, 0}, + {"File.ByteOrder", Field, 0}, + {"File.Dysymtab", Field, 0}, + {"File.FileHeader", Field, 0}, + {"File.Loads", Field, 0}, + {"File.Sections", Field, 0}, + {"File.Symtab", Field, 0}, + {"FileHeader", Type, 0}, + {"FileHeader.Cmdsz", Field, 0}, + {"FileHeader.Cpu", Field, 0}, + {"FileHeader.Flags", Field, 0}, + {"FileHeader.Magic", Field, 0}, + {"FileHeader.Ncmd", Field, 0}, + {"FileHeader.SubCpu", Field, 0}, + {"FileHeader.Type", Field, 0}, + {"FlagAllModsBound", Const, 10}, + {"FlagAllowStackExecution", Const, 10}, + {"FlagAppExtensionSafe", Const, 10}, + {"FlagBindAtLoad", Const, 10}, + {"FlagBindsToWeak", Const, 10}, + {"FlagCanonical", Const, 10}, + {"FlagDeadStrippableDylib", Const, 10}, + {"FlagDyldLink", Const, 10}, + {"FlagForceFlat", Const, 10}, + {"FlagHasTLVDescriptors", Const, 10}, + {"FlagIncrLink", Const, 10}, + {"FlagLazyInit", Const, 10}, + {"FlagNoFixPrebinding", Const, 10}, + {"FlagNoHeapExecution", Const, 10}, + {"FlagNoMultiDefs", Const, 10}, + {"FlagNoReexportedDylibs", Const, 10}, + {"FlagNoUndefs", Const, 10}, + {"FlagPIE", Const, 10}, + {"FlagPrebindable", Const, 10}, + {"FlagPrebound", Const, 10}, + {"FlagRootSafe", Const, 10}, + {"FlagSetuidSafe", Const, 10}, + {"FlagSplitSegs", Const, 10}, + {"FlagSubsectionsViaSymbols", Const, 10}, + {"FlagTwoLevel", Const, 10}, + {"FlagWeakDefines", Const, 10}, + {"FormatError", Type, 0}, + {"GENERIC_RELOC_LOCAL_SECTDIFF", Const, 10}, + {"GENERIC_RELOC_PAIR", Const, 10}, + {"GENERIC_RELOC_PB_LA_PTR", Const, 10}, + {"GENERIC_RELOC_SECTDIFF", Const, 10}, + {"GENERIC_RELOC_TLV", Const, 10}, + {"GENERIC_RELOC_VANILLA", Const, 10}, + {"Load", Type, 0}, + {"LoadBytes", Type, 0}, + {"LoadCmd", Type, 0}, + {"LoadCmdDylib", Const, 0}, + {"LoadCmdDylinker", Const, 0}, + {"LoadCmdDysymtab", Const, 0}, + {"LoadCmdRpath", Const, 10}, + {"LoadCmdSegment", Const, 0}, + {"LoadCmdSegment64", Const, 0}, + {"LoadCmdSymtab", Const, 0}, + {"LoadCmdThread", Const, 0}, + {"LoadCmdUnixThread", Const, 0}, + {"Magic32", Const, 0}, + {"Magic64", Const, 0}, + {"MagicFat", Const, 3}, + {"NewFatFile", Func, 3}, + {"NewFile", Func, 0}, + {"Nlist32", Type, 0}, + {"Nlist32.Desc", Field, 0}, + {"Nlist32.Name", Field, 0}, + {"Nlist32.Sect", Field, 0}, + {"Nlist32.Type", Field, 0}, + {"Nlist32.Value", Field, 0}, + {"Nlist64", Type, 0}, + {"Nlist64.Desc", Field, 0}, + {"Nlist64.Name", Field, 0}, + {"Nlist64.Sect", Field, 0}, + {"Nlist64.Type", Field, 0}, + {"Nlist64.Value", Field, 0}, + {"Open", Func, 0}, + {"OpenFat", Func, 3}, + {"Regs386", Type, 0}, + {"Regs386.AX", Field, 0}, + {"Regs386.BP", Field, 0}, + {"Regs386.BX", Field, 0}, + {"Regs386.CS", Field, 0}, + {"Regs386.CX", Field, 0}, + {"Regs386.DI", Field, 0}, + {"Regs386.DS", Field, 0}, + {"Regs386.DX", Field, 0}, + {"Regs386.ES", Field, 0}, + {"Regs386.FLAGS", Field, 0}, + {"Regs386.FS", Field, 0}, + {"Regs386.GS", Field, 0}, + {"Regs386.IP", Field, 0}, + {"Regs386.SI", Field, 0}, + {"Regs386.SP", Field, 0}, + {"Regs386.SS", Field, 0}, + {"RegsAMD64", Type, 0}, + {"RegsAMD64.AX", Field, 0}, + {"RegsAMD64.BP", Field, 0}, + {"RegsAMD64.BX", Field, 0}, + {"RegsAMD64.CS", Field, 0}, + {"RegsAMD64.CX", Field, 0}, + {"RegsAMD64.DI", Field, 0}, + {"RegsAMD64.DX", Field, 0}, + {"RegsAMD64.FLAGS", Field, 0}, + {"RegsAMD64.FS", Field, 0}, + {"RegsAMD64.GS", Field, 0}, + {"RegsAMD64.IP", Field, 0}, + {"RegsAMD64.R10", Field, 0}, + {"RegsAMD64.R11", Field, 0}, + {"RegsAMD64.R12", Field, 0}, + {"RegsAMD64.R13", Field, 0}, + {"RegsAMD64.R14", Field, 0}, + {"RegsAMD64.R15", Field, 0}, + {"RegsAMD64.R8", Field, 0}, + {"RegsAMD64.R9", Field, 0}, + {"RegsAMD64.SI", Field, 0}, + {"RegsAMD64.SP", Field, 0}, + {"Reloc", Type, 10}, + {"Reloc.Addr", Field, 10}, + {"Reloc.Extern", Field, 10}, + {"Reloc.Len", Field, 10}, + {"Reloc.Pcrel", Field, 10}, + {"Reloc.Scattered", Field, 10}, + {"Reloc.Type", Field, 10}, + {"Reloc.Value", Field, 10}, + {"RelocTypeARM", Type, 10}, + {"RelocTypeARM64", Type, 10}, + {"RelocTypeGeneric", Type, 10}, + {"RelocTypeX86_64", Type, 10}, + {"Rpath", Type, 10}, + {"Rpath.LoadBytes", Field, 10}, + {"Rpath.Path", Field, 10}, + {"RpathCmd", Type, 10}, + {"RpathCmd.Cmd", Field, 10}, + {"RpathCmd.Len", Field, 10}, + {"RpathCmd.Path", Field, 10}, + {"Section", Type, 0}, + {"Section.ReaderAt", Field, 0}, + {"Section.Relocs", Field, 10}, + {"Section.SectionHeader", Field, 0}, + {"Section32", Type, 0}, + {"Section32.Addr", Field, 0}, + {"Section32.Align", Field, 0}, + {"Section32.Flags", Field, 0}, + {"Section32.Name", Field, 0}, + {"Section32.Nreloc", Field, 0}, + {"Section32.Offset", Field, 0}, + {"Section32.Reloff", Field, 0}, + {"Section32.Reserve1", Field, 0}, + {"Section32.Reserve2", Field, 0}, + {"Section32.Seg", Field, 0}, + {"Section32.Size", Field, 0}, + {"Section64", Type, 0}, + {"Section64.Addr", Field, 0}, + {"Section64.Align", Field, 0}, + {"Section64.Flags", Field, 0}, + {"Section64.Name", Field, 0}, + {"Section64.Nreloc", Field, 0}, + {"Section64.Offset", Field, 0}, + {"Section64.Reloff", Field, 0}, + {"Section64.Reserve1", Field, 0}, + {"Section64.Reserve2", Field, 0}, + {"Section64.Reserve3", Field, 0}, + {"Section64.Seg", Field, 0}, + {"Section64.Size", Field, 0}, + {"SectionHeader", Type, 0}, + {"SectionHeader.Addr", Field, 0}, + {"SectionHeader.Align", Field, 0}, + {"SectionHeader.Flags", Field, 0}, + {"SectionHeader.Name", Field, 0}, + {"SectionHeader.Nreloc", Field, 0}, + {"SectionHeader.Offset", Field, 0}, + {"SectionHeader.Reloff", Field, 0}, + {"SectionHeader.Seg", Field, 0}, + {"SectionHeader.Size", Field, 0}, + {"Segment", Type, 0}, + {"Segment.LoadBytes", Field, 0}, + {"Segment.ReaderAt", Field, 0}, + {"Segment.SegmentHeader", Field, 0}, + {"Segment32", Type, 0}, + {"Segment32.Addr", Field, 0}, + {"Segment32.Cmd", Field, 0}, + {"Segment32.Filesz", Field, 0}, + {"Segment32.Flag", Field, 0}, + {"Segment32.Len", Field, 0}, + {"Segment32.Maxprot", Field, 0}, + {"Segment32.Memsz", Field, 0}, + {"Segment32.Name", Field, 0}, + {"Segment32.Nsect", Field, 0}, + {"Segment32.Offset", Field, 0}, + {"Segment32.Prot", Field, 0}, + {"Segment64", Type, 0}, + {"Segment64.Addr", Field, 0}, + {"Segment64.Cmd", Field, 0}, + {"Segment64.Filesz", Field, 0}, + {"Segment64.Flag", Field, 0}, + {"Segment64.Len", Field, 0}, + {"Segment64.Maxprot", Field, 0}, + {"Segment64.Memsz", Field, 0}, + {"Segment64.Name", Field, 0}, + {"Segment64.Nsect", Field, 0}, + {"Segment64.Offset", Field, 0}, + {"Segment64.Prot", Field, 0}, + {"SegmentHeader", Type, 0}, + {"SegmentHeader.Addr", Field, 0}, + {"SegmentHeader.Cmd", Field, 0}, + {"SegmentHeader.Filesz", Field, 0}, + {"SegmentHeader.Flag", Field, 0}, + {"SegmentHeader.Len", Field, 0}, + {"SegmentHeader.Maxprot", Field, 0}, + {"SegmentHeader.Memsz", Field, 0}, + {"SegmentHeader.Name", Field, 0}, + {"SegmentHeader.Nsect", Field, 0}, + {"SegmentHeader.Offset", Field, 0}, + {"SegmentHeader.Prot", Field, 0}, + {"Symbol", Type, 0}, + {"Symbol.Desc", Field, 0}, + {"Symbol.Name", Field, 0}, + {"Symbol.Sect", Field, 0}, + {"Symbol.Type", Field, 0}, + {"Symbol.Value", Field, 0}, + {"Symtab", Type, 0}, + {"Symtab.LoadBytes", Field, 0}, + {"Symtab.Syms", Field, 0}, + {"Symtab.SymtabCmd", Field, 0}, + {"SymtabCmd", Type, 0}, + {"SymtabCmd.Cmd", Field, 0}, + {"SymtabCmd.Len", Field, 0}, + {"SymtabCmd.Nsyms", Field, 0}, + {"SymtabCmd.Stroff", Field, 0}, + {"SymtabCmd.Strsize", Field, 0}, + {"SymtabCmd.Symoff", Field, 0}, + {"Thread", Type, 0}, + {"Thread.Cmd", Field, 0}, + {"Thread.Data", Field, 0}, + {"Thread.Len", Field, 0}, + {"Thread.Type", Field, 0}, + {"Type", Type, 0}, + {"TypeBundle", Const, 3}, + {"TypeDylib", Const, 3}, + {"TypeExec", Const, 0}, + {"TypeObj", Const, 0}, + {"X86_64_RELOC_BRANCH", Const, 10}, + {"X86_64_RELOC_GOT", Const, 10}, + {"X86_64_RELOC_GOT_LOAD", Const, 10}, + {"X86_64_RELOC_SIGNED", Const, 10}, + {"X86_64_RELOC_SIGNED_1", Const, 10}, + {"X86_64_RELOC_SIGNED_2", Const, 10}, + {"X86_64_RELOC_SIGNED_4", Const, 10}, + {"X86_64_RELOC_SUBTRACTOR", Const, 10}, + {"X86_64_RELOC_TLV", Const, 10}, + {"X86_64_RELOC_UNSIGNED", Const, 10}, + }, + "debug/pe": { + {"(*COFFSymbol).FullName", Method, 8}, + {"(*File).COFFSymbolReadSectionDefAux", Method, 19}, + {"(*File).Close", Method, 0}, + {"(*File).DWARF", Method, 0}, + {"(*File).ImportedLibraries", Method, 0}, + {"(*File).ImportedSymbols", Method, 0}, + {"(*File).Section", Method, 0}, + {"(*FormatError).Error", Method, 0}, + {"(*Section).Data", Method, 0}, + {"(*Section).Open", Method, 0}, + {"(Section).ReadAt", Method, 0}, + {"(StringTable).String", Method, 8}, + {"COFFSymbol", Type, 1}, + {"COFFSymbol.Name", Field, 1}, + {"COFFSymbol.NumberOfAuxSymbols", Field, 1}, + {"COFFSymbol.SectionNumber", Field, 1}, + {"COFFSymbol.StorageClass", Field, 1}, + {"COFFSymbol.Type", Field, 1}, + {"COFFSymbol.Value", Field, 1}, + {"COFFSymbolAuxFormat5", Type, 19}, + {"COFFSymbolAuxFormat5.Checksum", Field, 19}, + {"COFFSymbolAuxFormat5.NumLineNumbers", Field, 19}, + {"COFFSymbolAuxFormat5.NumRelocs", Field, 19}, + {"COFFSymbolAuxFormat5.SecNum", Field, 19}, + {"COFFSymbolAuxFormat5.Selection", Field, 19}, + {"COFFSymbolAuxFormat5.Size", Field, 19}, + {"COFFSymbolSize", Const, 1}, + {"DataDirectory", Type, 3}, + {"DataDirectory.Size", Field, 3}, + {"DataDirectory.VirtualAddress", Field, 3}, + {"File", Type, 0}, + {"File.COFFSymbols", Field, 8}, + {"File.FileHeader", Field, 0}, + {"File.OptionalHeader", Field, 3}, + {"File.Sections", Field, 0}, + {"File.StringTable", Field, 8}, + {"File.Symbols", Field, 1}, + {"FileHeader", Type, 0}, + {"FileHeader.Characteristics", Field, 0}, + {"FileHeader.Machine", Field, 0}, + {"FileHeader.NumberOfSections", Field, 0}, + {"FileHeader.NumberOfSymbols", Field, 0}, + {"FileHeader.PointerToSymbolTable", Field, 0}, + {"FileHeader.SizeOfOptionalHeader", Field, 0}, + {"FileHeader.TimeDateStamp", Field, 0}, + {"FormatError", Type, 0}, + {"IMAGE_COMDAT_SELECT_ANY", Const, 19}, + {"IMAGE_COMDAT_SELECT_ASSOCIATIVE", Const, 19}, + {"IMAGE_COMDAT_SELECT_EXACT_MATCH", Const, 19}, + {"IMAGE_COMDAT_SELECT_LARGEST", Const, 19}, + {"IMAGE_COMDAT_SELECT_NODUPLICATES", Const, 19}, + {"IMAGE_COMDAT_SELECT_SAME_SIZE", Const, 19}, + {"IMAGE_DIRECTORY_ENTRY_ARCHITECTURE", Const, 11}, + {"IMAGE_DIRECTORY_ENTRY_BASERELOC", Const, 11}, + {"IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT", Const, 11}, + {"IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR", Const, 11}, + {"IMAGE_DIRECTORY_ENTRY_DEBUG", Const, 11}, + {"IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT", Const, 11}, + {"IMAGE_DIRECTORY_ENTRY_EXCEPTION", Const, 11}, + {"IMAGE_DIRECTORY_ENTRY_EXPORT", Const, 11}, + {"IMAGE_DIRECTORY_ENTRY_GLOBALPTR", Const, 11}, + {"IMAGE_DIRECTORY_ENTRY_IAT", Const, 11}, + {"IMAGE_DIRECTORY_ENTRY_IMPORT", Const, 11}, + {"IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG", Const, 11}, + {"IMAGE_DIRECTORY_ENTRY_RESOURCE", Const, 11}, + {"IMAGE_DIRECTORY_ENTRY_SECURITY", Const, 11}, + {"IMAGE_DIRECTORY_ENTRY_TLS", Const, 11}, + {"IMAGE_DLLCHARACTERISTICS_APPCONTAINER", Const, 15}, + {"IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE", Const, 15}, + {"IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY", Const, 15}, + {"IMAGE_DLLCHARACTERISTICS_GUARD_CF", Const, 15}, + {"IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA", Const, 15}, + {"IMAGE_DLLCHARACTERISTICS_NO_BIND", Const, 15}, + {"IMAGE_DLLCHARACTERISTICS_NO_ISOLATION", Const, 15}, + {"IMAGE_DLLCHARACTERISTICS_NO_SEH", Const, 15}, + {"IMAGE_DLLCHARACTERISTICS_NX_COMPAT", Const, 15}, + {"IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE", Const, 15}, + {"IMAGE_DLLCHARACTERISTICS_WDM_DRIVER", Const, 15}, + {"IMAGE_FILE_32BIT_MACHINE", Const, 15}, + {"IMAGE_FILE_AGGRESIVE_WS_TRIM", Const, 15}, + {"IMAGE_FILE_BYTES_REVERSED_HI", Const, 15}, + {"IMAGE_FILE_BYTES_REVERSED_LO", Const, 15}, + {"IMAGE_FILE_DEBUG_STRIPPED", Const, 15}, + {"IMAGE_FILE_DLL", Const, 15}, + {"IMAGE_FILE_EXECUTABLE_IMAGE", Const, 15}, + {"IMAGE_FILE_LARGE_ADDRESS_AWARE", Const, 15}, + {"IMAGE_FILE_LINE_NUMS_STRIPPED", Const, 15}, + {"IMAGE_FILE_LOCAL_SYMS_STRIPPED", Const, 15}, + {"IMAGE_FILE_MACHINE_AM33", Const, 0}, + {"IMAGE_FILE_MACHINE_AMD64", Const, 0}, + {"IMAGE_FILE_MACHINE_ARM", Const, 0}, + {"IMAGE_FILE_MACHINE_ARM64", Const, 11}, + {"IMAGE_FILE_MACHINE_ARMNT", Const, 12}, + {"IMAGE_FILE_MACHINE_EBC", Const, 0}, + {"IMAGE_FILE_MACHINE_I386", Const, 0}, + {"IMAGE_FILE_MACHINE_IA64", Const, 0}, + {"IMAGE_FILE_MACHINE_LOONGARCH32", Const, 19}, + {"IMAGE_FILE_MACHINE_LOONGARCH64", Const, 19}, + {"IMAGE_FILE_MACHINE_M32R", Const, 0}, + {"IMAGE_FILE_MACHINE_MIPS16", Const, 0}, + {"IMAGE_FILE_MACHINE_MIPSFPU", Const, 0}, + {"IMAGE_FILE_MACHINE_MIPSFPU16", Const, 0}, + {"IMAGE_FILE_MACHINE_POWERPC", Const, 0}, + {"IMAGE_FILE_MACHINE_POWERPCFP", Const, 0}, + {"IMAGE_FILE_MACHINE_R4000", Const, 0}, + {"IMAGE_FILE_MACHINE_RISCV128", Const, 20}, + {"IMAGE_FILE_MACHINE_RISCV32", Const, 20}, + {"IMAGE_FILE_MACHINE_RISCV64", Const, 20}, + {"IMAGE_FILE_MACHINE_SH3", Const, 0}, + {"IMAGE_FILE_MACHINE_SH3DSP", Const, 0}, + {"IMAGE_FILE_MACHINE_SH4", Const, 0}, + {"IMAGE_FILE_MACHINE_SH5", Const, 0}, + {"IMAGE_FILE_MACHINE_THUMB", Const, 0}, + {"IMAGE_FILE_MACHINE_UNKNOWN", Const, 0}, + {"IMAGE_FILE_MACHINE_WCEMIPSV2", Const, 0}, + {"IMAGE_FILE_NET_RUN_FROM_SWAP", Const, 15}, + {"IMAGE_FILE_RELOCS_STRIPPED", Const, 15}, + {"IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP", Const, 15}, + {"IMAGE_FILE_SYSTEM", Const, 15}, + {"IMAGE_FILE_UP_SYSTEM_ONLY", Const, 15}, + {"IMAGE_SCN_CNT_CODE", Const, 19}, + {"IMAGE_SCN_CNT_INITIALIZED_DATA", Const, 19}, + {"IMAGE_SCN_CNT_UNINITIALIZED_DATA", Const, 19}, + {"IMAGE_SCN_LNK_COMDAT", Const, 19}, + {"IMAGE_SCN_MEM_DISCARDABLE", Const, 19}, + {"IMAGE_SCN_MEM_EXECUTE", Const, 19}, + {"IMAGE_SCN_MEM_READ", Const, 19}, + {"IMAGE_SCN_MEM_WRITE", Const, 19}, + {"IMAGE_SUBSYSTEM_EFI_APPLICATION", Const, 15}, + {"IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER", Const, 15}, + {"IMAGE_SUBSYSTEM_EFI_ROM", Const, 15}, + {"IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER", Const, 15}, + {"IMAGE_SUBSYSTEM_NATIVE", Const, 15}, + {"IMAGE_SUBSYSTEM_NATIVE_WINDOWS", Const, 15}, + {"IMAGE_SUBSYSTEM_OS2_CUI", Const, 15}, + {"IMAGE_SUBSYSTEM_POSIX_CUI", Const, 15}, + {"IMAGE_SUBSYSTEM_UNKNOWN", Const, 15}, + {"IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION", Const, 15}, + {"IMAGE_SUBSYSTEM_WINDOWS_CE_GUI", Const, 15}, + {"IMAGE_SUBSYSTEM_WINDOWS_CUI", Const, 15}, + {"IMAGE_SUBSYSTEM_WINDOWS_GUI", Const, 15}, + {"IMAGE_SUBSYSTEM_XBOX", Const, 15}, + {"ImportDirectory", Type, 0}, + {"ImportDirectory.FirstThunk", Field, 0}, + {"ImportDirectory.ForwarderChain", Field, 0}, + {"ImportDirectory.Name", Field, 0}, + {"ImportDirectory.OriginalFirstThunk", Field, 0}, + {"ImportDirectory.TimeDateStamp", Field, 0}, + {"NewFile", Func, 0}, + {"Open", Func, 0}, + {"OptionalHeader32", Type, 3}, + {"OptionalHeader32.AddressOfEntryPoint", Field, 3}, + {"OptionalHeader32.BaseOfCode", Field, 3}, + {"OptionalHeader32.BaseOfData", Field, 3}, + {"OptionalHeader32.CheckSum", Field, 3}, + {"OptionalHeader32.DataDirectory", Field, 3}, + {"OptionalHeader32.DllCharacteristics", Field, 3}, + {"OptionalHeader32.FileAlignment", Field, 3}, + {"OptionalHeader32.ImageBase", Field, 3}, + {"OptionalHeader32.LoaderFlags", Field, 3}, + {"OptionalHeader32.Magic", Field, 3}, + {"OptionalHeader32.MajorImageVersion", Field, 3}, + {"OptionalHeader32.MajorLinkerVersion", Field, 3}, + {"OptionalHeader32.MajorOperatingSystemVersion", Field, 3}, + {"OptionalHeader32.MajorSubsystemVersion", Field, 3}, + {"OptionalHeader32.MinorImageVersion", Field, 3}, + {"OptionalHeader32.MinorLinkerVersion", Field, 3}, + {"OptionalHeader32.MinorOperatingSystemVersion", Field, 3}, + {"OptionalHeader32.MinorSubsystemVersion", Field, 3}, + {"OptionalHeader32.NumberOfRvaAndSizes", Field, 3}, + {"OptionalHeader32.SectionAlignment", Field, 3}, + {"OptionalHeader32.SizeOfCode", Field, 3}, + {"OptionalHeader32.SizeOfHeaders", Field, 3}, + {"OptionalHeader32.SizeOfHeapCommit", Field, 3}, + {"OptionalHeader32.SizeOfHeapReserve", Field, 3}, + {"OptionalHeader32.SizeOfImage", Field, 3}, + {"OptionalHeader32.SizeOfInitializedData", Field, 3}, + {"OptionalHeader32.SizeOfStackCommit", Field, 3}, + {"OptionalHeader32.SizeOfStackReserve", Field, 3}, + {"OptionalHeader32.SizeOfUninitializedData", Field, 3}, + {"OptionalHeader32.Subsystem", Field, 3}, + {"OptionalHeader32.Win32VersionValue", Field, 3}, + {"OptionalHeader64", Type, 3}, + {"OptionalHeader64.AddressOfEntryPoint", Field, 3}, + {"OptionalHeader64.BaseOfCode", Field, 3}, + {"OptionalHeader64.CheckSum", Field, 3}, + {"OptionalHeader64.DataDirectory", Field, 3}, + {"OptionalHeader64.DllCharacteristics", Field, 3}, + {"OptionalHeader64.FileAlignment", Field, 3}, + {"OptionalHeader64.ImageBase", Field, 3}, + {"OptionalHeader64.LoaderFlags", Field, 3}, + {"OptionalHeader64.Magic", Field, 3}, + {"OptionalHeader64.MajorImageVersion", Field, 3}, + {"OptionalHeader64.MajorLinkerVersion", Field, 3}, + {"OptionalHeader64.MajorOperatingSystemVersion", Field, 3}, + {"OptionalHeader64.MajorSubsystemVersion", Field, 3}, + {"OptionalHeader64.MinorImageVersion", Field, 3}, + {"OptionalHeader64.MinorLinkerVersion", Field, 3}, + {"OptionalHeader64.MinorOperatingSystemVersion", Field, 3}, + {"OptionalHeader64.MinorSubsystemVersion", Field, 3}, + {"OptionalHeader64.NumberOfRvaAndSizes", Field, 3}, + {"OptionalHeader64.SectionAlignment", Field, 3}, + {"OptionalHeader64.SizeOfCode", Field, 3}, + {"OptionalHeader64.SizeOfHeaders", Field, 3}, + {"OptionalHeader64.SizeOfHeapCommit", Field, 3}, + {"OptionalHeader64.SizeOfHeapReserve", Field, 3}, + {"OptionalHeader64.SizeOfImage", Field, 3}, + {"OptionalHeader64.SizeOfInitializedData", Field, 3}, + {"OptionalHeader64.SizeOfStackCommit", Field, 3}, + {"OptionalHeader64.SizeOfStackReserve", Field, 3}, + {"OptionalHeader64.SizeOfUninitializedData", Field, 3}, + {"OptionalHeader64.Subsystem", Field, 3}, + {"OptionalHeader64.Win32VersionValue", Field, 3}, + {"Reloc", Type, 8}, + {"Reloc.SymbolTableIndex", Field, 8}, + {"Reloc.Type", Field, 8}, + {"Reloc.VirtualAddress", Field, 8}, + {"Section", Type, 0}, + {"Section.ReaderAt", Field, 0}, + {"Section.Relocs", Field, 8}, + {"Section.SectionHeader", Field, 0}, + {"SectionHeader", Type, 0}, + {"SectionHeader.Characteristics", Field, 0}, + {"SectionHeader.Name", Field, 0}, + {"SectionHeader.NumberOfLineNumbers", Field, 0}, + {"SectionHeader.NumberOfRelocations", Field, 0}, + {"SectionHeader.Offset", Field, 0}, + {"SectionHeader.PointerToLineNumbers", Field, 0}, + {"SectionHeader.PointerToRelocations", Field, 0}, + {"SectionHeader.Size", Field, 0}, + {"SectionHeader.VirtualAddress", Field, 0}, + {"SectionHeader.VirtualSize", Field, 0}, + {"SectionHeader32", Type, 0}, + {"SectionHeader32.Characteristics", Field, 0}, + {"SectionHeader32.Name", Field, 0}, + {"SectionHeader32.NumberOfLineNumbers", Field, 0}, + {"SectionHeader32.NumberOfRelocations", Field, 0}, + {"SectionHeader32.PointerToLineNumbers", Field, 0}, + {"SectionHeader32.PointerToRawData", Field, 0}, + {"SectionHeader32.PointerToRelocations", Field, 0}, + {"SectionHeader32.SizeOfRawData", Field, 0}, + {"SectionHeader32.VirtualAddress", Field, 0}, + {"SectionHeader32.VirtualSize", Field, 0}, + {"StringTable", Type, 8}, + {"Symbol", Type, 1}, + {"Symbol.Name", Field, 1}, + {"Symbol.SectionNumber", Field, 1}, + {"Symbol.StorageClass", Field, 1}, + {"Symbol.Type", Field, 1}, + {"Symbol.Value", Field, 1}, + }, + "debug/plan9obj": { + {"(*File).Close", Method, 3}, + {"(*File).Section", Method, 3}, + {"(*File).Symbols", Method, 3}, + {"(*Section).Data", Method, 3}, + {"(*Section).Open", Method, 3}, + {"(Section).ReadAt", Method, 3}, + {"ErrNoSymbols", Var, 18}, + {"File", Type, 3}, + {"File.FileHeader", Field, 3}, + {"File.Sections", Field, 3}, + {"FileHeader", Type, 3}, + {"FileHeader.Bss", Field, 3}, + {"FileHeader.Entry", Field, 3}, + {"FileHeader.HdrSize", Field, 4}, + {"FileHeader.LoadAddress", Field, 4}, + {"FileHeader.Magic", Field, 3}, + {"FileHeader.PtrSize", Field, 3}, + {"Magic386", Const, 3}, + {"Magic64", Const, 3}, + {"MagicAMD64", Const, 3}, + {"MagicARM", Const, 3}, + {"NewFile", Func, 3}, + {"Open", Func, 3}, + {"Section", Type, 3}, + {"Section.ReaderAt", Field, 3}, + {"Section.SectionHeader", Field, 3}, + {"SectionHeader", Type, 3}, + {"SectionHeader.Name", Field, 3}, + {"SectionHeader.Offset", Field, 3}, + {"SectionHeader.Size", Field, 3}, + {"Sym", Type, 3}, + {"Sym.Name", Field, 3}, + {"Sym.Type", Field, 3}, + {"Sym.Value", Field, 3}, + }, + "embed": { + {"(FS).Open", Method, 16}, + {"(FS).ReadDir", Method, 16}, + {"(FS).ReadFile", Method, 16}, + {"FS", Type, 16}, + }, + "encoding": { + {"BinaryMarshaler", Type, 2}, + {"BinaryUnmarshaler", Type, 2}, + {"TextMarshaler", Type, 2}, + {"TextUnmarshaler", Type, 2}, + }, + "encoding/ascii85": { + {"(CorruptInputError).Error", Method, 0}, + {"CorruptInputError", Type, 0}, + {"Decode", Func, 0}, + {"Encode", Func, 0}, + {"MaxEncodedLen", Func, 0}, + {"NewDecoder", Func, 0}, + {"NewEncoder", Func, 0}, + }, + "encoding/asn1": { + {"(BitString).At", Method, 0}, + {"(BitString).RightAlign", Method, 0}, + {"(ObjectIdentifier).Equal", Method, 0}, + {"(ObjectIdentifier).String", Method, 3}, + {"(StructuralError).Error", Method, 0}, + {"(SyntaxError).Error", Method, 0}, + {"BitString", Type, 0}, + {"BitString.BitLength", Field, 0}, + {"BitString.Bytes", Field, 0}, + {"ClassApplication", Const, 6}, + {"ClassContextSpecific", Const, 6}, + {"ClassPrivate", Const, 6}, + {"ClassUniversal", Const, 6}, + {"Enumerated", Type, 0}, + {"Flag", Type, 0}, + {"Marshal", Func, 0}, + {"MarshalWithParams", Func, 10}, + {"NullBytes", Var, 9}, + {"NullRawValue", Var, 9}, + {"ObjectIdentifier", Type, 0}, + {"RawContent", Type, 0}, + {"RawValue", Type, 0}, + {"RawValue.Bytes", Field, 0}, + {"RawValue.Class", Field, 0}, + {"RawValue.FullBytes", Field, 0}, + {"RawValue.IsCompound", Field, 0}, + {"RawValue.Tag", Field, 0}, + {"StructuralError", Type, 0}, + {"StructuralError.Msg", Field, 0}, + {"SyntaxError", Type, 0}, + {"SyntaxError.Msg", Field, 0}, + {"TagBMPString", Const, 14}, + {"TagBitString", Const, 6}, + {"TagBoolean", Const, 6}, + {"TagEnum", Const, 6}, + {"TagGeneralString", Const, 6}, + {"TagGeneralizedTime", Const, 6}, + {"TagIA5String", Const, 6}, + {"TagInteger", Const, 6}, + {"TagNull", Const, 9}, + {"TagNumericString", Const, 10}, + {"TagOID", Const, 6}, + {"TagOctetString", Const, 6}, + {"TagPrintableString", Const, 6}, + {"TagSequence", Const, 6}, + {"TagSet", Const, 6}, + {"TagT61String", Const, 6}, + {"TagUTCTime", Const, 6}, + {"TagUTF8String", Const, 6}, + {"Unmarshal", Func, 0}, + {"UnmarshalWithParams", Func, 0}, + }, + "encoding/base32": { + {"(*Encoding).AppendDecode", Method, 22}, + {"(*Encoding).AppendEncode", Method, 22}, + {"(*Encoding).Decode", Method, 0}, + {"(*Encoding).DecodeString", Method, 0}, + {"(*Encoding).DecodedLen", Method, 0}, + {"(*Encoding).Encode", Method, 0}, + {"(*Encoding).EncodeToString", Method, 0}, + {"(*Encoding).EncodedLen", Method, 0}, + {"(CorruptInputError).Error", Method, 0}, + {"(Encoding).WithPadding", Method, 9}, + {"CorruptInputError", Type, 0}, + {"Encoding", Type, 0}, + {"HexEncoding", Var, 0}, + {"NewDecoder", Func, 0}, + {"NewEncoder", Func, 0}, + {"NewEncoding", Func, 0}, + {"NoPadding", Const, 9}, + {"StdEncoding", Var, 0}, + {"StdPadding", Const, 9}, + }, + "encoding/base64": { + {"(*Encoding).AppendDecode", Method, 22}, + {"(*Encoding).AppendEncode", Method, 22}, + {"(*Encoding).Decode", Method, 0}, + {"(*Encoding).DecodeString", Method, 0}, + {"(*Encoding).DecodedLen", Method, 0}, + {"(*Encoding).Encode", Method, 0}, + {"(*Encoding).EncodeToString", Method, 0}, + {"(*Encoding).EncodedLen", Method, 0}, + {"(CorruptInputError).Error", Method, 0}, + {"(Encoding).Strict", Method, 8}, + {"(Encoding).WithPadding", Method, 5}, + {"CorruptInputError", Type, 0}, + {"Encoding", Type, 0}, + {"NewDecoder", Func, 0}, + {"NewEncoder", Func, 0}, + {"NewEncoding", Func, 0}, + {"NoPadding", Const, 5}, + {"RawStdEncoding", Var, 5}, + {"RawURLEncoding", Var, 5}, + {"StdEncoding", Var, 0}, + {"StdPadding", Const, 5}, + {"URLEncoding", Var, 0}, + }, + "encoding/binary": { + {"AppendByteOrder", Type, 19}, + {"AppendUvarint", Func, 19}, + {"AppendVarint", Func, 19}, + {"BigEndian", Var, 0}, + {"ByteOrder", Type, 0}, + {"LittleEndian", Var, 0}, + {"MaxVarintLen16", Const, 0}, + {"MaxVarintLen32", Const, 0}, + {"MaxVarintLen64", Const, 0}, + {"NativeEndian", Var, 21}, + {"PutUvarint", Func, 0}, + {"PutVarint", Func, 0}, + {"Read", Func, 0}, + {"ReadUvarint", Func, 0}, + {"ReadVarint", Func, 0}, + {"Size", Func, 0}, + {"Uvarint", Func, 0}, + {"Varint", Func, 0}, + {"Write", Func, 0}, + }, + "encoding/csv": { + {"(*ParseError).Error", Method, 0}, + {"(*ParseError).Unwrap", Method, 13}, + {"(*Reader).FieldPos", Method, 17}, + {"(*Reader).InputOffset", Method, 19}, + {"(*Reader).Read", Method, 0}, + {"(*Reader).ReadAll", Method, 0}, + {"(*Writer).Error", Method, 1}, + {"(*Writer).Flush", Method, 0}, + {"(*Writer).Write", Method, 0}, + {"(*Writer).WriteAll", Method, 0}, + {"ErrBareQuote", Var, 0}, + {"ErrFieldCount", Var, 0}, + {"ErrQuote", Var, 0}, + {"ErrTrailingComma", Var, 0}, + {"NewReader", Func, 0}, + {"NewWriter", Func, 0}, + {"ParseError", Type, 0}, + {"ParseError.Column", Field, 0}, + {"ParseError.Err", Field, 0}, + {"ParseError.Line", Field, 0}, + {"ParseError.StartLine", Field, 10}, + {"Reader", Type, 0}, + {"Reader.Comma", Field, 0}, + {"Reader.Comment", Field, 0}, + {"Reader.FieldsPerRecord", Field, 0}, + {"Reader.LazyQuotes", Field, 0}, + {"Reader.ReuseRecord", Field, 9}, + {"Reader.TrailingComma", Field, 0}, + {"Reader.TrimLeadingSpace", Field, 0}, + {"Writer", Type, 0}, + {"Writer.Comma", Field, 0}, + {"Writer.UseCRLF", Field, 0}, + }, + "encoding/gob": { + {"(*Decoder).Decode", Method, 0}, + {"(*Decoder).DecodeValue", Method, 0}, + {"(*Encoder).Encode", Method, 0}, + {"(*Encoder).EncodeValue", Method, 0}, + {"CommonType", Type, 0}, + {"CommonType.Id", Field, 0}, + {"CommonType.Name", Field, 0}, + {"Decoder", Type, 0}, + {"Encoder", Type, 0}, + {"GobDecoder", Type, 0}, + {"GobEncoder", Type, 0}, + {"NewDecoder", Func, 0}, + {"NewEncoder", Func, 0}, + {"Register", Func, 0}, + {"RegisterName", Func, 0}, + }, + "encoding/hex": { + {"(InvalidByteError).Error", Method, 0}, + {"AppendDecode", Func, 22}, + {"AppendEncode", Func, 22}, + {"Decode", Func, 0}, + {"DecodeString", Func, 0}, + {"DecodedLen", Func, 0}, + {"Dump", Func, 0}, + {"Dumper", Func, 0}, + {"Encode", Func, 0}, + {"EncodeToString", Func, 0}, + {"EncodedLen", Func, 0}, + {"ErrLength", Var, 0}, + {"InvalidByteError", Type, 0}, + {"NewDecoder", Func, 10}, + {"NewEncoder", Func, 10}, + }, + "encoding/json": { + {"(*Decoder).Buffered", Method, 1}, + {"(*Decoder).Decode", Method, 0}, + {"(*Decoder).DisallowUnknownFields", Method, 10}, + {"(*Decoder).InputOffset", Method, 14}, + {"(*Decoder).More", Method, 5}, + {"(*Decoder).Token", Method, 5}, + {"(*Decoder).UseNumber", Method, 1}, + {"(*Encoder).Encode", Method, 0}, + {"(*Encoder).SetEscapeHTML", Method, 7}, + {"(*Encoder).SetIndent", Method, 7}, + {"(*InvalidUTF8Error).Error", Method, 0}, + {"(*InvalidUnmarshalError).Error", Method, 0}, + {"(*MarshalerError).Error", Method, 0}, + {"(*MarshalerError).Unwrap", Method, 13}, + {"(*RawMessage).MarshalJSON", Method, 0}, + {"(*RawMessage).UnmarshalJSON", Method, 0}, + {"(*SyntaxError).Error", Method, 0}, + {"(*UnmarshalFieldError).Error", Method, 0}, + {"(*UnmarshalTypeError).Error", Method, 0}, + {"(*UnsupportedTypeError).Error", Method, 0}, + {"(*UnsupportedValueError).Error", Method, 0}, + {"(Delim).String", Method, 5}, + {"(Number).Float64", Method, 1}, + {"(Number).Int64", Method, 1}, + {"(Number).String", Method, 1}, + {"(RawMessage).MarshalJSON", Method, 8}, + {"Compact", Func, 0}, + {"Decoder", Type, 0}, + {"Delim", Type, 5}, + {"Encoder", Type, 0}, + {"HTMLEscape", Func, 0}, + {"Indent", Func, 0}, + {"InvalidUTF8Error", Type, 0}, + {"InvalidUTF8Error.S", Field, 0}, + {"InvalidUnmarshalError", Type, 0}, + {"InvalidUnmarshalError.Type", Field, 0}, + {"Marshal", Func, 0}, + {"MarshalIndent", Func, 0}, + {"Marshaler", Type, 0}, + {"MarshalerError", Type, 0}, + {"MarshalerError.Err", Field, 0}, + {"MarshalerError.Type", Field, 0}, + {"NewDecoder", Func, 0}, + {"NewEncoder", Func, 0}, + {"Number", Type, 1}, + {"RawMessage", Type, 0}, + {"SyntaxError", Type, 0}, + {"SyntaxError.Offset", Field, 0}, + {"Token", Type, 5}, + {"Unmarshal", Func, 0}, + {"UnmarshalFieldError", Type, 0}, + {"UnmarshalFieldError.Field", Field, 0}, + {"UnmarshalFieldError.Key", Field, 0}, + {"UnmarshalFieldError.Type", Field, 0}, + {"UnmarshalTypeError", Type, 0}, + {"UnmarshalTypeError.Field", Field, 8}, + {"UnmarshalTypeError.Offset", Field, 5}, + {"UnmarshalTypeError.Struct", Field, 8}, + {"UnmarshalTypeError.Type", Field, 0}, + {"UnmarshalTypeError.Value", Field, 0}, + {"Unmarshaler", Type, 0}, + {"UnsupportedTypeError", Type, 0}, + {"UnsupportedTypeError.Type", Field, 0}, + {"UnsupportedValueError", Type, 0}, + {"UnsupportedValueError.Str", Field, 0}, + {"UnsupportedValueError.Value", Field, 0}, + {"Valid", Func, 9}, + }, + "encoding/pem": { + {"Block", Type, 0}, + {"Block.Bytes", Field, 0}, + {"Block.Headers", Field, 0}, + {"Block.Type", Field, 0}, + {"Decode", Func, 0}, + {"Encode", Func, 0}, + {"EncodeToMemory", Func, 0}, + }, + "encoding/xml": { + {"(*Decoder).Decode", Method, 0}, + {"(*Decoder).DecodeElement", Method, 0}, + {"(*Decoder).InputOffset", Method, 4}, + {"(*Decoder).InputPos", Method, 19}, + {"(*Decoder).RawToken", Method, 0}, + {"(*Decoder).Skip", Method, 0}, + {"(*Decoder).Token", Method, 0}, + {"(*Encoder).Close", Method, 20}, + {"(*Encoder).Encode", Method, 0}, + {"(*Encoder).EncodeElement", Method, 2}, + {"(*Encoder).EncodeToken", Method, 2}, + {"(*Encoder).Flush", Method, 2}, + {"(*Encoder).Indent", Method, 1}, + {"(*SyntaxError).Error", Method, 0}, + {"(*TagPathError).Error", Method, 0}, + {"(*UnsupportedTypeError).Error", Method, 0}, + {"(CharData).Copy", Method, 0}, + {"(Comment).Copy", Method, 0}, + {"(Directive).Copy", Method, 0}, + {"(ProcInst).Copy", Method, 0}, + {"(StartElement).Copy", Method, 0}, + {"(StartElement).End", Method, 2}, + {"(UnmarshalError).Error", Method, 0}, + {"Attr", Type, 0}, + {"Attr.Name", Field, 0}, + {"Attr.Value", Field, 0}, + {"CharData", Type, 0}, + {"Comment", Type, 0}, + {"CopyToken", Func, 0}, + {"Decoder", Type, 0}, + {"Decoder.AutoClose", Field, 0}, + {"Decoder.CharsetReader", Field, 0}, + {"Decoder.DefaultSpace", Field, 1}, + {"Decoder.Entity", Field, 0}, + {"Decoder.Strict", Field, 0}, + {"Directive", Type, 0}, + {"Encoder", Type, 0}, + {"EndElement", Type, 0}, + {"EndElement.Name", Field, 0}, + {"Escape", Func, 0}, + {"EscapeText", Func, 1}, + {"HTMLAutoClose", Var, 0}, + {"HTMLEntity", Var, 0}, + {"Header", Const, 0}, + {"Marshal", Func, 0}, + {"MarshalIndent", Func, 0}, + {"Marshaler", Type, 2}, + {"MarshalerAttr", Type, 2}, + {"Name", Type, 0}, + {"Name.Local", Field, 0}, + {"Name.Space", Field, 0}, + {"NewDecoder", Func, 0}, + {"NewEncoder", Func, 0}, + {"NewTokenDecoder", Func, 10}, + {"ProcInst", Type, 0}, + {"ProcInst.Inst", Field, 0}, + {"ProcInst.Target", Field, 0}, + {"StartElement", Type, 0}, + {"StartElement.Attr", Field, 0}, + {"StartElement.Name", Field, 0}, + {"SyntaxError", Type, 0}, + {"SyntaxError.Line", Field, 0}, + {"SyntaxError.Msg", Field, 0}, + {"TagPathError", Type, 0}, + {"TagPathError.Field1", Field, 0}, + {"TagPathError.Field2", Field, 0}, + {"TagPathError.Struct", Field, 0}, + {"TagPathError.Tag1", Field, 0}, + {"TagPathError.Tag2", Field, 0}, + {"Token", Type, 0}, + {"TokenReader", Type, 10}, + {"Unmarshal", Func, 0}, + {"UnmarshalError", Type, 0}, + {"Unmarshaler", Type, 2}, + {"UnmarshalerAttr", Type, 2}, + {"UnsupportedTypeError", Type, 0}, + {"UnsupportedTypeError.Type", Field, 0}, + }, + "errors": { + {"As", Func, 13}, + {"ErrUnsupported", Var, 21}, + {"Is", Func, 13}, + {"Join", Func, 20}, + {"New", Func, 0}, + {"Unwrap", Func, 13}, + }, + "expvar": { + {"(*Float).Add", Method, 0}, + {"(*Float).Set", Method, 0}, + {"(*Float).String", Method, 0}, + {"(*Float).Value", Method, 8}, + {"(*Int).Add", Method, 0}, + {"(*Int).Set", Method, 0}, + {"(*Int).String", Method, 0}, + {"(*Int).Value", Method, 8}, + {"(*Map).Add", Method, 0}, + {"(*Map).AddFloat", Method, 0}, + {"(*Map).Delete", Method, 12}, + {"(*Map).Do", Method, 0}, + {"(*Map).Get", Method, 0}, + {"(*Map).Init", Method, 0}, + {"(*Map).Set", Method, 0}, + {"(*Map).String", Method, 0}, + {"(*String).Set", Method, 0}, + {"(*String).String", Method, 0}, + {"(*String).Value", Method, 8}, + {"(Func).String", Method, 0}, + {"(Func).Value", Method, 8}, + {"Do", Func, 0}, + {"Float", Type, 0}, + {"Func", Type, 0}, + {"Get", Func, 0}, + {"Handler", Func, 8}, + {"Int", Type, 0}, + {"KeyValue", Type, 0}, + {"KeyValue.Key", Field, 0}, + {"KeyValue.Value", Field, 0}, + {"Map", Type, 0}, + {"NewFloat", Func, 0}, + {"NewInt", Func, 0}, + {"NewMap", Func, 0}, + {"NewString", Func, 0}, + {"Publish", Func, 0}, + {"String", Type, 0}, + {"Var", Type, 0}, + }, + "flag": { + {"(*FlagSet).Arg", Method, 0}, + {"(*FlagSet).Args", Method, 0}, + {"(*FlagSet).Bool", Method, 0}, + {"(*FlagSet).BoolFunc", Method, 21}, + {"(*FlagSet).BoolVar", Method, 0}, + {"(*FlagSet).Duration", Method, 0}, + {"(*FlagSet).DurationVar", Method, 0}, + {"(*FlagSet).ErrorHandling", Method, 10}, + {"(*FlagSet).Float64", Method, 0}, + {"(*FlagSet).Float64Var", Method, 0}, + {"(*FlagSet).Func", Method, 16}, + {"(*FlagSet).Init", Method, 0}, + {"(*FlagSet).Int", Method, 0}, + {"(*FlagSet).Int64", Method, 0}, + {"(*FlagSet).Int64Var", Method, 0}, + {"(*FlagSet).IntVar", Method, 0}, + {"(*FlagSet).Lookup", Method, 0}, + {"(*FlagSet).NArg", Method, 0}, + {"(*FlagSet).NFlag", Method, 0}, + {"(*FlagSet).Name", Method, 10}, + {"(*FlagSet).Output", Method, 10}, + {"(*FlagSet).Parse", Method, 0}, + {"(*FlagSet).Parsed", Method, 0}, + {"(*FlagSet).PrintDefaults", Method, 0}, + {"(*FlagSet).Set", Method, 0}, + {"(*FlagSet).SetOutput", Method, 0}, + {"(*FlagSet).String", Method, 0}, + {"(*FlagSet).StringVar", Method, 0}, + {"(*FlagSet).TextVar", Method, 19}, + {"(*FlagSet).Uint", Method, 0}, + {"(*FlagSet).Uint64", Method, 0}, + {"(*FlagSet).Uint64Var", Method, 0}, + {"(*FlagSet).UintVar", Method, 0}, + {"(*FlagSet).Var", Method, 0}, + {"(*FlagSet).Visit", Method, 0}, + {"(*FlagSet).VisitAll", Method, 0}, + {"Arg", Func, 0}, + {"Args", Func, 0}, + {"Bool", Func, 0}, + {"BoolFunc", Func, 21}, + {"BoolVar", Func, 0}, + {"CommandLine", Var, 2}, + {"ContinueOnError", Const, 0}, + {"Duration", Func, 0}, + {"DurationVar", Func, 0}, + {"ErrHelp", Var, 0}, + {"ErrorHandling", Type, 0}, + {"ExitOnError", Const, 0}, + {"Flag", Type, 0}, + {"Flag.DefValue", Field, 0}, + {"Flag.Name", Field, 0}, + {"Flag.Usage", Field, 0}, + {"Flag.Value", Field, 0}, + {"FlagSet", Type, 0}, + {"FlagSet.Usage", Field, 0}, + {"Float64", Func, 0}, + {"Float64Var", Func, 0}, + {"Func", Func, 16}, + {"Getter", Type, 2}, + {"Int", Func, 0}, + {"Int64", Func, 0}, + {"Int64Var", Func, 0}, + {"IntVar", Func, 0}, + {"Lookup", Func, 0}, + {"NArg", Func, 0}, + {"NFlag", Func, 0}, + {"NewFlagSet", Func, 0}, + {"PanicOnError", Const, 0}, + {"Parse", Func, 0}, + {"Parsed", Func, 0}, + {"PrintDefaults", Func, 0}, + {"Set", Func, 0}, + {"String", Func, 0}, + {"StringVar", Func, 0}, + {"TextVar", Func, 19}, + {"Uint", Func, 0}, + {"Uint64", Func, 0}, + {"Uint64Var", Func, 0}, + {"UintVar", Func, 0}, + {"UnquoteUsage", Func, 5}, + {"Usage", Var, 0}, + {"Value", Type, 0}, + {"Var", Func, 0}, + {"Visit", Func, 0}, + {"VisitAll", Func, 0}, + }, + "fmt": { + {"Append", Func, 19}, + {"Appendf", Func, 19}, + {"Appendln", Func, 19}, + {"Errorf", Func, 0}, + {"FormatString", Func, 20}, + {"Formatter", Type, 0}, + {"Fprint", Func, 0}, + {"Fprintf", Func, 0}, + {"Fprintln", Func, 0}, + {"Fscan", Func, 0}, + {"Fscanf", Func, 0}, + {"Fscanln", Func, 0}, + {"GoStringer", Type, 0}, + {"Print", Func, 0}, + {"Printf", Func, 0}, + {"Println", Func, 0}, + {"Scan", Func, 0}, + {"ScanState", Type, 0}, + {"Scanf", Func, 0}, + {"Scanln", Func, 0}, + {"Scanner", Type, 0}, + {"Sprint", Func, 0}, + {"Sprintf", Func, 0}, + {"Sprintln", Func, 0}, + {"Sscan", Func, 0}, + {"Sscanf", Func, 0}, + {"Sscanln", Func, 0}, + {"State", Type, 0}, + {"Stringer", Type, 0}, + }, + "go/ast": { + {"(*ArrayType).End", Method, 0}, + {"(*ArrayType).Pos", Method, 0}, + {"(*AssignStmt).End", Method, 0}, + {"(*AssignStmt).Pos", Method, 0}, + {"(*BadDecl).End", Method, 0}, + {"(*BadDecl).Pos", Method, 0}, + {"(*BadExpr).End", Method, 0}, + {"(*BadExpr).Pos", Method, 0}, + {"(*BadStmt).End", Method, 0}, + {"(*BadStmt).Pos", Method, 0}, + {"(*BasicLit).End", Method, 0}, + {"(*BasicLit).Pos", Method, 0}, + {"(*BinaryExpr).End", Method, 0}, + {"(*BinaryExpr).Pos", Method, 0}, + {"(*BlockStmt).End", Method, 0}, + {"(*BlockStmt).Pos", Method, 0}, + {"(*BranchStmt).End", Method, 0}, + {"(*BranchStmt).Pos", Method, 0}, + {"(*CallExpr).End", Method, 0}, + {"(*CallExpr).Pos", Method, 0}, + {"(*CaseClause).End", Method, 0}, + {"(*CaseClause).Pos", Method, 0}, + {"(*ChanType).End", Method, 0}, + {"(*ChanType).Pos", Method, 0}, + {"(*CommClause).End", Method, 0}, + {"(*CommClause).Pos", Method, 0}, + {"(*Comment).End", Method, 0}, + {"(*Comment).Pos", Method, 0}, + {"(*CommentGroup).End", Method, 0}, + {"(*CommentGroup).Pos", Method, 0}, + {"(*CommentGroup).Text", Method, 0}, + {"(*CompositeLit).End", Method, 0}, + {"(*CompositeLit).Pos", Method, 0}, + {"(*DeclStmt).End", Method, 0}, + {"(*DeclStmt).Pos", Method, 0}, + {"(*DeferStmt).End", Method, 0}, + {"(*DeferStmt).Pos", Method, 0}, + {"(*Ellipsis).End", Method, 0}, + {"(*Ellipsis).Pos", Method, 0}, + {"(*EmptyStmt).End", Method, 0}, + {"(*EmptyStmt).Pos", Method, 0}, + {"(*ExprStmt).End", Method, 0}, + {"(*ExprStmt).Pos", Method, 0}, + {"(*Field).End", Method, 0}, + {"(*Field).Pos", Method, 0}, + {"(*FieldList).End", Method, 0}, + {"(*FieldList).NumFields", Method, 0}, + {"(*FieldList).Pos", Method, 0}, + {"(*File).End", Method, 0}, + {"(*File).Pos", Method, 0}, + {"(*ForStmt).End", Method, 0}, + {"(*ForStmt).Pos", Method, 0}, + {"(*FuncDecl).End", Method, 0}, + {"(*FuncDecl).Pos", Method, 0}, + {"(*FuncLit).End", Method, 0}, + {"(*FuncLit).Pos", Method, 0}, + {"(*FuncType).End", Method, 0}, + {"(*FuncType).Pos", Method, 0}, + {"(*GenDecl).End", Method, 0}, + {"(*GenDecl).Pos", Method, 0}, + {"(*GoStmt).End", Method, 0}, + {"(*GoStmt).Pos", Method, 0}, + {"(*Ident).End", Method, 0}, + {"(*Ident).IsExported", Method, 0}, + {"(*Ident).Pos", Method, 0}, + {"(*Ident).String", Method, 0}, + {"(*IfStmt).End", Method, 0}, + {"(*IfStmt).Pos", Method, 0}, + {"(*ImportSpec).End", Method, 0}, + {"(*ImportSpec).Pos", Method, 0}, + {"(*IncDecStmt).End", Method, 0}, + {"(*IncDecStmt).Pos", Method, 0}, + {"(*IndexExpr).End", Method, 0}, + {"(*IndexExpr).Pos", Method, 0}, + {"(*IndexListExpr).End", Method, 18}, + {"(*IndexListExpr).Pos", Method, 18}, + {"(*InterfaceType).End", Method, 0}, + {"(*InterfaceType).Pos", Method, 0}, + {"(*KeyValueExpr).End", Method, 0}, + {"(*KeyValueExpr).Pos", Method, 0}, + {"(*LabeledStmt).End", Method, 0}, + {"(*LabeledStmt).Pos", Method, 0}, + {"(*MapType).End", Method, 0}, + {"(*MapType).Pos", Method, 0}, + {"(*Object).Pos", Method, 0}, + {"(*Package).End", Method, 0}, + {"(*Package).Pos", Method, 0}, + {"(*ParenExpr).End", Method, 0}, + {"(*ParenExpr).Pos", Method, 0}, + {"(*RangeStmt).End", Method, 0}, + {"(*RangeStmt).Pos", Method, 0}, + {"(*ReturnStmt).End", Method, 0}, + {"(*ReturnStmt).Pos", Method, 0}, + {"(*Scope).Insert", Method, 0}, + {"(*Scope).Lookup", Method, 0}, + {"(*Scope).String", Method, 0}, + {"(*SelectStmt).End", Method, 0}, + {"(*SelectStmt).Pos", Method, 0}, + {"(*SelectorExpr).End", Method, 0}, + {"(*SelectorExpr).Pos", Method, 0}, + {"(*SendStmt).End", Method, 0}, + {"(*SendStmt).Pos", Method, 0}, + {"(*SliceExpr).End", Method, 0}, + {"(*SliceExpr).Pos", Method, 0}, + {"(*StarExpr).End", Method, 0}, + {"(*StarExpr).Pos", Method, 0}, + {"(*StructType).End", Method, 0}, + {"(*StructType).Pos", Method, 0}, + {"(*SwitchStmt).End", Method, 0}, + {"(*SwitchStmt).Pos", Method, 0}, + {"(*TypeAssertExpr).End", Method, 0}, + {"(*TypeAssertExpr).Pos", Method, 0}, + {"(*TypeSpec).End", Method, 0}, + {"(*TypeSpec).Pos", Method, 0}, + {"(*TypeSwitchStmt).End", Method, 0}, + {"(*TypeSwitchStmt).Pos", Method, 0}, + {"(*UnaryExpr).End", Method, 0}, + {"(*UnaryExpr).Pos", Method, 0}, + {"(*ValueSpec).End", Method, 0}, + {"(*ValueSpec).Pos", Method, 0}, + {"(CommentMap).Comments", Method, 1}, + {"(CommentMap).Filter", Method, 1}, + {"(CommentMap).String", Method, 1}, + {"(CommentMap).Update", Method, 1}, + {"(ObjKind).String", Method, 0}, + {"ArrayType", Type, 0}, + {"ArrayType.Elt", Field, 0}, + {"ArrayType.Lbrack", Field, 0}, + {"ArrayType.Len", Field, 0}, + {"AssignStmt", Type, 0}, + {"AssignStmt.Lhs", Field, 0}, + {"AssignStmt.Rhs", Field, 0}, + {"AssignStmt.Tok", Field, 0}, + {"AssignStmt.TokPos", Field, 0}, + {"Bad", Const, 0}, + {"BadDecl", Type, 0}, + {"BadDecl.From", Field, 0}, + {"BadDecl.To", Field, 0}, + {"BadExpr", Type, 0}, + {"BadExpr.From", Field, 0}, + {"BadExpr.To", Field, 0}, + {"BadStmt", Type, 0}, + {"BadStmt.From", Field, 0}, + {"BadStmt.To", Field, 0}, + {"BasicLit", Type, 0}, + {"BasicLit.Kind", Field, 0}, + {"BasicLit.Value", Field, 0}, + {"BasicLit.ValuePos", Field, 0}, + {"BinaryExpr", Type, 0}, + {"BinaryExpr.Op", Field, 0}, + {"BinaryExpr.OpPos", Field, 0}, + {"BinaryExpr.X", Field, 0}, + {"BinaryExpr.Y", Field, 0}, + {"BlockStmt", Type, 0}, + {"BlockStmt.Lbrace", Field, 0}, + {"BlockStmt.List", Field, 0}, + {"BlockStmt.Rbrace", Field, 0}, + {"BranchStmt", Type, 0}, + {"BranchStmt.Label", Field, 0}, + {"BranchStmt.Tok", Field, 0}, + {"BranchStmt.TokPos", Field, 0}, + {"CallExpr", Type, 0}, + {"CallExpr.Args", Field, 0}, + {"CallExpr.Ellipsis", Field, 0}, + {"CallExpr.Fun", Field, 0}, + {"CallExpr.Lparen", Field, 0}, + {"CallExpr.Rparen", Field, 0}, + {"CaseClause", Type, 0}, + {"CaseClause.Body", Field, 0}, + {"CaseClause.Case", Field, 0}, + {"CaseClause.Colon", Field, 0}, + {"CaseClause.List", Field, 0}, + {"ChanDir", Type, 0}, + {"ChanType", Type, 0}, + {"ChanType.Arrow", Field, 1}, + {"ChanType.Begin", Field, 0}, + {"ChanType.Dir", Field, 0}, + {"ChanType.Value", Field, 0}, + {"CommClause", Type, 0}, + {"CommClause.Body", Field, 0}, + {"CommClause.Case", Field, 0}, + {"CommClause.Colon", Field, 0}, + {"CommClause.Comm", Field, 0}, + {"Comment", Type, 0}, + {"Comment.Slash", Field, 0}, + {"Comment.Text", Field, 0}, + {"CommentGroup", Type, 0}, + {"CommentGroup.List", Field, 0}, + {"CommentMap", Type, 1}, + {"CompositeLit", Type, 0}, + {"CompositeLit.Elts", Field, 0}, + {"CompositeLit.Incomplete", Field, 11}, + {"CompositeLit.Lbrace", Field, 0}, + {"CompositeLit.Rbrace", Field, 0}, + {"CompositeLit.Type", Field, 0}, + {"Con", Const, 0}, + {"Decl", Type, 0}, + {"DeclStmt", Type, 0}, + {"DeclStmt.Decl", Field, 0}, + {"DeferStmt", Type, 0}, + {"DeferStmt.Call", Field, 0}, + {"DeferStmt.Defer", Field, 0}, + {"Ellipsis", Type, 0}, + {"Ellipsis.Ellipsis", Field, 0}, + {"Ellipsis.Elt", Field, 0}, + {"EmptyStmt", Type, 0}, + {"EmptyStmt.Implicit", Field, 5}, + {"EmptyStmt.Semicolon", Field, 0}, + {"Expr", Type, 0}, + {"ExprStmt", Type, 0}, + {"ExprStmt.X", Field, 0}, + {"Field", Type, 0}, + {"Field.Comment", Field, 0}, + {"Field.Doc", Field, 0}, + {"Field.Names", Field, 0}, + {"Field.Tag", Field, 0}, + {"Field.Type", Field, 0}, + {"FieldFilter", Type, 0}, + {"FieldList", Type, 0}, + {"FieldList.Closing", Field, 0}, + {"FieldList.List", Field, 0}, + {"FieldList.Opening", Field, 0}, + {"File", Type, 0}, + {"File.Comments", Field, 0}, + {"File.Decls", Field, 0}, + {"File.Doc", Field, 0}, + {"File.FileEnd", Field, 20}, + {"File.FileStart", Field, 20}, + {"File.GoVersion", Field, 21}, + {"File.Imports", Field, 0}, + {"File.Name", Field, 0}, + {"File.Package", Field, 0}, + {"File.Scope", Field, 0}, + {"File.Unresolved", Field, 0}, + {"FileExports", Func, 0}, + {"Filter", Type, 0}, + {"FilterDecl", Func, 0}, + {"FilterFile", Func, 0}, + {"FilterFuncDuplicates", Const, 0}, + {"FilterImportDuplicates", Const, 0}, + {"FilterPackage", Func, 0}, + {"FilterUnassociatedComments", Const, 0}, + {"ForStmt", Type, 0}, + {"ForStmt.Body", Field, 0}, + {"ForStmt.Cond", Field, 0}, + {"ForStmt.For", Field, 0}, + {"ForStmt.Init", Field, 0}, + {"ForStmt.Post", Field, 0}, + {"Fprint", Func, 0}, + {"Fun", Const, 0}, + {"FuncDecl", Type, 0}, + {"FuncDecl.Body", Field, 0}, + {"FuncDecl.Doc", Field, 0}, + {"FuncDecl.Name", Field, 0}, + {"FuncDecl.Recv", Field, 0}, + {"FuncDecl.Type", Field, 0}, + {"FuncLit", Type, 0}, + {"FuncLit.Body", Field, 0}, + {"FuncLit.Type", Field, 0}, + {"FuncType", Type, 0}, + {"FuncType.Func", Field, 0}, + {"FuncType.Params", Field, 0}, + {"FuncType.Results", Field, 0}, + {"FuncType.TypeParams", Field, 18}, + {"GenDecl", Type, 0}, + {"GenDecl.Doc", Field, 0}, + {"GenDecl.Lparen", Field, 0}, + {"GenDecl.Rparen", Field, 0}, + {"GenDecl.Specs", Field, 0}, + {"GenDecl.Tok", Field, 0}, + {"GenDecl.TokPos", Field, 0}, + {"GoStmt", Type, 0}, + {"GoStmt.Call", Field, 0}, + {"GoStmt.Go", Field, 0}, + {"Ident", Type, 0}, + {"Ident.Name", Field, 0}, + {"Ident.NamePos", Field, 0}, + {"Ident.Obj", Field, 0}, + {"IfStmt", Type, 0}, + {"IfStmt.Body", Field, 0}, + {"IfStmt.Cond", Field, 0}, + {"IfStmt.Else", Field, 0}, + {"IfStmt.If", Field, 0}, + {"IfStmt.Init", Field, 0}, + {"ImportSpec", Type, 0}, + {"ImportSpec.Comment", Field, 0}, + {"ImportSpec.Doc", Field, 0}, + {"ImportSpec.EndPos", Field, 0}, + {"ImportSpec.Name", Field, 0}, + {"ImportSpec.Path", Field, 0}, + {"Importer", Type, 0}, + {"IncDecStmt", Type, 0}, + {"IncDecStmt.Tok", Field, 0}, + {"IncDecStmt.TokPos", Field, 0}, + {"IncDecStmt.X", Field, 0}, + {"IndexExpr", Type, 0}, + {"IndexExpr.Index", Field, 0}, + {"IndexExpr.Lbrack", Field, 0}, + {"IndexExpr.Rbrack", Field, 0}, + {"IndexExpr.X", Field, 0}, + {"IndexListExpr", Type, 18}, + {"IndexListExpr.Indices", Field, 18}, + {"IndexListExpr.Lbrack", Field, 18}, + {"IndexListExpr.Rbrack", Field, 18}, + {"IndexListExpr.X", Field, 18}, + {"Inspect", Func, 0}, + {"InterfaceType", Type, 0}, + {"InterfaceType.Incomplete", Field, 0}, + {"InterfaceType.Interface", Field, 0}, + {"InterfaceType.Methods", Field, 0}, + {"IsExported", Func, 0}, + {"IsGenerated", Func, 21}, + {"KeyValueExpr", Type, 0}, + {"KeyValueExpr.Colon", Field, 0}, + {"KeyValueExpr.Key", Field, 0}, + {"KeyValueExpr.Value", Field, 0}, + {"LabeledStmt", Type, 0}, + {"LabeledStmt.Colon", Field, 0}, + {"LabeledStmt.Label", Field, 0}, + {"LabeledStmt.Stmt", Field, 0}, + {"Lbl", Const, 0}, + {"MapType", Type, 0}, + {"MapType.Key", Field, 0}, + {"MapType.Map", Field, 0}, + {"MapType.Value", Field, 0}, + {"MergeMode", Type, 0}, + {"MergePackageFiles", Func, 0}, + {"NewCommentMap", Func, 1}, + {"NewIdent", Func, 0}, + {"NewObj", Func, 0}, + {"NewPackage", Func, 0}, + {"NewScope", Func, 0}, + {"Node", Type, 0}, + {"NotNilFilter", Func, 0}, + {"ObjKind", Type, 0}, + {"Object", Type, 0}, + {"Object.Data", Field, 0}, + {"Object.Decl", Field, 0}, + {"Object.Kind", Field, 0}, + {"Object.Name", Field, 0}, + {"Object.Type", Field, 0}, + {"Package", Type, 0}, + {"Package.Files", Field, 0}, + {"Package.Imports", Field, 0}, + {"Package.Name", Field, 0}, + {"Package.Scope", Field, 0}, + {"PackageExports", Func, 0}, + {"ParenExpr", Type, 0}, + {"ParenExpr.Lparen", Field, 0}, + {"ParenExpr.Rparen", Field, 0}, + {"ParenExpr.X", Field, 0}, + {"Pkg", Const, 0}, + {"Print", Func, 0}, + {"RECV", Const, 0}, + {"RangeStmt", Type, 0}, + {"RangeStmt.Body", Field, 0}, + {"RangeStmt.For", Field, 0}, + {"RangeStmt.Key", Field, 0}, + {"RangeStmt.Range", Field, 20}, + {"RangeStmt.Tok", Field, 0}, + {"RangeStmt.TokPos", Field, 0}, + {"RangeStmt.Value", Field, 0}, + {"RangeStmt.X", Field, 0}, + {"ReturnStmt", Type, 0}, + {"ReturnStmt.Results", Field, 0}, + {"ReturnStmt.Return", Field, 0}, + {"SEND", Const, 0}, + {"Scope", Type, 0}, + {"Scope.Objects", Field, 0}, + {"Scope.Outer", Field, 0}, + {"SelectStmt", Type, 0}, + {"SelectStmt.Body", Field, 0}, + {"SelectStmt.Select", Field, 0}, + {"SelectorExpr", Type, 0}, + {"SelectorExpr.Sel", Field, 0}, + {"SelectorExpr.X", Field, 0}, + {"SendStmt", Type, 0}, + {"SendStmt.Arrow", Field, 0}, + {"SendStmt.Chan", Field, 0}, + {"SendStmt.Value", Field, 0}, + {"SliceExpr", Type, 0}, + {"SliceExpr.High", Field, 0}, + {"SliceExpr.Lbrack", Field, 0}, + {"SliceExpr.Low", Field, 0}, + {"SliceExpr.Max", Field, 2}, + {"SliceExpr.Rbrack", Field, 0}, + {"SliceExpr.Slice3", Field, 2}, + {"SliceExpr.X", Field, 0}, + {"SortImports", Func, 0}, + {"Spec", Type, 0}, + {"StarExpr", Type, 0}, + {"StarExpr.Star", Field, 0}, + {"StarExpr.X", Field, 0}, + {"Stmt", Type, 0}, + {"StructType", Type, 0}, + {"StructType.Fields", Field, 0}, + {"StructType.Incomplete", Field, 0}, + {"StructType.Struct", Field, 0}, + {"SwitchStmt", Type, 0}, + {"SwitchStmt.Body", Field, 0}, + {"SwitchStmt.Init", Field, 0}, + {"SwitchStmt.Switch", Field, 0}, + {"SwitchStmt.Tag", Field, 0}, + {"Typ", Const, 0}, + {"TypeAssertExpr", Type, 0}, + {"TypeAssertExpr.Lparen", Field, 2}, + {"TypeAssertExpr.Rparen", Field, 2}, + {"TypeAssertExpr.Type", Field, 0}, + {"TypeAssertExpr.X", Field, 0}, + {"TypeSpec", Type, 0}, + {"TypeSpec.Assign", Field, 9}, + {"TypeSpec.Comment", Field, 0}, + {"TypeSpec.Doc", Field, 0}, + {"TypeSpec.Name", Field, 0}, + {"TypeSpec.Type", Field, 0}, + {"TypeSpec.TypeParams", Field, 18}, + {"TypeSwitchStmt", Type, 0}, + {"TypeSwitchStmt.Assign", Field, 0}, + {"TypeSwitchStmt.Body", Field, 0}, + {"TypeSwitchStmt.Init", Field, 0}, + {"TypeSwitchStmt.Switch", Field, 0}, + {"UnaryExpr", Type, 0}, + {"UnaryExpr.Op", Field, 0}, + {"UnaryExpr.OpPos", Field, 0}, + {"UnaryExpr.X", Field, 0}, + {"Unparen", Func, 22}, + {"ValueSpec", Type, 0}, + {"ValueSpec.Comment", Field, 0}, + {"ValueSpec.Doc", Field, 0}, + {"ValueSpec.Names", Field, 0}, + {"ValueSpec.Type", Field, 0}, + {"ValueSpec.Values", Field, 0}, + {"Var", Const, 0}, + {"Visitor", Type, 0}, + {"Walk", Func, 0}, + }, + "go/build": { + {"(*Context).Import", Method, 0}, + {"(*Context).ImportDir", Method, 0}, + {"(*Context).MatchFile", Method, 2}, + {"(*Context).SrcDirs", Method, 0}, + {"(*MultiplePackageError).Error", Method, 4}, + {"(*NoGoError).Error", Method, 0}, + {"(*Package).IsCommand", Method, 0}, + {"AllowBinary", Const, 0}, + {"ArchChar", Func, 0}, + {"Context", Type, 0}, + {"Context.BuildTags", Field, 0}, + {"Context.CgoEnabled", Field, 0}, + {"Context.Compiler", Field, 0}, + {"Context.Dir", Field, 14}, + {"Context.GOARCH", Field, 0}, + {"Context.GOOS", Field, 0}, + {"Context.GOPATH", Field, 0}, + {"Context.GOROOT", Field, 0}, + {"Context.HasSubdir", Field, 0}, + {"Context.InstallSuffix", Field, 1}, + {"Context.IsAbsPath", Field, 0}, + {"Context.IsDir", Field, 0}, + {"Context.JoinPath", Field, 0}, + {"Context.OpenFile", Field, 0}, + {"Context.ReadDir", Field, 0}, + {"Context.ReleaseTags", Field, 1}, + {"Context.SplitPathList", Field, 0}, + {"Context.ToolTags", Field, 17}, + {"Context.UseAllFiles", Field, 0}, + {"Default", Var, 0}, + {"Directive", Type, 21}, + {"Directive.Pos", Field, 21}, + {"Directive.Text", Field, 21}, + {"FindOnly", Const, 0}, + {"IgnoreVendor", Const, 6}, + {"Import", Func, 0}, + {"ImportComment", Const, 4}, + {"ImportDir", Func, 0}, + {"ImportMode", Type, 0}, + {"IsLocalImport", Func, 0}, + {"MultiplePackageError", Type, 4}, + {"MultiplePackageError.Dir", Field, 4}, + {"MultiplePackageError.Files", Field, 4}, + {"MultiplePackageError.Packages", Field, 4}, + {"NoGoError", Type, 0}, + {"NoGoError.Dir", Field, 0}, + {"Package", Type, 0}, + {"Package.AllTags", Field, 2}, + {"Package.BinDir", Field, 0}, + {"Package.BinaryOnly", Field, 7}, + {"Package.CFiles", Field, 0}, + {"Package.CXXFiles", Field, 2}, + {"Package.CgoCFLAGS", Field, 0}, + {"Package.CgoCPPFLAGS", Field, 2}, + {"Package.CgoCXXFLAGS", Field, 2}, + {"Package.CgoFFLAGS", Field, 7}, + {"Package.CgoFiles", Field, 0}, + {"Package.CgoLDFLAGS", Field, 0}, + {"Package.CgoPkgConfig", Field, 0}, + {"Package.ConflictDir", Field, 2}, + {"Package.Dir", Field, 0}, + {"Package.Directives", Field, 21}, + {"Package.Doc", Field, 0}, + {"Package.EmbedPatternPos", Field, 16}, + {"Package.EmbedPatterns", Field, 16}, + {"Package.FFiles", Field, 7}, + {"Package.GoFiles", Field, 0}, + {"Package.Goroot", Field, 0}, + {"Package.HFiles", Field, 0}, + {"Package.IgnoredGoFiles", Field, 1}, + {"Package.IgnoredOtherFiles", Field, 16}, + {"Package.ImportComment", Field, 4}, + {"Package.ImportPath", Field, 0}, + {"Package.ImportPos", Field, 0}, + {"Package.Imports", Field, 0}, + {"Package.InvalidGoFiles", Field, 6}, + {"Package.MFiles", Field, 3}, + {"Package.Name", Field, 0}, + {"Package.PkgObj", Field, 0}, + {"Package.PkgRoot", Field, 0}, + {"Package.PkgTargetRoot", Field, 5}, + {"Package.Root", Field, 0}, + {"Package.SFiles", Field, 0}, + {"Package.SrcRoot", Field, 0}, + {"Package.SwigCXXFiles", Field, 1}, + {"Package.SwigFiles", Field, 1}, + {"Package.SysoFiles", Field, 0}, + {"Package.TestDirectives", Field, 21}, + {"Package.TestEmbedPatternPos", Field, 16}, + {"Package.TestEmbedPatterns", Field, 16}, + {"Package.TestGoFiles", Field, 0}, + {"Package.TestImportPos", Field, 0}, + {"Package.TestImports", Field, 0}, + {"Package.XTestDirectives", Field, 21}, + {"Package.XTestEmbedPatternPos", Field, 16}, + {"Package.XTestEmbedPatterns", Field, 16}, + {"Package.XTestGoFiles", Field, 0}, + {"Package.XTestImportPos", Field, 0}, + {"Package.XTestImports", Field, 0}, + {"ToolDir", Var, 0}, + }, + "go/build/constraint": { + {"(*AndExpr).Eval", Method, 16}, + {"(*AndExpr).String", Method, 16}, + {"(*NotExpr).Eval", Method, 16}, + {"(*NotExpr).String", Method, 16}, + {"(*OrExpr).Eval", Method, 16}, + {"(*OrExpr).String", Method, 16}, + {"(*SyntaxError).Error", Method, 16}, + {"(*TagExpr).Eval", Method, 16}, + {"(*TagExpr).String", Method, 16}, + {"AndExpr", Type, 16}, + {"AndExpr.X", Field, 16}, + {"AndExpr.Y", Field, 16}, + {"Expr", Type, 16}, + {"GoVersion", Func, 21}, + {"IsGoBuild", Func, 16}, + {"IsPlusBuild", Func, 16}, + {"NotExpr", Type, 16}, + {"NotExpr.X", Field, 16}, + {"OrExpr", Type, 16}, + {"OrExpr.X", Field, 16}, + {"OrExpr.Y", Field, 16}, + {"Parse", Func, 16}, + {"PlusBuildLines", Func, 16}, + {"SyntaxError", Type, 16}, + {"SyntaxError.Err", Field, 16}, + {"SyntaxError.Offset", Field, 16}, + {"TagExpr", Type, 16}, + {"TagExpr.Tag", Field, 16}, + }, + "go/constant": { + {"(Kind).String", Method, 18}, + {"BinaryOp", Func, 5}, + {"BitLen", Func, 5}, + {"Bool", Const, 5}, + {"BoolVal", Func, 5}, + {"Bytes", Func, 5}, + {"Compare", Func, 5}, + {"Complex", Const, 5}, + {"Denom", Func, 5}, + {"Float", Const, 5}, + {"Float32Val", Func, 5}, + {"Float64Val", Func, 5}, + {"Imag", Func, 5}, + {"Int", Const, 5}, + {"Int64Val", Func, 5}, + {"Kind", Type, 5}, + {"Make", Func, 13}, + {"MakeBool", Func, 5}, + {"MakeFloat64", Func, 5}, + {"MakeFromBytes", Func, 5}, + {"MakeFromLiteral", Func, 5}, + {"MakeImag", Func, 5}, + {"MakeInt64", Func, 5}, + {"MakeString", Func, 5}, + {"MakeUint64", Func, 5}, + {"MakeUnknown", Func, 5}, + {"Num", Func, 5}, + {"Real", Func, 5}, + {"Shift", Func, 5}, + {"Sign", Func, 5}, + {"String", Const, 5}, + {"StringVal", Func, 5}, + {"ToComplex", Func, 6}, + {"ToFloat", Func, 6}, + {"ToInt", Func, 6}, + {"Uint64Val", Func, 5}, + {"UnaryOp", Func, 5}, + {"Unknown", Const, 5}, + {"Val", Func, 13}, + {"Value", Type, 5}, + }, + "go/doc": { + {"(*Package).Filter", Method, 0}, + {"(*Package).HTML", Method, 19}, + {"(*Package).Markdown", Method, 19}, + {"(*Package).Parser", Method, 19}, + {"(*Package).Printer", Method, 19}, + {"(*Package).Synopsis", Method, 19}, + {"(*Package).Text", Method, 19}, + {"AllDecls", Const, 0}, + {"AllMethods", Const, 0}, + {"Example", Type, 0}, + {"Example.Code", Field, 0}, + {"Example.Comments", Field, 0}, + {"Example.Doc", Field, 0}, + {"Example.EmptyOutput", Field, 1}, + {"Example.Name", Field, 0}, + {"Example.Order", Field, 1}, + {"Example.Output", Field, 0}, + {"Example.Play", Field, 1}, + {"Example.Suffix", Field, 14}, + {"Example.Unordered", Field, 7}, + {"Examples", Func, 0}, + {"Filter", Type, 0}, + {"Func", Type, 0}, + {"Func.Decl", Field, 0}, + {"Func.Doc", Field, 0}, + {"Func.Examples", Field, 14}, + {"Func.Level", Field, 0}, + {"Func.Name", Field, 0}, + {"Func.Orig", Field, 0}, + {"Func.Recv", Field, 0}, + {"IllegalPrefixes", Var, 1}, + {"IsPredeclared", Func, 8}, + {"Mode", Type, 0}, + {"New", Func, 0}, + {"NewFromFiles", Func, 14}, + {"Note", Type, 1}, + {"Note.Body", Field, 1}, + {"Note.End", Field, 1}, + {"Note.Pos", Field, 1}, + {"Note.UID", Field, 1}, + {"Package", Type, 0}, + {"Package.Bugs", Field, 0}, + {"Package.Consts", Field, 0}, + {"Package.Doc", Field, 0}, + {"Package.Examples", Field, 14}, + {"Package.Filenames", Field, 0}, + {"Package.Funcs", Field, 0}, + {"Package.ImportPath", Field, 0}, + {"Package.Imports", Field, 0}, + {"Package.Name", Field, 0}, + {"Package.Notes", Field, 1}, + {"Package.Types", Field, 0}, + {"Package.Vars", Field, 0}, + {"PreserveAST", Const, 12}, + {"Synopsis", Func, 0}, + {"ToHTML", Func, 0}, + {"ToText", Func, 0}, + {"Type", Type, 0}, + {"Type.Consts", Field, 0}, + {"Type.Decl", Field, 0}, + {"Type.Doc", Field, 0}, + {"Type.Examples", Field, 14}, + {"Type.Funcs", Field, 0}, + {"Type.Methods", Field, 0}, + {"Type.Name", Field, 0}, + {"Type.Vars", Field, 0}, + {"Value", Type, 0}, + {"Value.Decl", Field, 0}, + {"Value.Doc", Field, 0}, + {"Value.Names", Field, 0}, + }, + "go/doc/comment": { + {"(*DocLink).DefaultURL", Method, 19}, + {"(*Heading).DefaultID", Method, 19}, + {"(*List).BlankBefore", Method, 19}, + {"(*List).BlankBetween", Method, 19}, + {"(*Parser).Parse", Method, 19}, + {"(*Printer).Comment", Method, 19}, + {"(*Printer).HTML", Method, 19}, + {"(*Printer).Markdown", Method, 19}, + {"(*Printer).Text", Method, 19}, + {"Block", Type, 19}, + {"Code", Type, 19}, + {"Code.Text", Field, 19}, + {"DefaultLookupPackage", Func, 19}, + {"Doc", Type, 19}, + {"Doc.Content", Field, 19}, + {"Doc.Links", Field, 19}, + {"DocLink", Type, 19}, + {"DocLink.ImportPath", Field, 19}, + {"DocLink.Name", Field, 19}, + {"DocLink.Recv", Field, 19}, + {"DocLink.Text", Field, 19}, + {"Heading", Type, 19}, + {"Heading.Text", Field, 19}, + {"Italic", Type, 19}, + {"Link", Type, 19}, + {"Link.Auto", Field, 19}, + {"Link.Text", Field, 19}, + {"Link.URL", Field, 19}, + {"LinkDef", Type, 19}, + {"LinkDef.Text", Field, 19}, + {"LinkDef.URL", Field, 19}, + {"LinkDef.Used", Field, 19}, + {"List", Type, 19}, + {"List.ForceBlankBefore", Field, 19}, + {"List.ForceBlankBetween", Field, 19}, + {"List.Items", Field, 19}, + {"ListItem", Type, 19}, + {"ListItem.Content", Field, 19}, + {"ListItem.Number", Field, 19}, + {"Paragraph", Type, 19}, + {"Paragraph.Text", Field, 19}, + {"Parser", Type, 19}, + {"Parser.LookupPackage", Field, 19}, + {"Parser.LookupSym", Field, 19}, + {"Parser.Words", Field, 19}, + {"Plain", Type, 19}, + {"Printer", Type, 19}, + {"Printer.DocLinkBaseURL", Field, 19}, + {"Printer.DocLinkURL", Field, 19}, + {"Printer.HeadingID", Field, 19}, + {"Printer.HeadingLevel", Field, 19}, + {"Printer.TextCodePrefix", Field, 19}, + {"Printer.TextPrefix", Field, 19}, + {"Printer.TextWidth", Field, 19}, + {"Text", Type, 19}, + }, + "go/format": { + {"Node", Func, 1}, + {"Source", Func, 1}, + }, + "go/importer": { + {"Default", Func, 5}, + {"For", Func, 5}, + {"ForCompiler", Func, 12}, + {"Lookup", Type, 5}, + }, + "go/parser": { + {"AllErrors", Const, 1}, + {"DeclarationErrors", Const, 0}, + {"ImportsOnly", Const, 0}, + {"Mode", Type, 0}, + {"PackageClauseOnly", Const, 0}, + {"ParseComments", Const, 0}, + {"ParseDir", Func, 0}, + {"ParseExpr", Func, 0}, + {"ParseExprFrom", Func, 5}, + {"ParseFile", Func, 0}, + {"SkipObjectResolution", Const, 17}, + {"SpuriousErrors", Const, 0}, + {"Trace", Const, 0}, + }, + "go/printer": { + {"(*Config).Fprint", Method, 0}, + {"CommentedNode", Type, 0}, + {"CommentedNode.Comments", Field, 0}, + {"CommentedNode.Node", Field, 0}, + {"Config", Type, 0}, + {"Config.Indent", Field, 1}, + {"Config.Mode", Field, 0}, + {"Config.Tabwidth", Field, 0}, + {"Fprint", Func, 0}, + {"Mode", Type, 0}, + {"RawFormat", Const, 0}, + {"SourcePos", Const, 0}, + {"TabIndent", Const, 0}, + {"UseSpaces", Const, 0}, + }, + "go/scanner": { + {"(*ErrorList).Add", Method, 0}, + {"(*ErrorList).RemoveMultiples", Method, 0}, + {"(*ErrorList).Reset", Method, 0}, + {"(*Scanner).Init", Method, 0}, + {"(*Scanner).Scan", Method, 0}, + {"(Error).Error", Method, 0}, + {"(ErrorList).Err", Method, 0}, + {"(ErrorList).Error", Method, 0}, + {"(ErrorList).Len", Method, 0}, + {"(ErrorList).Less", Method, 0}, + {"(ErrorList).Sort", Method, 0}, + {"(ErrorList).Swap", Method, 0}, + {"Error", Type, 0}, + {"Error.Msg", Field, 0}, + {"Error.Pos", Field, 0}, + {"ErrorHandler", Type, 0}, + {"ErrorList", Type, 0}, + {"Mode", Type, 0}, + {"PrintError", Func, 0}, + {"ScanComments", Const, 0}, + {"Scanner", Type, 0}, + {"Scanner.ErrorCount", Field, 0}, + }, + "go/token": { + {"(*File).AddLine", Method, 0}, + {"(*File).AddLineColumnInfo", Method, 11}, + {"(*File).AddLineInfo", Method, 0}, + {"(*File).Base", Method, 0}, + {"(*File).Line", Method, 0}, + {"(*File).LineCount", Method, 0}, + {"(*File).LineStart", Method, 12}, + {"(*File).Lines", Method, 21}, + {"(*File).MergeLine", Method, 2}, + {"(*File).Name", Method, 0}, + {"(*File).Offset", Method, 0}, + {"(*File).Pos", Method, 0}, + {"(*File).Position", Method, 0}, + {"(*File).PositionFor", Method, 4}, + {"(*File).SetLines", Method, 0}, + {"(*File).SetLinesForContent", Method, 0}, + {"(*File).Size", Method, 0}, + {"(*FileSet).AddFile", Method, 0}, + {"(*FileSet).Base", Method, 0}, + {"(*FileSet).File", Method, 0}, + {"(*FileSet).Iterate", Method, 0}, + {"(*FileSet).Position", Method, 0}, + {"(*FileSet).PositionFor", Method, 4}, + {"(*FileSet).Read", Method, 0}, + {"(*FileSet).RemoveFile", Method, 20}, + {"(*FileSet).Write", Method, 0}, + {"(*Position).IsValid", Method, 0}, + {"(Pos).IsValid", Method, 0}, + {"(Position).String", Method, 0}, + {"(Token).IsKeyword", Method, 0}, + {"(Token).IsLiteral", Method, 0}, + {"(Token).IsOperator", Method, 0}, + {"(Token).Precedence", Method, 0}, + {"(Token).String", Method, 0}, + {"ADD", Const, 0}, + {"ADD_ASSIGN", Const, 0}, + {"AND", Const, 0}, + {"AND_ASSIGN", Const, 0}, + {"AND_NOT", Const, 0}, + {"AND_NOT_ASSIGN", Const, 0}, + {"ARROW", Const, 0}, + {"ASSIGN", Const, 0}, + {"BREAK", Const, 0}, + {"CASE", Const, 0}, + {"CHAN", Const, 0}, + {"CHAR", Const, 0}, + {"COLON", Const, 0}, + {"COMMA", Const, 0}, + {"COMMENT", Const, 0}, + {"CONST", Const, 0}, + {"CONTINUE", Const, 0}, + {"DEC", Const, 0}, + {"DEFAULT", Const, 0}, + {"DEFER", Const, 0}, + {"DEFINE", Const, 0}, + {"ELLIPSIS", Const, 0}, + {"ELSE", Const, 0}, + {"EOF", Const, 0}, + {"EQL", Const, 0}, + {"FALLTHROUGH", Const, 0}, + {"FLOAT", Const, 0}, + {"FOR", Const, 0}, + {"FUNC", Const, 0}, + {"File", Type, 0}, + {"FileSet", Type, 0}, + {"GEQ", Const, 0}, + {"GO", Const, 0}, + {"GOTO", Const, 0}, + {"GTR", Const, 0}, + {"HighestPrec", Const, 0}, + {"IDENT", Const, 0}, + {"IF", Const, 0}, + {"ILLEGAL", Const, 0}, + {"IMAG", Const, 0}, + {"IMPORT", Const, 0}, + {"INC", Const, 0}, + {"INT", Const, 0}, + {"INTERFACE", Const, 0}, + {"IsExported", Func, 13}, + {"IsIdentifier", Func, 13}, + {"IsKeyword", Func, 13}, + {"LAND", Const, 0}, + {"LBRACE", Const, 0}, + {"LBRACK", Const, 0}, + {"LEQ", Const, 0}, + {"LOR", Const, 0}, + {"LPAREN", Const, 0}, + {"LSS", Const, 0}, + {"Lookup", Func, 0}, + {"LowestPrec", Const, 0}, + {"MAP", Const, 0}, + {"MUL", Const, 0}, + {"MUL_ASSIGN", Const, 0}, + {"NEQ", Const, 0}, + {"NOT", Const, 0}, + {"NewFileSet", Func, 0}, + {"NoPos", Const, 0}, + {"OR", Const, 0}, + {"OR_ASSIGN", Const, 0}, + {"PACKAGE", Const, 0}, + {"PERIOD", Const, 0}, + {"Pos", Type, 0}, + {"Position", Type, 0}, + {"Position.Column", Field, 0}, + {"Position.Filename", Field, 0}, + {"Position.Line", Field, 0}, + {"Position.Offset", Field, 0}, + {"QUO", Const, 0}, + {"QUO_ASSIGN", Const, 0}, + {"RANGE", Const, 0}, + {"RBRACE", Const, 0}, + {"RBRACK", Const, 0}, + {"REM", Const, 0}, + {"REM_ASSIGN", Const, 0}, + {"RETURN", Const, 0}, + {"RPAREN", Const, 0}, + {"SELECT", Const, 0}, + {"SEMICOLON", Const, 0}, + {"SHL", Const, 0}, + {"SHL_ASSIGN", Const, 0}, + {"SHR", Const, 0}, + {"SHR_ASSIGN", Const, 0}, + {"STRING", Const, 0}, + {"STRUCT", Const, 0}, + {"SUB", Const, 0}, + {"SUB_ASSIGN", Const, 0}, + {"SWITCH", Const, 0}, + {"TILDE", Const, 18}, + {"TYPE", Const, 0}, + {"Token", Type, 0}, + {"UnaryPrec", Const, 0}, + {"VAR", Const, 0}, + {"XOR", Const, 0}, + {"XOR_ASSIGN", Const, 0}, + }, + "go/types": { + {"(*Alias).Obj", Method, 22}, + {"(*Alias).String", Method, 22}, + {"(*Alias).Underlying", Method, 22}, + {"(*ArgumentError).Error", Method, 18}, + {"(*ArgumentError).Unwrap", Method, 18}, + {"(*Array).Elem", Method, 5}, + {"(*Array).Len", Method, 5}, + {"(*Array).String", Method, 5}, + {"(*Array).Underlying", Method, 5}, + {"(*Basic).Info", Method, 5}, + {"(*Basic).Kind", Method, 5}, + {"(*Basic).Name", Method, 5}, + {"(*Basic).String", Method, 5}, + {"(*Basic).Underlying", Method, 5}, + {"(*Builtin).Exported", Method, 5}, + {"(*Builtin).Id", Method, 5}, + {"(*Builtin).Name", Method, 5}, + {"(*Builtin).Parent", Method, 5}, + {"(*Builtin).Pkg", Method, 5}, + {"(*Builtin).Pos", Method, 5}, + {"(*Builtin).String", Method, 5}, + {"(*Builtin).Type", Method, 5}, + {"(*Chan).Dir", Method, 5}, + {"(*Chan).Elem", Method, 5}, + {"(*Chan).String", Method, 5}, + {"(*Chan).Underlying", Method, 5}, + {"(*Checker).Files", Method, 5}, + {"(*Config).Check", Method, 5}, + {"(*Const).Exported", Method, 5}, + {"(*Const).Id", Method, 5}, + {"(*Const).Name", Method, 5}, + {"(*Const).Parent", Method, 5}, + {"(*Const).Pkg", Method, 5}, + {"(*Const).Pos", Method, 5}, + {"(*Const).String", Method, 5}, + {"(*Const).Type", Method, 5}, + {"(*Const).Val", Method, 5}, + {"(*Func).Exported", Method, 5}, + {"(*Func).FullName", Method, 5}, + {"(*Func).Id", Method, 5}, + {"(*Func).Name", Method, 5}, + {"(*Func).Origin", Method, 19}, + {"(*Func).Parent", Method, 5}, + {"(*Func).Pkg", Method, 5}, + {"(*Func).Pos", Method, 5}, + {"(*Func).Scope", Method, 5}, + {"(*Func).String", Method, 5}, + {"(*Func).Type", Method, 5}, + {"(*Info).ObjectOf", Method, 5}, + {"(*Info).PkgNameOf", Method, 22}, + {"(*Info).TypeOf", Method, 5}, + {"(*Initializer).String", Method, 5}, + {"(*Interface).Complete", Method, 5}, + {"(*Interface).Embedded", Method, 5}, + {"(*Interface).EmbeddedType", Method, 11}, + {"(*Interface).Empty", Method, 5}, + {"(*Interface).ExplicitMethod", Method, 5}, + {"(*Interface).IsComparable", Method, 18}, + {"(*Interface).IsImplicit", Method, 18}, + {"(*Interface).IsMethodSet", Method, 18}, + {"(*Interface).MarkImplicit", Method, 18}, + {"(*Interface).Method", Method, 5}, + {"(*Interface).NumEmbeddeds", Method, 5}, + {"(*Interface).NumExplicitMethods", Method, 5}, + {"(*Interface).NumMethods", Method, 5}, + {"(*Interface).String", Method, 5}, + {"(*Interface).Underlying", Method, 5}, + {"(*Label).Exported", Method, 5}, + {"(*Label).Id", Method, 5}, + {"(*Label).Name", Method, 5}, + {"(*Label).Parent", Method, 5}, + {"(*Label).Pkg", Method, 5}, + {"(*Label).Pos", Method, 5}, + {"(*Label).String", Method, 5}, + {"(*Label).Type", Method, 5}, + {"(*Map).Elem", Method, 5}, + {"(*Map).Key", Method, 5}, + {"(*Map).String", Method, 5}, + {"(*Map).Underlying", Method, 5}, + {"(*MethodSet).At", Method, 5}, + {"(*MethodSet).Len", Method, 5}, + {"(*MethodSet).Lookup", Method, 5}, + {"(*MethodSet).String", Method, 5}, + {"(*Named).AddMethod", Method, 5}, + {"(*Named).Method", Method, 5}, + {"(*Named).NumMethods", Method, 5}, + {"(*Named).Obj", Method, 5}, + {"(*Named).Origin", Method, 18}, + {"(*Named).SetTypeParams", Method, 18}, + {"(*Named).SetUnderlying", Method, 5}, + {"(*Named).String", Method, 5}, + {"(*Named).TypeArgs", Method, 18}, + {"(*Named).TypeParams", Method, 18}, + {"(*Named).Underlying", Method, 5}, + {"(*Nil).Exported", Method, 5}, + {"(*Nil).Id", Method, 5}, + {"(*Nil).Name", Method, 5}, + {"(*Nil).Parent", Method, 5}, + {"(*Nil).Pkg", Method, 5}, + {"(*Nil).Pos", Method, 5}, + {"(*Nil).String", Method, 5}, + {"(*Nil).Type", Method, 5}, + {"(*Package).Complete", Method, 5}, + {"(*Package).GoVersion", Method, 21}, + {"(*Package).Imports", Method, 5}, + {"(*Package).MarkComplete", Method, 5}, + {"(*Package).Name", Method, 5}, + {"(*Package).Path", Method, 5}, + {"(*Package).Scope", Method, 5}, + {"(*Package).SetImports", Method, 5}, + {"(*Package).SetName", Method, 6}, + {"(*Package).String", Method, 5}, + {"(*PkgName).Exported", Method, 5}, + {"(*PkgName).Id", Method, 5}, + {"(*PkgName).Imported", Method, 5}, + {"(*PkgName).Name", Method, 5}, + {"(*PkgName).Parent", Method, 5}, + {"(*PkgName).Pkg", Method, 5}, + {"(*PkgName).Pos", Method, 5}, + {"(*PkgName).String", Method, 5}, + {"(*PkgName).Type", Method, 5}, + {"(*Pointer).Elem", Method, 5}, + {"(*Pointer).String", Method, 5}, + {"(*Pointer).Underlying", Method, 5}, + {"(*Scope).Child", Method, 5}, + {"(*Scope).Contains", Method, 5}, + {"(*Scope).End", Method, 5}, + {"(*Scope).Innermost", Method, 5}, + {"(*Scope).Insert", Method, 5}, + {"(*Scope).Len", Method, 5}, + {"(*Scope).Lookup", Method, 5}, + {"(*Scope).LookupParent", Method, 5}, + {"(*Scope).Names", Method, 5}, + {"(*Scope).NumChildren", Method, 5}, + {"(*Scope).Parent", Method, 5}, + {"(*Scope).Pos", Method, 5}, + {"(*Scope).String", Method, 5}, + {"(*Scope).WriteTo", Method, 5}, + {"(*Selection).Index", Method, 5}, + {"(*Selection).Indirect", Method, 5}, + {"(*Selection).Kind", Method, 5}, + {"(*Selection).Obj", Method, 5}, + {"(*Selection).Recv", Method, 5}, + {"(*Selection).String", Method, 5}, + {"(*Selection).Type", Method, 5}, + {"(*Signature).Params", Method, 5}, + {"(*Signature).Recv", Method, 5}, + {"(*Signature).RecvTypeParams", Method, 18}, + {"(*Signature).Results", Method, 5}, + {"(*Signature).String", Method, 5}, + {"(*Signature).TypeParams", Method, 18}, + {"(*Signature).Underlying", Method, 5}, + {"(*Signature).Variadic", Method, 5}, + {"(*Slice).Elem", Method, 5}, + {"(*Slice).String", Method, 5}, + {"(*Slice).Underlying", Method, 5}, + {"(*StdSizes).Alignof", Method, 5}, + {"(*StdSizes).Offsetsof", Method, 5}, + {"(*StdSizes).Sizeof", Method, 5}, + {"(*Struct).Field", Method, 5}, + {"(*Struct).NumFields", Method, 5}, + {"(*Struct).String", Method, 5}, + {"(*Struct).Tag", Method, 5}, + {"(*Struct).Underlying", Method, 5}, + {"(*Term).String", Method, 18}, + {"(*Term).Tilde", Method, 18}, + {"(*Term).Type", Method, 18}, + {"(*Tuple).At", Method, 5}, + {"(*Tuple).Len", Method, 5}, + {"(*Tuple).String", Method, 5}, + {"(*Tuple).Underlying", Method, 5}, + {"(*TypeList).At", Method, 18}, + {"(*TypeList).Len", Method, 18}, + {"(*TypeName).Exported", Method, 5}, + {"(*TypeName).Id", Method, 5}, + {"(*TypeName).IsAlias", Method, 9}, + {"(*TypeName).Name", Method, 5}, + {"(*TypeName).Parent", Method, 5}, + {"(*TypeName).Pkg", Method, 5}, + {"(*TypeName).Pos", Method, 5}, + {"(*TypeName).String", Method, 5}, + {"(*TypeName).Type", Method, 5}, + {"(*TypeParam).Constraint", Method, 18}, + {"(*TypeParam).Index", Method, 18}, + {"(*TypeParam).Obj", Method, 18}, + {"(*TypeParam).SetConstraint", Method, 18}, + {"(*TypeParam).String", Method, 18}, + {"(*TypeParam).Underlying", Method, 18}, + {"(*TypeParamList).At", Method, 18}, + {"(*TypeParamList).Len", Method, 18}, + {"(*Union).Len", Method, 18}, + {"(*Union).String", Method, 18}, + {"(*Union).Term", Method, 18}, + {"(*Union).Underlying", Method, 18}, + {"(*Var).Anonymous", Method, 5}, + {"(*Var).Embedded", Method, 11}, + {"(*Var).Exported", Method, 5}, + {"(*Var).Id", Method, 5}, + {"(*Var).IsField", Method, 5}, + {"(*Var).Name", Method, 5}, + {"(*Var).Origin", Method, 19}, + {"(*Var).Parent", Method, 5}, + {"(*Var).Pkg", Method, 5}, + {"(*Var).Pos", Method, 5}, + {"(*Var).String", Method, 5}, + {"(*Var).Type", Method, 5}, + {"(Checker).ObjectOf", Method, 5}, + {"(Checker).PkgNameOf", Method, 22}, + {"(Checker).TypeOf", Method, 5}, + {"(Error).Error", Method, 5}, + {"(TypeAndValue).Addressable", Method, 5}, + {"(TypeAndValue).Assignable", Method, 5}, + {"(TypeAndValue).HasOk", Method, 5}, + {"(TypeAndValue).IsBuiltin", Method, 5}, + {"(TypeAndValue).IsNil", Method, 5}, + {"(TypeAndValue).IsType", Method, 5}, + {"(TypeAndValue).IsValue", Method, 5}, + {"(TypeAndValue).IsVoid", Method, 5}, + {"Alias", Type, 22}, + {"ArgumentError", Type, 18}, + {"ArgumentError.Err", Field, 18}, + {"ArgumentError.Index", Field, 18}, + {"Array", Type, 5}, + {"AssertableTo", Func, 5}, + {"AssignableTo", Func, 5}, + {"Basic", Type, 5}, + {"BasicInfo", Type, 5}, + {"BasicKind", Type, 5}, + {"Bool", Const, 5}, + {"Builtin", Type, 5}, + {"Byte", Const, 5}, + {"Chan", Type, 5}, + {"ChanDir", Type, 5}, + {"CheckExpr", Func, 13}, + {"Checker", Type, 5}, + {"Checker.Info", Field, 5}, + {"Comparable", Func, 5}, + {"Complex128", Const, 5}, + {"Complex64", Const, 5}, + {"Config", Type, 5}, + {"Config.Context", Field, 18}, + {"Config.DisableUnusedImportCheck", Field, 5}, + {"Config.Error", Field, 5}, + {"Config.FakeImportC", Field, 5}, + {"Config.GoVersion", Field, 18}, + {"Config.IgnoreFuncBodies", Field, 5}, + {"Config.Importer", Field, 5}, + {"Config.Sizes", Field, 5}, + {"Const", Type, 5}, + {"Context", Type, 18}, + {"ConvertibleTo", Func, 5}, + {"DefPredeclaredTestFuncs", Func, 5}, + {"Default", Func, 8}, + {"Error", Type, 5}, + {"Error.Fset", Field, 5}, + {"Error.Msg", Field, 5}, + {"Error.Pos", Field, 5}, + {"Error.Soft", Field, 5}, + {"Eval", Func, 5}, + {"ExprString", Func, 5}, + {"FieldVal", Const, 5}, + {"Float32", Const, 5}, + {"Float64", Const, 5}, + {"Func", Type, 5}, + {"Id", Func, 5}, + {"Identical", Func, 5}, + {"IdenticalIgnoreTags", Func, 8}, + {"Implements", Func, 5}, + {"ImportMode", Type, 6}, + {"Importer", Type, 5}, + {"ImporterFrom", Type, 6}, + {"Info", Type, 5}, + {"Info.Defs", Field, 5}, + {"Info.FileVersions", Field, 22}, + {"Info.Implicits", Field, 5}, + {"Info.InitOrder", Field, 5}, + {"Info.Instances", Field, 18}, + {"Info.Scopes", Field, 5}, + {"Info.Selections", Field, 5}, + {"Info.Types", Field, 5}, + {"Info.Uses", Field, 5}, + {"Initializer", Type, 5}, + {"Initializer.Lhs", Field, 5}, + {"Initializer.Rhs", Field, 5}, + {"Instance", Type, 18}, + {"Instance.Type", Field, 18}, + {"Instance.TypeArgs", Field, 18}, + {"Instantiate", Func, 18}, + {"Int", Const, 5}, + {"Int16", Const, 5}, + {"Int32", Const, 5}, + {"Int64", Const, 5}, + {"Int8", Const, 5}, + {"Interface", Type, 5}, + {"Invalid", Const, 5}, + {"IsBoolean", Const, 5}, + {"IsComplex", Const, 5}, + {"IsConstType", Const, 5}, + {"IsFloat", Const, 5}, + {"IsInteger", Const, 5}, + {"IsInterface", Func, 5}, + {"IsNumeric", Const, 5}, + {"IsOrdered", Const, 5}, + {"IsString", Const, 5}, + {"IsUnsigned", Const, 5}, + {"IsUntyped", Const, 5}, + {"Label", Type, 5}, + {"LookupFieldOrMethod", Func, 5}, + {"Map", Type, 5}, + {"MethodExpr", Const, 5}, + {"MethodSet", Type, 5}, + {"MethodVal", Const, 5}, + {"MissingMethod", Func, 5}, + {"Named", Type, 5}, + {"NewAlias", Func, 22}, + {"NewArray", Func, 5}, + {"NewChan", Func, 5}, + {"NewChecker", Func, 5}, + {"NewConst", Func, 5}, + {"NewContext", Func, 18}, + {"NewField", Func, 5}, + {"NewFunc", Func, 5}, + {"NewInterface", Func, 5}, + {"NewInterfaceType", Func, 11}, + {"NewLabel", Func, 5}, + {"NewMap", Func, 5}, + {"NewMethodSet", Func, 5}, + {"NewNamed", Func, 5}, + {"NewPackage", Func, 5}, + {"NewParam", Func, 5}, + {"NewPkgName", Func, 5}, + {"NewPointer", Func, 5}, + {"NewScope", Func, 5}, + {"NewSignature", Func, 5}, + {"NewSignatureType", Func, 18}, + {"NewSlice", Func, 5}, + {"NewStruct", Func, 5}, + {"NewTerm", Func, 18}, + {"NewTuple", Func, 5}, + {"NewTypeName", Func, 5}, + {"NewTypeParam", Func, 18}, + {"NewUnion", Func, 18}, + {"NewVar", Func, 5}, + {"Nil", Type, 5}, + {"Object", Type, 5}, + {"ObjectString", Func, 5}, + {"Package", Type, 5}, + {"PkgName", Type, 5}, + {"Pointer", Type, 5}, + {"Qualifier", Type, 5}, + {"RecvOnly", Const, 5}, + {"RelativeTo", Func, 5}, + {"Rune", Const, 5}, + {"Satisfies", Func, 20}, + {"Scope", Type, 5}, + {"Selection", Type, 5}, + {"SelectionKind", Type, 5}, + {"SelectionString", Func, 5}, + {"SendOnly", Const, 5}, + {"SendRecv", Const, 5}, + {"Signature", Type, 5}, + {"Sizes", Type, 5}, + {"SizesFor", Func, 9}, + {"Slice", Type, 5}, + {"StdSizes", Type, 5}, + {"StdSizes.MaxAlign", Field, 5}, + {"StdSizes.WordSize", Field, 5}, + {"String", Const, 5}, + {"Struct", Type, 5}, + {"Term", Type, 18}, + {"Tuple", Type, 5}, + {"Typ", Var, 5}, + {"Type", Type, 5}, + {"TypeAndValue", Type, 5}, + {"TypeAndValue.Type", Field, 5}, + {"TypeAndValue.Value", Field, 5}, + {"TypeList", Type, 18}, + {"TypeName", Type, 5}, + {"TypeParam", Type, 18}, + {"TypeParamList", Type, 18}, + {"TypeString", Func, 5}, + {"Uint", Const, 5}, + {"Uint16", Const, 5}, + {"Uint32", Const, 5}, + {"Uint64", Const, 5}, + {"Uint8", Const, 5}, + {"Uintptr", Const, 5}, + {"Unalias", Func, 22}, + {"Union", Type, 18}, + {"Universe", Var, 5}, + {"Unsafe", Var, 5}, + {"UnsafePointer", Const, 5}, + {"UntypedBool", Const, 5}, + {"UntypedComplex", Const, 5}, + {"UntypedFloat", Const, 5}, + {"UntypedInt", Const, 5}, + {"UntypedNil", Const, 5}, + {"UntypedRune", Const, 5}, + {"UntypedString", Const, 5}, + {"Var", Type, 5}, + {"WriteExpr", Func, 5}, + {"WriteSignature", Func, 5}, + {"WriteType", Func, 5}, + }, + "go/version": { + {"Compare", Func, 22}, + {"IsValid", Func, 22}, + {"Lang", Func, 22}, + }, + "hash": { + {"Hash", Type, 0}, + {"Hash32", Type, 0}, + {"Hash64", Type, 0}, + }, + "hash/adler32": { + {"Checksum", Func, 0}, + {"New", Func, 0}, + {"Size", Const, 0}, + }, + "hash/crc32": { + {"Castagnoli", Const, 0}, + {"Checksum", Func, 0}, + {"ChecksumIEEE", Func, 0}, + {"IEEE", Const, 0}, + {"IEEETable", Var, 0}, + {"Koopman", Const, 0}, + {"MakeTable", Func, 0}, + {"New", Func, 0}, + {"NewIEEE", Func, 0}, + {"Size", Const, 0}, + {"Table", Type, 0}, + {"Update", Func, 0}, + }, + "hash/crc64": { + {"Checksum", Func, 0}, + {"ECMA", Const, 0}, + {"ISO", Const, 0}, + {"MakeTable", Func, 0}, + {"New", Func, 0}, + {"Size", Const, 0}, + {"Table", Type, 0}, + {"Update", Func, 0}, + }, + "hash/fnv": { + {"New128", Func, 9}, + {"New128a", Func, 9}, + {"New32", Func, 0}, + {"New32a", Func, 0}, + {"New64", Func, 0}, + {"New64a", Func, 0}, + }, + "hash/maphash": { + {"(*Hash).BlockSize", Method, 14}, + {"(*Hash).Reset", Method, 14}, + {"(*Hash).Seed", Method, 14}, + {"(*Hash).SetSeed", Method, 14}, + {"(*Hash).Size", Method, 14}, + {"(*Hash).Sum", Method, 14}, + {"(*Hash).Sum64", Method, 14}, + {"(*Hash).Write", Method, 14}, + {"(*Hash).WriteByte", Method, 14}, + {"(*Hash).WriteString", Method, 14}, + {"Bytes", Func, 19}, + {"Hash", Type, 14}, + {"MakeSeed", Func, 14}, + {"Seed", Type, 14}, + {"String", Func, 19}, + }, + "html": { + {"EscapeString", Func, 0}, + {"UnescapeString", Func, 0}, + }, + "html/template": { + {"(*Error).Error", Method, 0}, + {"(*Template).AddParseTree", Method, 0}, + {"(*Template).Clone", Method, 0}, + {"(*Template).DefinedTemplates", Method, 6}, + {"(*Template).Delims", Method, 0}, + {"(*Template).Execute", Method, 0}, + {"(*Template).ExecuteTemplate", Method, 0}, + {"(*Template).Funcs", Method, 0}, + {"(*Template).Lookup", Method, 0}, + {"(*Template).Name", Method, 0}, + {"(*Template).New", Method, 0}, + {"(*Template).Option", Method, 5}, + {"(*Template).Parse", Method, 0}, + {"(*Template).ParseFS", Method, 16}, + {"(*Template).ParseFiles", Method, 0}, + {"(*Template).ParseGlob", Method, 0}, + {"(*Template).Templates", Method, 0}, + {"CSS", Type, 0}, + {"ErrAmbigContext", Const, 0}, + {"ErrBadHTML", Const, 0}, + {"ErrBranchEnd", Const, 0}, + {"ErrEndContext", Const, 0}, + {"ErrJSTemplate", Const, 21}, + {"ErrNoSuchTemplate", Const, 0}, + {"ErrOutputContext", Const, 0}, + {"ErrPartialCharset", Const, 0}, + {"ErrPartialEscape", Const, 0}, + {"ErrPredefinedEscaper", Const, 9}, + {"ErrRangeLoopReentry", Const, 0}, + {"ErrSlashAmbig", Const, 0}, + {"Error", Type, 0}, + {"Error.Description", Field, 0}, + {"Error.ErrorCode", Field, 0}, + {"Error.Line", Field, 0}, + {"Error.Name", Field, 0}, + {"Error.Node", Field, 4}, + {"ErrorCode", Type, 0}, + {"FuncMap", Type, 0}, + {"HTML", Type, 0}, + {"HTMLAttr", Type, 0}, + {"HTMLEscape", Func, 0}, + {"HTMLEscapeString", Func, 0}, + {"HTMLEscaper", Func, 0}, + {"IsTrue", Func, 6}, + {"JS", Type, 0}, + {"JSEscape", Func, 0}, + {"JSEscapeString", Func, 0}, + {"JSEscaper", Func, 0}, + {"JSStr", Type, 0}, + {"Must", Func, 0}, + {"New", Func, 0}, + {"OK", Const, 0}, + {"ParseFS", Func, 16}, + {"ParseFiles", Func, 0}, + {"ParseGlob", Func, 0}, + {"Srcset", Type, 10}, + {"Template", Type, 0}, + {"Template.Tree", Field, 2}, + {"URL", Type, 0}, + {"URLQueryEscaper", Func, 0}, + }, + "image": { + {"(*Alpha).AlphaAt", Method, 4}, + {"(*Alpha).At", Method, 0}, + {"(*Alpha).Bounds", Method, 0}, + {"(*Alpha).ColorModel", Method, 0}, + {"(*Alpha).Opaque", Method, 0}, + {"(*Alpha).PixOffset", Method, 0}, + {"(*Alpha).RGBA64At", Method, 17}, + {"(*Alpha).Set", Method, 0}, + {"(*Alpha).SetAlpha", Method, 0}, + {"(*Alpha).SetRGBA64", Method, 17}, + {"(*Alpha).SubImage", Method, 0}, + {"(*Alpha16).Alpha16At", Method, 4}, + {"(*Alpha16).At", Method, 0}, + {"(*Alpha16).Bounds", Method, 0}, + {"(*Alpha16).ColorModel", Method, 0}, + {"(*Alpha16).Opaque", Method, 0}, + {"(*Alpha16).PixOffset", Method, 0}, + {"(*Alpha16).RGBA64At", Method, 17}, + {"(*Alpha16).Set", Method, 0}, + {"(*Alpha16).SetAlpha16", Method, 0}, + {"(*Alpha16).SetRGBA64", Method, 17}, + {"(*Alpha16).SubImage", Method, 0}, + {"(*CMYK).At", Method, 5}, + {"(*CMYK).Bounds", Method, 5}, + {"(*CMYK).CMYKAt", Method, 5}, + {"(*CMYK).ColorModel", Method, 5}, + {"(*CMYK).Opaque", Method, 5}, + {"(*CMYK).PixOffset", Method, 5}, + {"(*CMYK).RGBA64At", Method, 17}, + {"(*CMYK).Set", Method, 5}, + {"(*CMYK).SetCMYK", Method, 5}, + {"(*CMYK).SetRGBA64", Method, 17}, + {"(*CMYK).SubImage", Method, 5}, + {"(*Gray).At", Method, 0}, + {"(*Gray).Bounds", Method, 0}, + {"(*Gray).ColorModel", Method, 0}, + {"(*Gray).GrayAt", Method, 4}, + {"(*Gray).Opaque", Method, 0}, + {"(*Gray).PixOffset", Method, 0}, + {"(*Gray).RGBA64At", Method, 17}, + {"(*Gray).Set", Method, 0}, + {"(*Gray).SetGray", Method, 0}, + {"(*Gray).SetRGBA64", Method, 17}, + {"(*Gray).SubImage", Method, 0}, + {"(*Gray16).At", Method, 0}, + {"(*Gray16).Bounds", Method, 0}, + {"(*Gray16).ColorModel", Method, 0}, + {"(*Gray16).Gray16At", Method, 4}, + {"(*Gray16).Opaque", Method, 0}, + {"(*Gray16).PixOffset", Method, 0}, + {"(*Gray16).RGBA64At", Method, 17}, + {"(*Gray16).Set", Method, 0}, + {"(*Gray16).SetGray16", Method, 0}, + {"(*Gray16).SetRGBA64", Method, 17}, + {"(*Gray16).SubImage", Method, 0}, + {"(*NRGBA).At", Method, 0}, + {"(*NRGBA).Bounds", Method, 0}, + {"(*NRGBA).ColorModel", Method, 0}, + {"(*NRGBA).NRGBAAt", Method, 4}, + {"(*NRGBA).Opaque", Method, 0}, + {"(*NRGBA).PixOffset", Method, 0}, + {"(*NRGBA).RGBA64At", Method, 17}, + {"(*NRGBA).Set", Method, 0}, + {"(*NRGBA).SetNRGBA", Method, 0}, + {"(*NRGBA).SetRGBA64", Method, 17}, + {"(*NRGBA).SubImage", Method, 0}, + {"(*NRGBA64).At", Method, 0}, + {"(*NRGBA64).Bounds", Method, 0}, + {"(*NRGBA64).ColorModel", Method, 0}, + {"(*NRGBA64).NRGBA64At", Method, 4}, + {"(*NRGBA64).Opaque", Method, 0}, + {"(*NRGBA64).PixOffset", Method, 0}, + {"(*NRGBA64).RGBA64At", Method, 17}, + {"(*NRGBA64).Set", Method, 0}, + {"(*NRGBA64).SetNRGBA64", Method, 0}, + {"(*NRGBA64).SetRGBA64", Method, 17}, + {"(*NRGBA64).SubImage", Method, 0}, + {"(*NYCbCrA).AOffset", Method, 6}, + {"(*NYCbCrA).At", Method, 6}, + {"(*NYCbCrA).Bounds", Method, 6}, + {"(*NYCbCrA).COffset", Method, 6}, + {"(*NYCbCrA).ColorModel", Method, 6}, + {"(*NYCbCrA).NYCbCrAAt", Method, 6}, + {"(*NYCbCrA).Opaque", Method, 6}, + {"(*NYCbCrA).RGBA64At", Method, 17}, + {"(*NYCbCrA).SubImage", Method, 6}, + {"(*NYCbCrA).YCbCrAt", Method, 6}, + {"(*NYCbCrA).YOffset", Method, 6}, + {"(*Paletted).At", Method, 0}, + {"(*Paletted).Bounds", Method, 0}, + {"(*Paletted).ColorIndexAt", Method, 0}, + {"(*Paletted).ColorModel", Method, 0}, + {"(*Paletted).Opaque", Method, 0}, + {"(*Paletted).PixOffset", Method, 0}, + {"(*Paletted).RGBA64At", Method, 17}, + {"(*Paletted).Set", Method, 0}, + {"(*Paletted).SetColorIndex", Method, 0}, + {"(*Paletted).SetRGBA64", Method, 17}, + {"(*Paletted).SubImage", Method, 0}, + {"(*RGBA).At", Method, 0}, + {"(*RGBA).Bounds", Method, 0}, + {"(*RGBA).ColorModel", Method, 0}, + {"(*RGBA).Opaque", Method, 0}, + {"(*RGBA).PixOffset", Method, 0}, + {"(*RGBA).RGBA64At", Method, 17}, + {"(*RGBA).RGBAAt", Method, 4}, + {"(*RGBA).Set", Method, 0}, + {"(*RGBA).SetRGBA", Method, 0}, + {"(*RGBA).SetRGBA64", Method, 17}, + {"(*RGBA).SubImage", Method, 0}, + {"(*RGBA64).At", Method, 0}, + {"(*RGBA64).Bounds", Method, 0}, + {"(*RGBA64).ColorModel", Method, 0}, + {"(*RGBA64).Opaque", Method, 0}, + {"(*RGBA64).PixOffset", Method, 0}, + {"(*RGBA64).RGBA64At", Method, 4}, + {"(*RGBA64).Set", Method, 0}, + {"(*RGBA64).SetRGBA64", Method, 0}, + {"(*RGBA64).SubImage", Method, 0}, + {"(*Uniform).At", Method, 0}, + {"(*Uniform).Bounds", Method, 0}, + {"(*Uniform).ColorModel", Method, 0}, + {"(*Uniform).Convert", Method, 0}, + {"(*Uniform).Opaque", Method, 0}, + {"(*Uniform).RGBA", Method, 0}, + {"(*Uniform).RGBA64At", Method, 17}, + {"(*YCbCr).At", Method, 0}, + {"(*YCbCr).Bounds", Method, 0}, + {"(*YCbCr).COffset", Method, 0}, + {"(*YCbCr).ColorModel", Method, 0}, + {"(*YCbCr).Opaque", Method, 0}, + {"(*YCbCr).RGBA64At", Method, 17}, + {"(*YCbCr).SubImage", Method, 0}, + {"(*YCbCr).YCbCrAt", Method, 4}, + {"(*YCbCr).YOffset", Method, 0}, + {"(Point).Add", Method, 0}, + {"(Point).Div", Method, 0}, + {"(Point).Eq", Method, 0}, + {"(Point).In", Method, 0}, + {"(Point).Mod", Method, 0}, + {"(Point).Mul", Method, 0}, + {"(Point).String", Method, 0}, + {"(Point).Sub", Method, 0}, + {"(Rectangle).Add", Method, 0}, + {"(Rectangle).At", Method, 5}, + {"(Rectangle).Bounds", Method, 5}, + {"(Rectangle).Canon", Method, 0}, + {"(Rectangle).ColorModel", Method, 5}, + {"(Rectangle).Dx", Method, 0}, + {"(Rectangle).Dy", Method, 0}, + {"(Rectangle).Empty", Method, 0}, + {"(Rectangle).Eq", Method, 0}, + {"(Rectangle).In", Method, 0}, + {"(Rectangle).Inset", Method, 0}, + {"(Rectangle).Intersect", Method, 0}, + {"(Rectangle).Overlaps", Method, 0}, + {"(Rectangle).RGBA64At", Method, 17}, + {"(Rectangle).Size", Method, 0}, + {"(Rectangle).String", Method, 0}, + {"(Rectangle).Sub", Method, 0}, + {"(Rectangle).Union", Method, 0}, + {"(YCbCrSubsampleRatio).String", Method, 0}, + {"Alpha", Type, 0}, + {"Alpha.Pix", Field, 0}, + {"Alpha.Rect", Field, 0}, + {"Alpha.Stride", Field, 0}, + {"Alpha16", Type, 0}, + {"Alpha16.Pix", Field, 0}, + {"Alpha16.Rect", Field, 0}, + {"Alpha16.Stride", Field, 0}, + {"Black", Var, 0}, + {"CMYK", Type, 5}, + {"CMYK.Pix", Field, 5}, + {"CMYK.Rect", Field, 5}, + {"CMYK.Stride", Field, 5}, + {"Config", Type, 0}, + {"Config.ColorModel", Field, 0}, + {"Config.Height", Field, 0}, + {"Config.Width", Field, 0}, + {"Decode", Func, 0}, + {"DecodeConfig", Func, 0}, + {"ErrFormat", Var, 0}, + {"Gray", Type, 0}, + {"Gray.Pix", Field, 0}, + {"Gray.Rect", Field, 0}, + {"Gray.Stride", Field, 0}, + {"Gray16", Type, 0}, + {"Gray16.Pix", Field, 0}, + {"Gray16.Rect", Field, 0}, + {"Gray16.Stride", Field, 0}, + {"Image", Type, 0}, + {"NRGBA", Type, 0}, + {"NRGBA.Pix", Field, 0}, + {"NRGBA.Rect", Field, 0}, + {"NRGBA.Stride", Field, 0}, + {"NRGBA64", Type, 0}, + {"NRGBA64.Pix", Field, 0}, + {"NRGBA64.Rect", Field, 0}, + {"NRGBA64.Stride", Field, 0}, + {"NYCbCrA", Type, 6}, + {"NYCbCrA.A", Field, 6}, + {"NYCbCrA.AStride", Field, 6}, + {"NYCbCrA.YCbCr", Field, 6}, + {"NewAlpha", Func, 0}, + {"NewAlpha16", Func, 0}, + {"NewCMYK", Func, 5}, + {"NewGray", Func, 0}, + {"NewGray16", Func, 0}, + {"NewNRGBA", Func, 0}, + {"NewNRGBA64", Func, 0}, + {"NewNYCbCrA", Func, 6}, + {"NewPaletted", Func, 0}, + {"NewRGBA", Func, 0}, + {"NewRGBA64", Func, 0}, + {"NewUniform", Func, 0}, + {"NewYCbCr", Func, 0}, + {"Opaque", Var, 0}, + {"Paletted", Type, 0}, + {"Paletted.Palette", Field, 0}, + {"Paletted.Pix", Field, 0}, + {"Paletted.Rect", Field, 0}, + {"Paletted.Stride", Field, 0}, + {"PalettedImage", Type, 0}, + {"Point", Type, 0}, + {"Point.X", Field, 0}, + {"Point.Y", Field, 0}, + {"Pt", Func, 0}, + {"RGBA", Type, 0}, + {"RGBA.Pix", Field, 0}, + {"RGBA.Rect", Field, 0}, + {"RGBA.Stride", Field, 0}, + {"RGBA64", Type, 0}, + {"RGBA64.Pix", Field, 0}, + {"RGBA64.Rect", Field, 0}, + {"RGBA64.Stride", Field, 0}, + {"RGBA64Image", Type, 17}, + {"Rect", Func, 0}, + {"Rectangle", Type, 0}, + {"Rectangle.Max", Field, 0}, + {"Rectangle.Min", Field, 0}, + {"RegisterFormat", Func, 0}, + {"Transparent", Var, 0}, + {"Uniform", Type, 0}, + {"Uniform.C", Field, 0}, + {"White", Var, 0}, + {"YCbCr", Type, 0}, + {"YCbCr.CStride", Field, 0}, + {"YCbCr.Cb", Field, 0}, + {"YCbCr.Cr", Field, 0}, + {"YCbCr.Rect", Field, 0}, + {"YCbCr.SubsampleRatio", Field, 0}, + {"YCbCr.Y", Field, 0}, + {"YCbCr.YStride", Field, 0}, + {"YCbCrSubsampleRatio", Type, 0}, + {"YCbCrSubsampleRatio410", Const, 5}, + {"YCbCrSubsampleRatio411", Const, 5}, + {"YCbCrSubsampleRatio420", Const, 0}, + {"YCbCrSubsampleRatio422", Const, 0}, + {"YCbCrSubsampleRatio440", Const, 1}, + {"YCbCrSubsampleRatio444", Const, 0}, + {"ZP", Var, 0}, + {"ZR", Var, 0}, + }, + "image/color": { + {"(Alpha).RGBA", Method, 0}, + {"(Alpha16).RGBA", Method, 0}, + {"(CMYK).RGBA", Method, 5}, + {"(Gray).RGBA", Method, 0}, + {"(Gray16).RGBA", Method, 0}, + {"(NRGBA).RGBA", Method, 0}, + {"(NRGBA64).RGBA", Method, 0}, + {"(NYCbCrA).RGBA", Method, 6}, + {"(Palette).Convert", Method, 0}, + {"(Palette).Index", Method, 0}, + {"(RGBA).RGBA", Method, 0}, + {"(RGBA64).RGBA", Method, 0}, + {"(YCbCr).RGBA", Method, 0}, + {"Alpha", Type, 0}, + {"Alpha.A", Field, 0}, + {"Alpha16", Type, 0}, + {"Alpha16.A", Field, 0}, + {"Alpha16Model", Var, 0}, + {"AlphaModel", Var, 0}, + {"Black", Var, 0}, + {"CMYK", Type, 5}, + {"CMYK.C", Field, 5}, + {"CMYK.K", Field, 5}, + {"CMYK.M", Field, 5}, + {"CMYK.Y", Field, 5}, + {"CMYKModel", Var, 5}, + {"CMYKToRGB", Func, 5}, + {"Color", Type, 0}, + {"Gray", Type, 0}, + {"Gray.Y", Field, 0}, + {"Gray16", Type, 0}, + {"Gray16.Y", Field, 0}, + {"Gray16Model", Var, 0}, + {"GrayModel", Var, 0}, + {"Model", Type, 0}, + {"ModelFunc", Func, 0}, + {"NRGBA", Type, 0}, + {"NRGBA.A", Field, 0}, + {"NRGBA.B", Field, 0}, + {"NRGBA.G", Field, 0}, + {"NRGBA.R", Field, 0}, + {"NRGBA64", Type, 0}, + {"NRGBA64.A", Field, 0}, + {"NRGBA64.B", Field, 0}, + {"NRGBA64.G", Field, 0}, + {"NRGBA64.R", Field, 0}, + {"NRGBA64Model", Var, 0}, + {"NRGBAModel", Var, 0}, + {"NYCbCrA", Type, 6}, + {"NYCbCrA.A", Field, 6}, + {"NYCbCrA.YCbCr", Field, 6}, + {"NYCbCrAModel", Var, 6}, + {"Opaque", Var, 0}, + {"Palette", Type, 0}, + {"RGBA", Type, 0}, + {"RGBA.A", Field, 0}, + {"RGBA.B", Field, 0}, + {"RGBA.G", Field, 0}, + {"RGBA.R", Field, 0}, + {"RGBA64", Type, 0}, + {"RGBA64.A", Field, 0}, + {"RGBA64.B", Field, 0}, + {"RGBA64.G", Field, 0}, + {"RGBA64.R", Field, 0}, + {"RGBA64Model", Var, 0}, + {"RGBAModel", Var, 0}, + {"RGBToCMYK", Func, 5}, + {"RGBToYCbCr", Func, 0}, + {"Transparent", Var, 0}, + {"White", Var, 0}, + {"YCbCr", Type, 0}, + {"YCbCr.Cb", Field, 0}, + {"YCbCr.Cr", Field, 0}, + {"YCbCr.Y", Field, 0}, + {"YCbCrModel", Var, 0}, + {"YCbCrToRGB", Func, 0}, + }, + "image/color/palette": { + {"Plan9", Var, 2}, + {"WebSafe", Var, 2}, + }, + "image/draw": { + {"(Op).Draw", Method, 2}, + {"Draw", Func, 0}, + {"DrawMask", Func, 0}, + {"Drawer", Type, 2}, + {"FloydSteinberg", Var, 2}, + {"Image", Type, 0}, + {"Op", Type, 0}, + {"Over", Const, 0}, + {"Quantizer", Type, 2}, + {"RGBA64Image", Type, 17}, + {"Src", Const, 0}, + }, + "image/gif": { + {"Decode", Func, 0}, + {"DecodeAll", Func, 0}, + {"DecodeConfig", Func, 0}, + {"DisposalBackground", Const, 5}, + {"DisposalNone", Const, 5}, + {"DisposalPrevious", Const, 5}, + {"Encode", Func, 2}, + {"EncodeAll", Func, 2}, + {"GIF", Type, 0}, + {"GIF.BackgroundIndex", Field, 5}, + {"GIF.Config", Field, 5}, + {"GIF.Delay", Field, 0}, + {"GIF.Disposal", Field, 5}, + {"GIF.Image", Field, 0}, + {"GIF.LoopCount", Field, 0}, + {"Options", Type, 2}, + {"Options.Drawer", Field, 2}, + {"Options.NumColors", Field, 2}, + {"Options.Quantizer", Field, 2}, + }, + "image/jpeg": { + {"(FormatError).Error", Method, 0}, + {"(UnsupportedError).Error", Method, 0}, + {"Decode", Func, 0}, + {"DecodeConfig", Func, 0}, + {"DefaultQuality", Const, 0}, + {"Encode", Func, 0}, + {"FormatError", Type, 0}, + {"Options", Type, 0}, + {"Options.Quality", Field, 0}, + {"Reader", Type, 0}, + {"UnsupportedError", Type, 0}, + }, + "image/png": { + {"(*Encoder).Encode", Method, 4}, + {"(FormatError).Error", Method, 0}, + {"(UnsupportedError).Error", Method, 0}, + {"BestCompression", Const, 4}, + {"BestSpeed", Const, 4}, + {"CompressionLevel", Type, 4}, + {"Decode", Func, 0}, + {"DecodeConfig", Func, 0}, + {"DefaultCompression", Const, 4}, + {"Encode", Func, 0}, + {"Encoder", Type, 4}, + {"Encoder.BufferPool", Field, 9}, + {"Encoder.CompressionLevel", Field, 4}, + {"EncoderBuffer", Type, 9}, + {"EncoderBufferPool", Type, 9}, + {"FormatError", Type, 0}, + {"NoCompression", Const, 4}, + {"UnsupportedError", Type, 0}, + }, + "index/suffixarray": { + {"(*Index).Bytes", Method, 0}, + {"(*Index).FindAllIndex", Method, 0}, + {"(*Index).Lookup", Method, 0}, + {"(*Index).Read", Method, 0}, + {"(*Index).Write", Method, 0}, + {"Index", Type, 0}, + {"New", Func, 0}, + }, + "io": { + {"(*LimitedReader).Read", Method, 0}, + {"(*OffsetWriter).Seek", Method, 20}, + {"(*OffsetWriter).Write", Method, 20}, + {"(*OffsetWriter).WriteAt", Method, 20}, + {"(*PipeReader).Close", Method, 0}, + {"(*PipeReader).CloseWithError", Method, 0}, + {"(*PipeReader).Read", Method, 0}, + {"(*PipeWriter).Close", Method, 0}, + {"(*PipeWriter).CloseWithError", Method, 0}, + {"(*PipeWriter).Write", Method, 0}, + {"(*SectionReader).Outer", Method, 22}, + {"(*SectionReader).Read", Method, 0}, + {"(*SectionReader).ReadAt", Method, 0}, + {"(*SectionReader).Seek", Method, 0}, + {"(*SectionReader).Size", Method, 0}, + {"ByteReader", Type, 0}, + {"ByteScanner", Type, 0}, + {"ByteWriter", Type, 1}, + {"Closer", Type, 0}, + {"Copy", Func, 0}, + {"CopyBuffer", Func, 5}, + {"CopyN", Func, 0}, + {"Discard", Var, 16}, + {"EOF", Var, 0}, + {"ErrClosedPipe", Var, 0}, + {"ErrNoProgress", Var, 1}, + {"ErrShortBuffer", Var, 0}, + {"ErrShortWrite", Var, 0}, + {"ErrUnexpectedEOF", Var, 0}, + {"LimitReader", Func, 0}, + {"LimitedReader", Type, 0}, + {"LimitedReader.N", Field, 0}, + {"LimitedReader.R", Field, 0}, + {"MultiReader", Func, 0}, + {"MultiWriter", Func, 0}, + {"NewOffsetWriter", Func, 20}, + {"NewSectionReader", Func, 0}, + {"NopCloser", Func, 16}, + {"OffsetWriter", Type, 20}, + {"Pipe", Func, 0}, + {"PipeReader", Type, 0}, + {"PipeWriter", Type, 0}, + {"ReadAll", Func, 16}, + {"ReadAtLeast", Func, 0}, + {"ReadCloser", Type, 0}, + {"ReadFull", Func, 0}, + {"ReadSeekCloser", Type, 16}, + {"ReadSeeker", Type, 0}, + {"ReadWriteCloser", Type, 0}, + {"ReadWriteSeeker", Type, 0}, + {"ReadWriter", Type, 0}, + {"Reader", Type, 0}, + {"ReaderAt", Type, 0}, + {"ReaderFrom", Type, 0}, + {"RuneReader", Type, 0}, + {"RuneScanner", Type, 0}, + {"SectionReader", Type, 0}, + {"SeekCurrent", Const, 7}, + {"SeekEnd", Const, 7}, + {"SeekStart", Const, 7}, + {"Seeker", Type, 0}, + {"StringWriter", Type, 12}, + {"TeeReader", Func, 0}, + {"WriteCloser", Type, 0}, + {"WriteSeeker", Type, 0}, + {"WriteString", Func, 0}, + {"Writer", Type, 0}, + {"WriterAt", Type, 0}, + {"WriterTo", Type, 0}, + }, + "io/fs": { + {"(*PathError).Error", Method, 16}, + {"(*PathError).Timeout", Method, 16}, + {"(*PathError).Unwrap", Method, 16}, + {"(FileMode).IsDir", Method, 16}, + {"(FileMode).IsRegular", Method, 16}, + {"(FileMode).Perm", Method, 16}, + {"(FileMode).String", Method, 16}, + {"(FileMode).Type", Method, 16}, + {"DirEntry", Type, 16}, + {"ErrClosed", Var, 16}, + {"ErrExist", Var, 16}, + {"ErrInvalid", Var, 16}, + {"ErrNotExist", Var, 16}, + {"ErrPermission", Var, 16}, + {"FS", Type, 16}, + {"File", Type, 16}, + {"FileInfo", Type, 16}, + {"FileInfoToDirEntry", Func, 17}, + {"FileMode", Type, 16}, + {"FormatDirEntry", Func, 21}, + {"FormatFileInfo", Func, 21}, + {"Glob", Func, 16}, + {"GlobFS", Type, 16}, + {"ModeAppend", Const, 16}, + {"ModeCharDevice", Const, 16}, + {"ModeDevice", Const, 16}, + {"ModeDir", Const, 16}, + {"ModeExclusive", Const, 16}, + {"ModeIrregular", Const, 16}, + {"ModeNamedPipe", Const, 16}, + {"ModePerm", Const, 16}, + {"ModeSetgid", Const, 16}, + {"ModeSetuid", Const, 16}, + {"ModeSocket", Const, 16}, + {"ModeSticky", Const, 16}, + {"ModeSymlink", Const, 16}, + {"ModeTemporary", Const, 16}, + {"ModeType", Const, 16}, + {"PathError", Type, 16}, + {"PathError.Err", Field, 16}, + {"PathError.Op", Field, 16}, + {"PathError.Path", Field, 16}, + {"ReadDir", Func, 16}, + {"ReadDirFS", Type, 16}, + {"ReadDirFile", Type, 16}, + {"ReadFile", Func, 16}, + {"ReadFileFS", Type, 16}, + {"SkipAll", Var, 20}, + {"SkipDir", Var, 16}, + {"Stat", Func, 16}, + {"StatFS", Type, 16}, + {"Sub", Func, 16}, + {"SubFS", Type, 16}, + {"ValidPath", Func, 16}, + {"WalkDir", Func, 16}, + {"WalkDirFunc", Type, 16}, + }, + "io/ioutil": { + {"Discard", Var, 0}, + {"NopCloser", Func, 0}, + {"ReadAll", Func, 0}, + {"ReadDir", Func, 0}, + {"ReadFile", Func, 0}, + {"TempDir", Func, 0}, + {"TempFile", Func, 0}, + {"WriteFile", Func, 0}, + }, + "log": { + {"(*Logger).Fatal", Method, 0}, + {"(*Logger).Fatalf", Method, 0}, + {"(*Logger).Fatalln", Method, 0}, + {"(*Logger).Flags", Method, 0}, + {"(*Logger).Output", Method, 0}, + {"(*Logger).Panic", Method, 0}, + {"(*Logger).Panicf", Method, 0}, + {"(*Logger).Panicln", Method, 0}, + {"(*Logger).Prefix", Method, 0}, + {"(*Logger).Print", Method, 0}, + {"(*Logger).Printf", Method, 0}, + {"(*Logger).Println", Method, 0}, + {"(*Logger).SetFlags", Method, 0}, + {"(*Logger).SetOutput", Method, 5}, + {"(*Logger).SetPrefix", Method, 0}, + {"(*Logger).Writer", Method, 12}, + {"Default", Func, 16}, + {"Fatal", Func, 0}, + {"Fatalf", Func, 0}, + {"Fatalln", Func, 0}, + {"Flags", Func, 0}, + {"LUTC", Const, 5}, + {"Ldate", Const, 0}, + {"Llongfile", Const, 0}, + {"Lmicroseconds", Const, 0}, + {"Lmsgprefix", Const, 14}, + {"Logger", Type, 0}, + {"Lshortfile", Const, 0}, + {"LstdFlags", Const, 0}, + {"Ltime", Const, 0}, + {"New", Func, 0}, + {"Output", Func, 5}, + {"Panic", Func, 0}, + {"Panicf", Func, 0}, + {"Panicln", Func, 0}, + {"Prefix", Func, 0}, + {"Print", Func, 0}, + {"Printf", Func, 0}, + {"Println", Func, 0}, + {"SetFlags", Func, 0}, + {"SetOutput", Func, 0}, + {"SetPrefix", Func, 0}, + {"Writer", Func, 13}, + }, + "log/slog": { + {"(*JSONHandler).Enabled", Method, 21}, + {"(*JSONHandler).Handle", Method, 21}, + {"(*JSONHandler).WithAttrs", Method, 21}, + {"(*JSONHandler).WithGroup", Method, 21}, + {"(*Level).UnmarshalJSON", Method, 21}, + {"(*Level).UnmarshalText", Method, 21}, + {"(*LevelVar).Level", Method, 21}, + {"(*LevelVar).MarshalText", Method, 21}, + {"(*LevelVar).Set", Method, 21}, + {"(*LevelVar).String", Method, 21}, + {"(*LevelVar).UnmarshalText", Method, 21}, + {"(*Logger).Debug", Method, 21}, + {"(*Logger).DebugContext", Method, 21}, + {"(*Logger).Enabled", Method, 21}, + {"(*Logger).Error", Method, 21}, + {"(*Logger).ErrorContext", Method, 21}, + {"(*Logger).Handler", Method, 21}, + {"(*Logger).Info", Method, 21}, + {"(*Logger).InfoContext", Method, 21}, + {"(*Logger).Log", Method, 21}, + {"(*Logger).LogAttrs", Method, 21}, + {"(*Logger).Warn", Method, 21}, + {"(*Logger).WarnContext", Method, 21}, + {"(*Logger).With", Method, 21}, + {"(*Logger).WithGroup", Method, 21}, + {"(*Record).Add", Method, 21}, + {"(*Record).AddAttrs", Method, 21}, + {"(*TextHandler).Enabled", Method, 21}, + {"(*TextHandler).Handle", Method, 21}, + {"(*TextHandler).WithAttrs", Method, 21}, + {"(*TextHandler).WithGroup", Method, 21}, + {"(Attr).Equal", Method, 21}, + {"(Attr).String", Method, 21}, + {"(Kind).String", Method, 21}, + {"(Level).Level", Method, 21}, + {"(Level).MarshalJSON", Method, 21}, + {"(Level).MarshalText", Method, 21}, + {"(Level).String", Method, 21}, + {"(Record).Attrs", Method, 21}, + {"(Record).Clone", Method, 21}, + {"(Record).NumAttrs", Method, 21}, + {"(Value).Any", Method, 21}, + {"(Value).Bool", Method, 21}, + {"(Value).Duration", Method, 21}, + {"(Value).Equal", Method, 21}, + {"(Value).Float64", Method, 21}, + {"(Value).Group", Method, 21}, + {"(Value).Int64", Method, 21}, + {"(Value).Kind", Method, 21}, + {"(Value).LogValuer", Method, 21}, + {"(Value).Resolve", Method, 21}, + {"(Value).String", Method, 21}, + {"(Value).Time", Method, 21}, + {"(Value).Uint64", Method, 21}, + {"Any", Func, 21}, + {"AnyValue", Func, 21}, + {"Attr", Type, 21}, + {"Attr.Key", Field, 21}, + {"Attr.Value", Field, 21}, + {"Bool", Func, 21}, + {"BoolValue", Func, 21}, + {"Debug", Func, 21}, + {"DebugContext", Func, 21}, + {"Default", Func, 21}, + {"Duration", Func, 21}, + {"DurationValue", Func, 21}, + {"Error", Func, 21}, + {"ErrorContext", Func, 21}, + {"Float64", Func, 21}, + {"Float64Value", Func, 21}, + {"Group", Func, 21}, + {"GroupValue", Func, 21}, + {"Handler", Type, 21}, + {"HandlerOptions", Type, 21}, + {"HandlerOptions.AddSource", Field, 21}, + {"HandlerOptions.Level", Field, 21}, + {"HandlerOptions.ReplaceAttr", Field, 21}, + {"Info", Func, 21}, + {"InfoContext", Func, 21}, + {"Int", Func, 21}, + {"Int64", Func, 21}, + {"Int64Value", Func, 21}, + {"IntValue", Func, 21}, + {"JSONHandler", Type, 21}, + {"Kind", Type, 21}, + {"KindAny", Const, 21}, + {"KindBool", Const, 21}, + {"KindDuration", Const, 21}, + {"KindFloat64", Const, 21}, + {"KindGroup", Const, 21}, + {"KindInt64", Const, 21}, + {"KindLogValuer", Const, 21}, + {"KindString", Const, 21}, + {"KindTime", Const, 21}, + {"KindUint64", Const, 21}, + {"Level", Type, 21}, + {"LevelDebug", Const, 21}, + {"LevelError", Const, 21}, + {"LevelInfo", Const, 21}, + {"LevelKey", Const, 21}, + {"LevelVar", Type, 21}, + {"LevelWarn", Const, 21}, + {"Leveler", Type, 21}, + {"Log", Func, 21}, + {"LogAttrs", Func, 21}, + {"LogValuer", Type, 21}, + {"Logger", Type, 21}, + {"MessageKey", Const, 21}, + {"New", Func, 21}, + {"NewJSONHandler", Func, 21}, + {"NewLogLogger", Func, 21}, + {"NewRecord", Func, 21}, + {"NewTextHandler", Func, 21}, + {"Record", Type, 21}, + {"Record.Level", Field, 21}, + {"Record.Message", Field, 21}, + {"Record.PC", Field, 21}, + {"Record.Time", Field, 21}, + {"SetDefault", Func, 21}, + {"SetLogLoggerLevel", Func, 22}, + {"Source", Type, 21}, + {"Source.File", Field, 21}, + {"Source.Function", Field, 21}, + {"Source.Line", Field, 21}, + {"SourceKey", Const, 21}, + {"String", Func, 21}, + {"StringValue", Func, 21}, + {"TextHandler", Type, 21}, + {"Time", Func, 21}, + {"TimeKey", Const, 21}, + {"TimeValue", Func, 21}, + {"Uint64", Func, 21}, + {"Uint64Value", Func, 21}, + {"Value", Type, 21}, + {"Warn", Func, 21}, + {"WarnContext", Func, 21}, + {"With", Func, 21}, + }, + "log/syslog": { + {"(*Writer).Alert", Method, 0}, + {"(*Writer).Close", Method, 0}, + {"(*Writer).Crit", Method, 0}, + {"(*Writer).Debug", Method, 0}, + {"(*Writer).Emerg", Method, 0}, + {"(*Writer).Err", Method, 0}, + {"(*Writer).Info", Method, 0}, + {"(*Writer).Notice", Method, 0}, + {"(*Writer).Warning", Method, 0}, + {"(*Writer).Write", Method, 0}, + {"Dial", Func, 0}, + {"LOG_ALERT", Const, 0}, + {"LOG_AUTH", Const, 1}, + {"LOG_AUTHPRIV", Const, 1}, + {"LOG_CRIT", Const, 0}, + {"LOG_CRON", Const, 1}, + {"LOG_DAEMON", Const, 1}, + {"LOG_DEBUG", Const, 0}, + {"LOG_EMERG", Const, 0}, + {"LOG_ERR", Const, 0}, + {"LOG_FTP", Const, 1}, + {"LOG_INFO", Const, 0}, + {"LOG_KERN", Const, 1}, + {"LOG_LOCAL0", Const, 1}, + {"LOG_LOCAL1", Const, 1}, + {"LOG_LOCAL2", Const, 1}, + {"LOG_LOCAL3", Const, 1}, + {"LOG_LOCAL4", Const, 1}, + {"LOG_LOCAL5", Const, 1}, + {"LOG_LOCAL6", Const, 1}, + {"LOG_LOCAL7", Const, 1}, + {"LOG_LPR", Const, 1}, + {"LOG_MAIL", Const, 1}, + {"LOG_NEWS", Const, 1}, + {"LOG_NOTICE", Const, 0}, + {"LOG_SYSLOG", Const, 1}, + {"LOG_USER", Const, 1}, + {"LOG_UUCP", Const, 1}, + {"LOG_WARNING", Const, 0}, + {"New", Func, 0}, + {"NewLogger", Func, 0}, + {"Priority", Type, 0}, + {"Writer", Type, 0}, + }, + "maps": { + {"Clone", Func, 21}, + {"Copy", Func, 21}, + {"DeleteFunc", Func, 21}, + {"Equal", Func, 21}, + {"EqualFunc", Func, 21}, + }, + "math": { + {"Abs", Func, 0}, + {"Acos", Func, 0}, + {"Acosh", Func, 0}, + {"Asin", Func, 0}, + {"Asinh", Func, 0}, + {"Atan", Func, 0}, + {"Atan2", Func, 0}, + {"Atanh", Func, 0}, + {"Cbrt", Func, 0}, + {"Ceil", Func, 0}, + {"Copysign", Func, 0}, + {"Cos", Func, 0}, + {"Cosh", Func, 0}, + {"Dim", Func, 0}, + {"E", Const, 0}, + {"Erf", Func, 0}, + {"Erfc", Func, 0}, + {"Erfcinv", Func, 10}, + {"Erfinv", Func, 10}, + {"Exp", Func, 0}, + {"Exp2", Func, 0}, + {"Expm1", Func, 0}, + {"FMA", Func, 14}, + {"Float32bits", Func, 0}, + {"Float32frombits", Func, 0}, + {"Float64bits", Func, 0}, + {"Float64frombits", Func, 0}, + {"Floor", Func, 0}, + {"Frexp", Func, 0}, + {"Gamma", Func, 0}, + {"Hypot", Func, 0}, + {"Ilogb", Func, 0}, + {"Inf", Func, 0}, + {"IsInf", Func, 0}, + {"IsNaN", Func, 0}, + {"J0", Func, 0}, + {"J1", Func, 0}, + {"Jn", Func, 0}, + {"Ldexp", Func, 0}, + {"Lgamma", Func, 0}, + {"Ln10", Const, 0}, + {"Ln2", Const, 0}, + {"Log", Func, 0}, + {"Log10", Func, 0}, + {"Log10E", Const, 0}, + {"Log1p", Func, 0}, + {"Log2", Func, 0}, + {"Log2E", Const, 0}, + {"Logb", Func, 0}, + {"Max", Func, 0}, + {"MaxFloat32", Const, 0}, + {"MaxFloat64", Const, 0}, + {"MaxInt", Const, 17}, + {"MaxInt16", Const, 0}, + {"MaxInt32", Const, 0}, + {"MaxInt64", Const, 0}, + {"MaxInt8", Const, 0}, + {"MaxUint", Const, 17}, + {"MaxUint16", Const, 0}, + {"MaxUint32", Const, 0}, + {"MaxUint64", Const, 0}, + {"MaxUint8", Const, 0}, + {"Min", Func, 0}, + {"MinInt", Const, 17}, + {"MinInt16", Const, 0}, + {"MinInt32", Const, 0}, + {"MinInt64", Const, 0}, + {"MinInt8", Const, 0}, + {"Mod", Func, 0}, + {"Modf", Func, 0}, + {"NaN", Func, 0}, + {"Nextafter", Func, 0}, + {"Nextafter32", Func, 4}, + {"Phi", Const, 0}, + {"Pi", Const, 0}, + {"Pow", Func, 0}, + {"Pow10", Func, 0}, + {"Remainder", Func, 0}, + {"Round", Func, 10}, + {"RoundToEven", Func, 10}, + {"Signbit", Func, 0}, + {"Sin", Func, 0}, + {"Sincos", Func, 0}, + {"Sinh", Func, 0}, + {"SmallestNonzeroFloat32", Const, 0}, + {"SmallestNonzeroFloat64", Const, 0}, + {"Sqrt", Func, 0}, + {"Sqrt2", Const, 0}, + {"SqrtE", Const, 0}, + {"SqrtPhi", Const, 0}, + {"SqrtPi", Const, 0}, + {"Tan", Func, 0}, + {"Tanh", Func, 0}, + {"Trunc", Func, 0}, + {"Y0", Func, 0}, + {"Y1", Func, 0}, + {"Yn", Func, 0}, + }, + "math/big": { + {"(*Float).Abs", Method, 5}, + {"(*Float).Acc", Method, 5}, + {"(*Float).Add", Method, 5}, + {"(*Float).Append", Method, 5}, + {"(*Float).Cmp", Method, 5}, + {"(*Float).Copy", Method, 5}, + {"(*Float).Float32", Method, 5}, + {"(*Float).Float64", Method, 5}, + {"(*Float).Format", Method, 5}, + {"(*Float).GobDecode", Method, 7}, + {"(*Float).GobEncode", Method, 7}, + {"(*Float).Int", Method, 5}, + {"(*Float).Int64", Method, 5}, + {"(*Float).IsInf", Method, 5}, + {"(*Float).IsInt", Method, 5}, + {"(*Float).MantExp", Method, 5}, + {"(*Float).MarshalText", Method, 6}, + {"(*Float).MinPrec", Method, 5}, + {"(*Float).Mode", Method, 5}, + {"(*Float).Mul", Method, 5}, + {"(*Float).Neg", Method, 5}, + {"(*Float).Parse", Method, 5}, + {"(*Float).Prec", Method, 5}, + {"(*Float).Quo", Method, 5}, + {"(*Float).Rat", Method, 5}, + {"(*Float).Scan", Method, 8}, + {"(*Float).Set", Method, 5}, + {"(*Float).SetFloat64", Method, 5}, + {"(*Float).SetInf", Method, 5}, + {"(*Float).SetInt", Method, 5}, + {"(*Float).SetInt64", Method, 5}, + {"(*Float).SetMantExp", Method, 5}, + {"(*Float).SetMode", Method, 5}, + {"(*Float).SetPrec", Method, 5}, + {"(*Float).SetRat", Method, 5}, + {"(*Float).SetString", Method, 5}, + {"(*Float).SetUint64", Method, 5}, + {"(*Float).Sign", Method, 5}, + {"(*Float).Signbit", Method, 5}, + {"(*Float).Sqrt", Method, 10}, + {"(*Float).String", Method, 5}, + {"(*Float).Sub", Method, 5}, + {"(*Float).Text", Method, 5}, + {"(*Float).Uint64", Method, 5}, + {"(*Float).UnmarshalText", Method, 6}, + {"(*Int).Abs", Method, 0}, + {"(*Int).Add", Method, 0}, + {"(*Int).And", Method, 0}, + {"(*Int).AndNot", Method, 0}, + {"(*Int).Append", Method, 6}, + {"(*Int).Binomial", Method, 0}, + {"(*Int).Bit", Method, 0}, + {"(*Int).BitLen", Method, 0}, + {"(*Int).Bits", Method, 0}, + {"(*Int).Bytes", Method, 0}, + {"(*Int).Cmp", Method, 0}, + {"(*Int).CmpAbs", Method, 10}, + {"(*Int).Div", Method, 0}, + {"(*Int).DivMod", Method, 0}, + {"(*Int).Exp", Method, 0}, + {"(*Int).FillBytes", Method, 15}, + {"(*Int).Float64", Method, 21}, + {"(*Int).Format", Method, 0}, + {"(*Int).GCD", Method, 0}, + {"(*Int).GobDecode", Method, 0}, + {"(*Int).GobEncode", Method, 0}, + {"(*Int).Int64", Method, 0}, + {"(*Int).IsInt64", Method, 9}, + {"(*Int).IsUint64", Method, 9}, + {"(*Int).Lsh", Method, 0}, + {"(*Int).MarshalJSON", Method, 1}, + {"(*Int).MarshalText", Method, 3}, + {"(*Int).Mod", Method, 0}, + {"(*Int).ModInverse", Method, 0}, + {"(*Int).ModSqrt", Method, 5}, + {"(*Int).Mul", Method, 0}, + {"(*Int).MulRange", Method, 0}, + {"(*Int).Neg", Method, 0}, + {"(*Int).Not", Method, 0}, + {"(*Int).Or", Method, 0}, + {"(*Int).ProbablyPrime", Method, 0}, + {"(*Int).Quo", Method, 0}, + {"(*Int).QuoRem", Method, 0}, + {"(*Int).Rand", Method, 0}, + {"(*Int).Rem", Method, 0}, + {"(*Int).Rsh", Method, 0}, + {"(*Int).Scan", Method, 0}, + {"(*Int).Set", Method, 0}, + {"(*Int).SetBit", Method, 0}, + {"(*Int).SetBits", Method, 0}, + {"(*Int).SetBytes", Method, 0}, + {"(*Int).SetInt64", Method, 0}, + {"(*Int).SetString", Method, 0}, + {"(*Int).SetUint64", Method, 1}, + {"(*Int).Sign", Method, 0}, + {"(*Int).Sqrt", Method, 8}, + {"(*Int).String", Method, 0}, + {"(*Int).Sub", Method, 0}, + {"(*Int).Text", Method, 6}, + {"(*Int).TrailingZeroBits", Method, 13}, + {"(*Int).Uint64", Method, 1}, + {"(*Int).UnmarshalJSON", Method, 1}, + {"(*Int).UnmarshalText", Method, 3}, + {"(*Int).Xor", Method, 0}, + {"(*Rat).Abs", Method, 0}, + {"(*Rat).Add", Method, 0}, + {"(*Rat).Cmp", Method, 0}, + {"(*Rat).Denom", Method, 0}, + {"(*Rat).Float32", Method, 4}, + {"(*Rat).Float64", Method, 1}, + {"(*Rat).FloatPrec", Method, 22}, + {"(*Rat).FloatString", Method, 0}, + {"(*Rat).GobDecode", Method, 0}, + {"(*Rat).GobEncode", Method, 0}, + {"(*Rat).Inv", Method, 0}, + {"(*Rat).IsInt", Method, 0}, + {"(*Rat).MarshalText", Method, 3}, + {"(*Rat).Mul", Method, 0}, + {"(*Rat).Neg", Method, 0}, + {"(*Rat).Num", Method, 0}, + {"(*Rat).Quo", Method, 0}, + {"(*Rat).RatString", Method, 0}, + {"(*Rat).Scan", Method, 0}, + {"(*Rat).Set", Method, 0}, + {"(*Rat).SetFloat64", Method, 1}, + {"(*Rat).SetFrac", Method, 0}, + {"(*Rat).SetFrac64", Method, 0}, + {"(*Rat).SetInt", Method, 0}, + {"(*Rat).SetInt64", Method, 0}, + {"(*Rat).SetString", Method, 0}, + {"(*Rat).SetUint64", Method, 13}, + {"(*Rat).Sign", Method, 0}, + {"(*Rat).String", Method, 0}, + {"(*Rat).Sub", Method, 0}, + {"(*Rat).UnmarshalText", Method, 3}, + {"(Accuracy).String", Method, 5}, + {"(ErrNaN).Error", Method, 5}, + {"(RoundingMode).String", Method, 5}, + {"Above", Const, 5}, + {"Accuracy", Type, 5}, + {"AwayFromZero", Const, 5}, + {"Below", Const, 5}, + {"ErrNaN", Type, 5}, + {"Exact", Const, 5}, + {"Float", Type, 5}, + {"Int", Type, 0}, + {"Jacobi", Func, 5}, + {"MaxBase", Const, 0}, + {"MaxExp", Const, 5}, + {"MaxPrec", Const, 5}, + {"MinExp", Const, 5}, + {"NewFloat", Func, 5}, + {"NewInt", Func, 0}, + {"NewRat", Func, 0}, + {"ParseFloat", Func, 5}, + {"Rat", Type, 0}, + {"RoundingMode", Type, 5}, + {"ToNearestAway", Const, 5}, + {"ToNearestEven", Const, 5}, + {"ToNegativeInf", Const, 5}, + {"ToPositiveInf", Const, 5}, + {"ToZero", Const, 5}, + {"Word", Type, 0}, + }, + "math/bits": { + {"Add", Func, 12}, + {"Add32", Func, 12}, + {"Add64", Func, 12}, + {"Div", Func, 12}, + {"Div32", Func, 12}, + {"Div64", Func, 12}, + {"LeadingZeros", Func, 9}, + {"LeadingZeros16", Func, 9}, + {"LeadingZeros32", Func, 9}, + {"LeadingZeros64", Func, 9}, + {"LeadingZeros8", Func, 9}, + {"Len", Func, 9}, + {"Len16", Func, 9}, + {"Len32", Func, 9}, + {"Len64", Func, 9}, + {"Len8", Func, 9}, + {"Mul", Func, 12}, + {"Mul32", Func, 12}, + {"Mul64", Func, 12}, + {"OnesCount", Func, 9}, + {"OnesCount16", Func, 9}, + {"OnesCount32", Func, 9}, + {"OnesCount64", Func, 9}, + {"OnesCount8", Func, 9}, + {"Rem", Func, 14}, + {"Rem32", Func, 14}, + {"Rem64", Func, 14}, + {"Reverse", Func, 9}, + {"Reverse16", Func, 9}, + {"Reverse32", Func, 9}, + {"Reverse64", Func, 9}, + {"Reverse8", Func, 9}, + {"ReverseBytes", Func, 9}, + {"ReverseBytes16", Func, 9}, + {"ReverseBytes32", Func, 9}, + {"ReverseBytes64", Func, 9}, + {"RotateLeft", Func, 9}, + {"RotateLeft16", Func, 9}, + {"RotateLeft32", Func, 9}, + {"RotateLeft64", Func, 9}, + {"RotateLeft8", Func, 9}, + {"Sub", Func, 12}, + {"Sub32", Func, 12}, + {"Sub64", Func, 12}, + {"TrailingZeros", Func, 9}, + {"TrailingZeros16", Func, 9}, + {"TrailingZeros32", Func, 9}, + {"TrailingZeros64", Func, 9}, + {"TrailingZeros8", Func, 9}, + {"UintSize", Const, 9}, + }, + "math/cmplx": { + {"Abs", Func, 0}, + {"Acos", Func, 0}, + {"Acosh", Func, 0}, + {"Asin", Func, 0}, + {"Asinh", Func, 0}, + {"Atan", Func, 0}, + {"Atanh", Func, 0}, + {"Conj", Func, 0}, + {"Cos", Func, 0}, + {"Cosh", Func, 0}, + {"Cot", Func, 0}, + {"Exp", Func, 0}, + {"Inf", Func, 0}, + {"IsInf", Func, 0}, + {"IsNaN", Func, 0}, + {"Log", Func, 0}, + {"Log10", Func, 0}, + {"NaN", Func, 0}, + {"Phase", Func, 0}, + {"Polar", Func, 0}, + {"Pow", Func, 0}, + {"Rect", Func, 0}, + {"Sin", Func, 0}, + {"Sinh", Func, 0}, + {"Sqrt", Func, 0}, + {"Tan", Func, 0}, + {"Tanh", Func, 0}, + }, + "math/rand": { + {"(*Rand).ExpFloat64", Method, 0}, + {"(*Rand).Float32", Method, 0}, + {"(*Rand).Float64", Method, 0}, + {"(*Rand).Int", Method, 0}, + {"(*Rand).Int31", Method, 0}, + {"(*Rand).Int31n", Method, 0}, + {"(*Rand).Int63", Method, 0}, + {"(*Rand).Int63n", Method, 0}, + {"(*Rand).Intn", Method, 0}, + {"(*Rand).NormFloat64", Method, 0}, + {"(*Rand).Perm", Method, 0}, + {"(*Rand).Read", Method, 6}, + {"(*Rand).Seed", Method, 0}, + {"(*Rand).Shuffle", Method, 10}, + {"(*Rand).Uint32", Method, 0}, + {"(*Rand).Uint64", Method, 8}, + {"(*Zipf).Uint64", Method, 0}, + {"ExpFloat64", Func, 0}, + {"Float32", Func, 0}, + {"Float64", Func, 0}, + {"Int", Func, 0}, + {"Int31", Func, 0}, + {"Int31n", Func, 0}, + {"Int63", Func, 0}, + {"Int63n", Func, 0}, + {"Intn", Func, 0}, + {"New", Func, 0}, + {"NewSource", Func, 0}, + {"NewZipf", Func, 0}, + {"NormFloat64", Func, 0}, + {"Perm", Func, 0}, + {"Rand", Type, 0}, + {"Read", Func, 6}, + {"Seed", Func, 0}, + {"Shuffle", Func, 10}, + {"Source", Type, 0}, + {"Source64", Type, 8}, + {"Uint32", Func, 0}, + {"Uint64", Func, 8}, + {"Zipf", Type, 0}, + }, + "math/rand/v2": { + {"(*ChaCha8).MarshalBinary", Method, 22}, + {"(*ChaCha8).Seed", Method, 22}, + {"(*ChaCha8).Uint64", Method, 22}, + {"(*ChaCha8).UnmarshalBinary", Method, 22}, + {"(*PCG).MarshalBinary", Method, 22}, + {"(*PCG).Seed", Method, 22}, + {"(*PCG).Uint64", Method, 22}, + {"(*PCG).UnmarshalBinary", Method, 22}, + {"(*Rand).ExpFloat64", Method, 22}, + {"(*Rand).Float32", Method, 22}, + {"(*Rand).Float64", Method, 22}, + {"(*Rand).Int", Method, 22}, + {"(*Rand).Int32", Method, 22}, + {"(*Rand).Int32N", Method, 22}, + {"(*Rand).Int64", Method, 22}, + {"(*Rand).Int64N", Method, 22}, + {"(*Rand).IntN", Method, 22}, + {"(*Rand).NormFloat64", Method, 22}, + {"(*Rand).Perm", Method, 22}, + {"(*Rand).Shuffle", Method, 22}, + {"(*Rand).Uint32", Method, 22}, + {"(*Rand).Uint32N", Method, 22}, + {"(*Rand).Uint64", Method, 22}, + {"(*Rand).Uint64N", Method, 22}, + {"(*Rand).UintN", Method, 22}, + {"(*Zipf).Uint64", Method, 22}, + {"ChaCha8", Type, 22}, + {"ExpFloat64", Func, 22}, + {"Float32", Func, 22}, + {"Float64", Func, 22}, + {"Int", Func, 22}, + {"Int32", Func, 22}, + {"Int32N", Func, 22}, + {"Int64", Func, 22}, + {"Int64N", Func, 22}, + {"IntN", Func, 22}, + {"N", Func, 22}, + {"New", Func, 22}, + {"NewChaCha8", Func, 22}, + {"NewPCG", Func, 22}, + {"NewZipf", Func, 22}, + {"NormFloat64", Func, 22}, + {"PCG", Type, 22}, + {"Perm", Func, 22}, + {"Rand", Type, 22}, + {"Shuffle", Func, 22}, + {"Source", Type, 22}, + {"Uint32", Func, 22}, + {"Uint32N", Func, 22}, + {"Uint64", Func, 22}, + {"Uint64N", Func, 22}, + {"UintN", Func, 22}, + {"Zipf", Type, 22}, + }, + "mime": { + {"(*WordDecoder).Decode", Method, 5}, + {"(*WordDecoder).DecodeHeader", Method, 5}, + {"(WordEncoder).Encode", Method, 5}, + {"AddExtensionType", Func, 0}, + {"BEncoding", Const, 5}, + {"ErrInvalidMediaParameter", Var, 9}, + {"ExtensionsByType", Func, 5}, + {"FormatMediaType", Func, 0}, + {"ParseMediaType", Func, 0}, + {"QEncoding", Const, 5}, + {"TypeByExtension", Func, 0}, + {"WordDecoder", Type, 5}, + {"WordDecoder.CharsetReader", Field, 5}, + {"WordEncoder", Type, 5}, + }, + "mime/multipart": { + {"(*FileHeader).Open", Method, 0}, + {"(*Form).RemoveAll", Method, 0}, + {"(*Part).Close", Method, 0}, + {"(*Part).FileName", Method, 0}, + {"(*Part).FormName", Method, 0}, + {"(*Part).Read", Method, 0}, + {"(*Reader).NextPart", Method, 0}, + {"(*Reader).NextRawPart", Method, 14}, + {"(*Reader).ReadForm", Method, 0}, + {"(*Writer).Boundary", Method, 0}, + {"(*Writer).Close", Method, 0}, + {"(*Writer).CreateFormField", Method, 0}, + {"(*Writer).CreateFormFile", Method, 0}, + {"(*Writer).CreatePart", Method, 0}, + {"(*Writer).FormDataContentType", Method, 0}, + {"(*Writer).SetBoundary", Method, 1}, + {"(*Writer).WriteField", Method, 0}, + {"ErrMessageTooLarge", Var, 9}, + {"File", Type, 0}, + {"FileHeader", Type, 0}, + {"FileHeader.Filename", Field, 0}, + {"FileHeader.Header", Field, 0}, + {"FileHeader.Size", Field, 9}, + {"Form", Type, 0}, + {"Form.File", Field, 0}, + {"Form.Value", Field, 0}, + {"NewReader", Func, 0}, + {"NewWriter", Func, 0}, + {"Part", Type, 0}, + {"Part.Header", Field, 0}, + {"Reader", Type, 0}, + {"Writer", Type, 0}, + }, + "mime/quotedprintable": { + {"(*Reader).Read", Method, 5}, + {"(*Writer).Close", Method, 5}, + {"(*Writer).Write", Method, 5}, + {"NewReader", Func, 5}, + {"NewWriter", Func, 5}, + {"Reader", Type, 5}, + {"Writer", Type, 5}, + {"Writer.Binary", Field, 5}, + }, + "net": { + {"(*AddrError).Error", Method, 0}, + {"(*AddrError).Temporary", Method, 0}, + {"(*AddrError).Timeout", Method, 0}, + {"(*Buffers).Read", Method, 8}, + {"(*Buffers).WriteTo", Method, 8}, + {"(*DNSConfigError).Error", Method, 0}, + {"(*DNSConfigError).Temporary", Method, 0}, + {"(*DNSConfigError).Timeout", Method, 0}, + {"(*DNSConfigError).Unwrap", Method, 13}, + {"(*DNSError).Error", Method, 0}, + {"(*DNSError).Temporary", Method, 0}, + {"(*DNSError).Timeout", Method, 0}, + {"(*Dialer).Dial", Method, 1}, + {"(*Dialer).DialContext", Method, 7}, + {"(*Dialer).MultipathTCP", Method, 21}, + {"(*Dialer).SetMultipathTCP", Method, 21}, + {"(*IP).UnmarshalText", Method, 2}, + {"(*IPAddr).Network", Method, 0}, + {"(*IPAddr).String", Method, 0}, + {"(*IPConn).Close", Method, 0}, + {"(*IPConn).File", Method, 0}, + {"(*IPConn).LocalAddr", Method, 0}, + {"(*IPConn).Read", Method, 0}, + {"(*IPConn).ReadFrom", Method, 0}, + {"(*IPConn).ReadFromIP", Method, 0}, + {"(*IPConn).ReadMsgIP", Method, 1}, + {"(*IPConn).RemoteAddr", Method, 0}, + {"(*IPConn).SetDeadline", Method, 0}, + {"(*IPConn).SetReadBuffer", Method, 0}, + {"(*IPConn).SetReadDeadline", Method, 0}, + {"(*IPConn).SetWriteBuffer", Method, 0}, + {"(*IPConn).SetWriteDeadline", Method, 0}, + {"(*IPConn).SyscallConn", Method, 9}, + {"(*IPConn).Write", Method, 0}, + {"(*IPConn).WriteMsgIP", Method, 1}, + {"(*IPConn).WriteTo", Method, 0}, + {"(*IPConn).WriteToIP", Method, 0}, + {"(*IPNet).Contains", Method, 0}, + {"(*IPNet).Network", Method, 0}, + {"(*IPNet).String", Method, 0}, + {"(*Interface).Addrs", Method, 0}, + {"(*Interface).MulticastAddrs", Method, 0}, + {"(*ListenConfig).Listen", Method, 11}, + {"(*ListenConfig).ListenPacket", Method, 11}, + {"(*ListenConfig).MultipathTCP", Method, 21}, + {"(*ListenConfig).SetMultipathTCP", Method, 21}, + {"(*OpError).Error", Method, 0}, + {"(*OpError).Temporary", Method, 0}, + {"(*OpError).Timeout", Method, 0}, + {"(*OpError).Unwrap", Method, 13}, + {"(*ParseError).Error", Method, 0}, + {"(*ParseError).Temporary", Method, 17}, + {"(*ParseError).Timeout", Method, 17}, + {"(*Resolver).LookupAddr", Method, 8}, + {"(*Resolver).LookupCNAME", Method, 8}, + {"(*Resolver).LookupHost", Method, 8}, + {"(*Resolver).LookupIP", Method, 15}, + {"(*Resolver).LookupIPAddr", Method, 8}, + {"(*Resolver).LookupMX", Method, 8}, + {"(*Resolver).LookupNS", Method, 8}, + {"(*Resolver).LookupNetIP", Method, 18}, + {"(*Resolver).LookupPort", Method, 8}, + {"(*Resolver).LookupSRV", Method, 8}, + {"(*Resolver).LookupTXT", Method, 8}, + {"(*TCPAddr).AddrPort", Method, 18}, + {"(*TCPAddr).Network", Method, 0}, + {"(*TCPAddr).String", Method, 0}, + {"(*TCPConn).Close", Method, 0}, + {"(*TCPConn).CloseRead", Method, 0}, + {"(*TCPConn).CloseWrite", Method, 0}, + {"(*TCPConn).File", Method, 0}, + {"(*TCPConn).LocalAddr", Method, 0}, + {"(*TCPConn).MultipathTCP", Method, 21}, + {"(*TCPConn).Read", Method, 0}, + {"(*TCPConn).ReadFrom", Method, 0}, + {"(*TCPConn).RemoteAddr", Method, 0}, + {"(*TCPConn).SetDeadline", Method, 0}, + {"(*TCPConn).SetKeepAlive", Method, 0}, + {"(*TCPConn).SetKeepAlivePeriod", Method, 2}, + {"(*TCPConn).SetLinger", Method, 0}, + {"(*TCPConn).SetNoDelay", Method, 0}, + {"(*TCPConn).SetReadBuffer", Method, 0}, + {"(*TCPConn).SetReadDeadline", Method, 0}, + {"(*TCPConn).SetWriteBuffer", Method, 0}, + {"(*TCPConn).SetWriteDeadline", Method, 0}, + {"(*TCPConn).SyscallConn", Method, 9}, + {"(*TCPConn).Write", Method, 0}, + {"(*TCPConn).WriteTo", Method, 22}, + {"(*TCPListener).Accept", Method, 0}, + {"(*TCPListener).AcceptTCP", Method, 0}, + {"(*TCPListener).Addr", Method, 0}, + {"(*TCPListener).Close", Method, 0}, + {"(*TCPListener).File", Method, 0}, + {"(*TCPListener).SetDeadline", Method, 0}, + {"(*TCPListener).SyscallConn", Method, 10}, + {"(*UDPAddr).AddrPort", Method, 18}, + {"(*UDPAddr).Network", Method, 0}, + {"(*UDPAddr).String", Method, 0}, + {"(*UDPConn).Close", Method, 0}, + {"(*UDPConn).File", Method, 0}, + {"(*UDPConn).LocalAddr", Method, 0}, + {"(*UDPConn).Read", Method, 0}, + {"(*UDPConn).ReadFrom", Method, 0}, + {"(*UDPConn).ReadFromUDP", Method, 0}, + {"(*UDPConn).ReadFromUDPAddrPort", Method, 18}, + {"(*UDPConn).ReadMsgUDP", Method, 1}, + {"(*UDPConn).ReadMsgUDPAddrPort", Method, 18}, + {"(*UDPConn).RemoteAddr", Method, 0}, + {"(*UDPConn).SetDeadline", Method, 0}, + {"(*UDPConn).SetReadBuffer", Method, 0}, + {"(*UDPConn).SetReadDeadline", Method, 0}, + {"(*UDPConn).SetWriteBuffer", Method, 0}, + {"(*UDPConn).SetWriteDeadline", Method, 0}, + {"(*UDPConn).SyscallConn", Method, 9}, + {"(*UDPConn).Write", Method, 0}, + {"(*UDPConn).WriteMsgUDP", Method, 1}, + {"(*UDPConn).WriteMsgUDPAddrPort", Method, 18}, + {"(*UDPConn).WriteTo", Method, 0}, + {"(*UDPConn).WriteToUDP", Method, 0}, + {"(*UDPConn).WriteToUDPAddrPort", Method, 18}, + {"(*UnixAddr).Network", Method, 0}, + {"(*UnixAddr).String", Method, 0}, + {"(*UnixConn).Close", Method, 0}, + {"(*UnixConn).CloseRead", Method, 1}, + {"(*UnixConn).CloseWrite", Method, 1}, + {"(*UnixConn).File", Method, 0}, + {"(*UnixConn).LocalAddr", Method, 0}, + {"(*UnixConn).Read", Method, 0}, + {"(*UnixConn).ReadFrom", Method, 0}, + {"(*UnixConn).ReadFromUnix", Method, 0}, + {"(*UnixConn).ReadMsgUnix", Method, 0}, + {"(*UnixConn).RemoteAddr", Method, 0}, + {"(*UnixConn).SetDeadline", Method, 0}, + {"(*UnixConn).SetReadBuffer", Method, 0}, + {"(*UnixConn).SetReadDeadline", Method, 0}, + {"(*UnixConn).SetWriteBuffer", Method, 0}, + {"(*UnixConn).SetWriteDeadline", Method, 0}, + {"(*UnixConn).SyscallConn", Method, 9}, + {"(*UnixConn).Write", Method, 0}, + {"(*UnixConn).WriteMsgUnix", Method, 0}, + {"(*UnixConn).WriteTo", Method, 0}, + {"(*UnixConn).WriteToUnix", Method, 0}, + {"(*UnixListener).Accept", Method, 0}, + {"(*UnixListener).AcceptUnix", Method, 0}, + {"(*UnixListener).Addr", Method, 0}, + {"(*UnixListener).Close", Method, 0}, + {"(*UnixListener).File", Method, 0}, + {"(*UnixListener).SetDeadline", Method, 0}, + {"(*UnixListener).SetUnlinkOnClose", Method, 8}, + {"(*UnixListener).SyscallConn", Method, 10}, + {"(Flags).String", Method, 0}, + {"(HardwareAddr).String", Method, 0}, + {"(IP).DefaultMask", Method, 0}, + {"(IP).Equal", Method, 0}, + {"(IP).IsGlobalUnicast", Method, 0}, + {"(IP).IsInterfaceLocalMulticast", Method, 0}, + {"(IP).IsLinkLocalMulticast", Method, 0}, + {"(IP).IsLinkLocalUnicast", Method, 0}, + {"(IP).IsLoopback", Method, 0}, + {"(IP).IsMulticast", Method, 0}, + {"(IP).IsPrivate", Method, 17}, + {"(IP).IsUnspecified", Method, 0}, + {"(IP).MarshalText", Method, 2}, + {"(IP).Mask", Method, 0}, + {"(IP).String", Method, 0}, + {"(IP).To16", Method, 0}, + {"(IP).To4", Method, 0}, + {"(IPMask).Size", Method, 0}, + {"(IPMask).String", Method, 0}, + {"(InvalidAddrError).Error", Method, 0}, + {"(InvalidAddrError).Temporary", Method, 0}, + {"(InvalidAddrError).Timeout", Method, 0}, + {"(UnknownNetworkError).Error", Method, 0}, + {"(UnknownNetworkError).Temporary", Method, 0}, + {"(UnknownNetworkError).Timeout", Method, 0}, + {"Addr", Type, 0}, + {"AddrError", Type, 0}, + {"AddrError.Addr", Field, 0}, + {"AddrError.Err", Field, 0}, + {"Buffers", Type, 8}, + {"CIDRMask", Func, 0}, + {"Conn", Type, 0}, + {"DNSConfigError", Type, 0}, + {"DNSConfigError.Err", Field, 0}, + {"DNSError", Type, 0}, + {"DNSError.Err", Field, 0}, + {"DNSError.IsNotFound", Field, 13}, + {"DNSError.IsTemporary", Field, 6}, + {"DNSError.IsTimeout", Field, 0}, + {"DNSError.Name", Field, 0}, + {"DNSError.Server", Field, 0}, + {"DefaultResolver", Var, 8}, + {"Dial", Func, 0}, + {"DialIP", Func, 0}, + {"DialTCP", Func, 0}, + {"DialTimeout", Func, 0}, + {"DialUDP", Func, 0}, + {"DialUnix", Func, 0}, + {"Dialer", Type, 1}, + {"Dialer.Cancel", Field, 6}, + {"Dialer.Control", Field, 11}, + {"Dialer.ControlContext", Field, 20}, + {"Dialer.Deadline", Field, 1}, + {"Dialer.DualStack", Field, 2}, + {"Dialer.FallbackDelay", Field, 5}, + {"Dialer.KeepAlive", Field, 3}, + {"Dialer.LocalAddr", Field, 1}, + {"Dialer.Resolver", Field, 8}, + {"Dialer.Timeout", Field, 1}, + {"ErrClosed", Var, 16}, + {"ErrWriteToConnected", Var, 0}, + {"Error", Type, 0}, + {"FileConn", Func, 0}, + {"FileListener", Func, 0}, + {"FilePacketConn", Func, 0}, + {"FlagBroadcast", Const, 0}, + {"FlagLoopback", Const, 0}, + {"FlagMulticast", Const, 0}, + {"FlagPointToPoint", Const, 0}, + {"FlagRunning", Const, 20}, + {"FlagUp", Const, 0}, + {"Flags", Type, 0}, + {"HardwareAddr", Type, 0}, + {"IP", Type, 0}, + {"IPAddr", Type, 0}, + {"IPAddr.IP", Field, 0}, + {"IPAddr.Zone", Field, 1}, + {"IPConn", Type, 0}, + {"IPMask", Type, 0}, + {"IPNet", Type, 0}, + {"IPNet.IP", Field, 0}, + {"IPNet.Mask", Field, 0}, + {"IPv4", Func, 0}, + {"IPv4Mask", Func, 0}, + {"IPv4allrouter", Var, 0}, + {"IPv4allsys", Var, 0}, + {"IPv4bcast", Var, 0}, + {"IPv4len", Const, 0}, + {"IPv4zero", Var, 0}, + {"IPv6interfacelocalallnodes", Var, 0}, + {"IPv6len", Const, 0}, + {"IPv6linklocalallnodes", Var, 0}, + {"IPv6linklocalallrouters", Var, 0}, + {"IPv6loopback", Var, 0}, + {"IPv6unspecified", Var, 0}, + {"IPv6zero", Var, 0}, + {"Interface", Type, 0}, + {"Interface.Flags", Field, 0}, + {"Interface.HardwareAddr", Field, 0}, + {"Interface.Index", Field, 0}, + {"Interface.MTU", Field, 0}, + {"Interface.Name", Field, 0}, + {"InterfaceAddrs", Func, 0}, + {"InterfaceByIndex", Func, 0}, + {"InterfaceByName", Func, 0}, + {"Interfaces", Func, 0}, + {"InvalidAddrError", Type, 0}, + {"JoinHostPort", Func, 0}, + {"Listen", Func, 0}, + {"ListenConfig", Type, 11}, + {"ListenConfig.Control", Field, 11}, + {"ListenConfig.KeepAlive", Field, 13}, + {"ListenIP", Func, 0}, + {"ListenMulticastUDP", Func, 0}, + {"ListenPacket", Func, 0}, + {"ListenTCP", Func, 0}, + {"ListenUDP", Func, 0}, + {"ListenUnix", Func, 0}, + {"ListenUnixgram", Func, 0}, + {"Listener", Type, 0}, + {"LookupAddr", Func, 0}, + {"LookupCNAME", Func, 0}, + {"LookupHost", Func, 0}, + {"LookupIP", Func, 0}, + {"LookupMX", Func, 0}, + {"LookupNS", Func, 1}, + {"LookupPort", Func, 0}, + {"LookupSRV", Func, 0}, + {"LookupTXT", Func, 0}, + {"MX", Type, 0}, + {"MX.Host", Field, 0}, + {"MX.Pref", Field, 0}, + {"NS", Type, 1}, + {"NS.Host", Field, 1}, + {"OpError", Type, 0}, + {"OpError.Addr", Field, 0}, + {"OpError.Err", Field, 0}, + {"OpError.Net", Field, 0}, + {"OpError.Op", Field, 0}, + {"OpError.Source", Field, 5}, + {"PacketConn", Type, 0}, + {"ParseCIDR", Func, 0}, + {"ParseError", Type, 0}, + {"ParseError.Text", Field, 0}, + {"ParseError.Type", Field, 0}, + {"ParseIP", Func, 0}, + {"ParseMAC", Func, 0}, + {"Pipe", Func, 0}, + {"ResolveIPAddr", Func, 0}, + {"ResolveTCPAddr", Func, 0}, + {"ResolveUDPAddr", Func, 0}, + {"ResolveUnixAddr", Func, 0}, + {"Resolver", Type, 8}, + {"Resolver.Dial", Field, 9}, + {"Resolver.PreferGo", Field, 8}, + {"Resolver.StrictErrors", Field, 9}, + {"SRV", Type, 0}, + {"SRV.Port", Field, 0}, + {"SRV.Priority", Field, 0}, + {"SRV.Target", Field, 0}, + {"SRV.Weight", Field, 0}, + {"SplitHostPort", Func, 0}, + {"TCPAddr", Type, 0}, + {"TCPAddr.IP", Field, 0}, + {"TCPAddr.Port", Field, 0}, + {"TCPAddr.Zone", Field, 1}, + {"TCPAddrFromAddrPort", Func, 18}, + {"TCPConn", Type, 0}, + {"TCPListener", Type, 0}, + {"UDPAddr", Type, 0}, + {"UDPAddr.IP", Field, 0}, + {"UDPAddr.Port", Field, 0}, + {"UDPAddr.Zone", Field, 1}, + {"UDPAddrFromAddrPort", Func, 18}, + {"UDPConn", Type, 0}, + {"UnixAddr", Type, 0}, + {"UnixAddr.Name", Field, 0}, + {"UnixAddr.Net", Field, 0}, + {"UnixConn", Type, 0}, + {"UnixListener", Type, 0}, + {"UnknownNetworkError", Type, 0}, + }, + "net/http": { + {"(*Client).CloseIdleConnections", Method, 12}, + {"(*Client).Do", Method, 0}, + {"(*Client).Get", Method, 0}, + {"(*Client).Head", Method, 0}, + {"(*Client).Post", Method, 0}, + {"(*Client).PostForm", Method, 0}, + {"(*Cookie).String", Method, 0}, + {"(*Cookie).Valid", Method, 18}, + {"(*MaxBytesError).Error", Method, 19}, + {"(*ProtocolError).Error", Method, 0}, + {"(*ProtocolError).Is", Method, 21}, + {"(*Request).AddCookie", Method, 0}, + {"(*Request).BasicAuth", Method, 4}, + {"(*Request).Clone", Method, 13}, + {"(*Request).Context", Method, 7}, + {"(*Request).Cookie", Method, 0}, + {"(*Request).Cookies", Method, 0}, + {"(*Request).FormFile", Method, 0}, + {"(*Request).FormValue", Method, 0}, + {"(*Request).MultipartReader", Method, 0}, + {"(*Request).ParseForm", Method, 0}, + {"(*Request).ParseMultipartForm", Method, 0}, + {"(*Request).PathValue", Method, 22}, + {"(*Request).PostFormValue", Method, 1}, + {"(*Request).ProtoAtLeast", Method, 0}, + {"(*Request).Referer", Method, 0}, + {"(*Request).SetBasicAuth", Method, 0}, + {"(*Request).SetPathValue", Method, 22}, + {"(*Request).UserAgent", Method, 0}, + {"(*Request).WithContext", Method, 7}, + {"(*Request).Write", Method, 0}, + {"(*Request).WriteProxy", Method, 0}, + {"(*Response).Cookies", Method, 0}, + {"(*Response).Location", Method, 0}, + {"(*Response).ProtoAtLeast", Method, 0}, + {"(*Response).Write", Method, 0}, + {"(*ResponseController).EnableFullDuplex", Method, 21}, + {"(*ResponseController).Flush", Method, 20}, + {"(*ResponseController).Hijack", Method, 20}, + {"(*ResponseController).SetReadDeadline", Method, 20}, + {"(*ResponseController).SetWriteDeadline", Method, 20}, + {"(*ServeMux).Handle", Method, 0}, + {"(*ServeMux).HandleFunc", Method, 0}, + {"(*ServeMux).Handler", Method, 1}, + {"(*ServeMux).ServeHTTP", Method, 0}, + {"(*Server).Close", Method, 8}, + {"(*Server).ListenAndServe", Method, 0}, + {"(*Server).ListenAndServeTLS", Method, 0}, + {"(*Server).RegisterOnShutdown", Method, 9}, + {"(*Server).Serve", Method, 0}, + {"(*Server).ServeTLS", Method, 9}, + {"(*Server).SetKeepAlivesEnabled", Method, 3}, + {"(*Server).Shutdown", Method, 8}, + {"(*Transport).CancelRequest", Method, 1}, + {"(*Transport).Clone", Method, 13}, + {"(*Transport).CloseIdleConnections", Method, 0}, + {"(*Transport).RegisterProtocol", Method, 0}, + {"(*Transport).RoundTrip", Method, 0}, + {"(ConnState).String", Method, 3}, + {"(Dir).Open", Method, 0}, + {"(HandlerFunc).ServeHTTP", Method, 0}, + {"(Header).Add", Method, 0}, + {"(Header).Clone", Method, 13}, + {"(Header).Del", Method, 0}, + {"(Header).Get", Method, 0}, + {"(Header).Set", Method, 0}, + {"(Header).Values", Method, 14}, + {"(Header).Write", Method, 0}, + {"(Header).WriteSubset", Method, 0}, + {"AllowQuerySemicolons", Func, 17}, + {"CanonicalHeaderKey", Func, 0}, + {"Client", Type, 0}, + {"Client.CheckRedirect", Field, 0}, + {"Client.Jar", Field, 0}, + {"Client.Timeout", Field, 3}, + {"Client.Transport", Field, 0}, + {"CloseNotifier", Type, 1}, + {"ConnState", Type, 3}, + {"Cookie", Type, 0}, + {"Cookie.Domain", Field, 0}, + {"Cookie.Expires", Field, 0}, + {"Cookie.HttpOnly", Field, 0}, + {"Cookie.MaxAge", Field, 0}, + {"Cookie.Name", Field, 0}, + {"Cookie.Path", Field, 0}, + {"Cookie.Raw", Field, 0}, + {"Cookie.RawExpires", Field, 0}, + {"Cookie.SameSite", Field, 11}, + {"Cookie.Secure", Field, 0}, + {"Cookie.Unparsed", Field, 0}, + {"Cookie.Value", Field, 0}, + {"CookieJar", Type, 0}, + {"DefaultClient", Var, 0}, + {"DefaultMaxHeaderBytes", Const, 0}, + {"DefaultMaxIdleConnsPerHost", Const, 0}, + {"DefaultServeMux", Var, 0}, + {"DefaultTransport", Var, 0}, + {"DetectContentType", Func, 0}, + {"Dir", Type, 0}, + {"ErrAbortHandler", Var, 8}, + {"ErrBodyNotAllowed", Var, 0}, + {"ErrBodyReadAfterClose", Var, 0}, + {"ErrContentLength", Var, 0}, + {"ErrHandlerTimeout", Var, 0}, + {"ErrHeaderTooLong", Var, 0}, + {"ErrHijacked", Var, 0}, + {"ErrLineTooLong", Var, 0}, + {"ErrMissingBoundary", Var, 0}, + {"ErrMissingContentLength", Var, 0}, + {"ErrMissingFile", Var, 0}, + {"ErrNoCookie", Var, 0}, + {"ErrNoLocation", Var, 0}, + {"ErrNotMultipart", Var, 0}, + {"ErrNotSupported", Var, 0}, + {"ErrSchemeMismatch", Var, 21}, + {"ErrServerClosed", Var, 8}, + {"ErrShortBody", Var, 0}, + {"ErrSkipAltProtocol", Var, 6}, + {"ErrUnexpectedTrailer", Var, 0}, + {"ErrUseLastResponse", Var, 7}, + {"ErrWriteAfterFlush", Var, 0}, + {"Error", Func, 0}, + {"FS", Func, 16}, + {"File", Type, 0}, + {"FileServer", Func, 0}, + {"FileServerFS", Func, 22}, + {"FileSystem", Type, 0}, + {"Flusher", Type, 0}, + {"Get", Func, 0}, + {"Handle", Func, 0}, + {"HandleFunc", Func, 0}, + {"Handler", Type, 0}, + {"HandlerFunc", Type, 0}, + {"Head", Func, 0}, + {"Header", Type, 0}, + {"Hijacker", Type, 0}, + {"ListenAndServe", Func, 0}, + {"ListenAndServeTLS", Func, 0}, + {"LocalAddrContextKey", Var, 7}, + {"MaxBytesError", Type, 19}, + {"MaxBytesError.Limit", Field, 19}, + {"MaxBytesHandler", Func, 18}, + {"MaxBytesReader", Func, 0}, + {"MethodConnect", Const, 6}, + {"MethodDelete", Const, 6}, + {"MethodGet", Const, 6}, + {"MethodHead", Const, 6}, + {"MethodOptions", Const, 6}, + {"MethodPatch", Const, 6}, + {"MethodPost", Const, 6}, + {"MethodPut", Const, 6}, + {"MethodTrace", Const, 6}, + {"NewFileTransport", Func, 0}, + {"NewFileTransportFS", Func, 22}, + {"NewRequest", Func, 0}, + {"NewRequestWithContext", Func, 13}, + {"NewResponseController", Func, 20}, + {"NewServeMux", Func, 0}, + {"NoBody", Var, 8}, + {"NotFound", Func, 0}, + {"NotFoundHandler", Func, 0}, + {"ParseHTTPVersion", Func, 0}, + {"ParseTime", Func, 1}, + {"Post", Func, 0}, + {"PostForm", Func, 0}, + {"ProtocolError", Type, 0}, + {"ProtocolError.ErrorString", Field, 0}, + {"ProxyFromEnvironment", Func, 0}, + {"ProxyURL", Func, 0}, + {"PushOptions", Type, 8}, + {"PushOptions.Header", Field, 8}, + {"PushOptions.Method", Field, 8}, + {"Pusher", Type, 8}, + {"ReadRequest", Func, 0}, + {"ReadResponse", Func, 0}, + {"Redirect", Func, 0}, + {"RedirectHandler", Func, 0}, + {"Request", Type, 0}, + {"Request.Body", Field, 0}, + {"Request.Cancel", Field, 5}, + {"Request.Close", Field, 0}, + {"Request.ContentLength", Field, 0}, + {"Request.Form", Field, 0}, + {"Request.GetBody", Field, 8}, + {"Request.Header", Field, 0}, + {"Request.Host", Field, 0}, + {"Request.Method", Field, 0}, + {"Request.MultipartForm", Field, 0}, + {"Request.PostForm", Field, 1}, + {"Request.Proto", Field, 0}, + {"Request.ProtoMajor", Field, 0}, + {"Request.ProtoMinor", Field, 0}, + {"Request.RemoteAddr", Field, 0}, + {"Request.RequestURI", Field, 0}, + {"Request.Response", Field, 7}, + {"Request.TLS", Field, 0}, + {"Request.Trailer", Field, 0}, + {"Request.TransferEncoding", Field, 0}, + {"Request.URL", Field, 0}, + {"Response", Type, 0}, + {"Response.Body", Field, 0}, + {"Response.Close", Field, 0}, + {"Response.ContentLength", Field, 0}, + {"Response.Header", Field, 0}, + {"Response.Proto", Field, 0}, + {"Response.ProtoMajor", Field, 0}, + {"Response.ProtoMinor", Field, 0}, + {"Response.Request", Field, 0}, + {"Response.Status", Field, 0}, + {"Response.StatusCode", Field, 0}, + {"Response.TLS", Field, 3}, + {"Response.Trailer", Field, 0}, + {"Response.TransferEncoding", Field, 0}, + {"Response.Uncompressed", Field, 7}, + {"ResponseController", Type, 20}, + {"ResponseWriter", Type, 0}, + {"RoundTripper", Type, 0}, + {"SameSite", Type, 11}, + {"SameSiteDefaultMode", Const, 11}, + {"SameSiteLaxMode", Const, 11}, + {"SameSiteNoneMode", Const, 13}, + {"SameSiteStrictMode", Const, 11}, + {"Serve", Func, 0}, + {"ServeContent", Func, 0}, + {"ServeFile", Func, 0}, + {"ServeFileFS", Func, 22}, + {"ServeMux", Type, 0}, + {"ServeTLS", Func, 9}, + {"Server", Type, 0}, + {"Server.Addr", Field, 0}, + {"Server.BaseContext", Field, 13}, + {"Server.ConnContext", Field, 13}, + {"Server.ConnState", Field, 3}, + {"Server.DisableGeneralOptionsHandler", Field, 20}, + {"Server.ErrorLog", Field, 3}, + {"Server.Handler", Field, 0}, + {"Server.IdleTimeout", Field, 8}, + {"Server.MaxHeaderBytes", Field, 0}, + {"Server.ReadHeaderTimeout", Field, 8}, + {"Server.ReadTimeout", Field, 0}, + {"Server.TLSConfig", Field, 0}, + {"Server.TLSNextProto", Field, 1}, + {"Server.WriteTimeout", Field, 0}, + {"ServerContextKey", Var, 7}, + {"SetCookie", Func, 0}, + {"StateActive", Const, 3}, + {"StateClosed", Const, 3}, + {"StateHijacked", Const, 3}, + {"StateIdle", Const, 3}, + {"StateNew", Const, 3}, + {"StatusAccepted", Const, 0}, + {"StatusAlreadyReported", Const, 7}, + {"StatusBadGateway", Const, 0}, + {"StatusBadRequest", Const, 0}, + {"StatusConflict", Const, 0}, + {"StatusContinue", Const, 0}, + {"StatusCreated", Const, 0}, + {"StatusEarlyHints", Const, 13}, + {"StatusExpectationFailed", Const, 0}, + {"StatusFailedDependency", Const, 7}, + {"StatusForbidden", Const, 0}, + {"StatusFound", Const, 0}, + {"StatusGatewayTimeout", Const, 0}, + {"StatusGone", Const, 0}, + {"StatusHTTPVersionNotSupported", Const, 0}, + {"StatusIMUsed", Const, 7}, + {"StatusInsufficientStorage", Const, 7}, + {"StatusInternalServerError", Const, 0}, + {"StatusLengthRequired", Const, 0}, + {"StatusLocked", Const, 7}, + {"StatusLoopDetected", Const, 7}, + {"StatusMethodNotAllowed", Const, 0}, + {"StatusMisdirectedRequest", Const, 11}, + {"StatusMovedPermanently", Const, 0}, + {"StatusMultiStatus", Const, 7}, + {"StatusMultipleChoices", Const, 0}, + {"StatusNetworkAuthenticationRequired", Const, 6}, + {"StatusNoContent", Const, 0}, + {"StatusNonAuthoritativeInfo", Const, 0}, + {"StatusNotAcceptable", Const, 0}, + {"StatusNotExtended", Const, 7}, + {"StatusNotFound", Const, 0}, + {"StatusNotImplemented", Const, 0}, + {"StatusNotModified", Const, 0}, + {"StatusOK", Const, 0}, + {"StatusPartialContent", Const, 0}, + {"StatusPaymentRequired", Const, 0}, + {"StatusPermanentRedirect", Const, 7}, + {"StatusPreconditionFailed", Const, 0}, + {"StatusPreconditionRequired", Const, 6}, + {"StatusProcessing", Const, 7}, + {"StatusProxyAuthRequired", Const, 0}, + {"StatusRequestEntityTooLarge", Const, 0}, + {"StatusRequestHeaderFieldsTooLarge", Const, 6}, + {"StatusRequestTimeout", Const, 0}, + {"StatusRequestURITooLong", Const, 0}, + {"StatusRequestedRangeNotSatisfiable", Const, 0}, + {"StatusResetContent", Const, 0}, + {"StatusSeeOther", Const, 0}, + {"StatusServiceUnavailable", Const, 0}, + {"StatusSwitchingProtocols", Const, 0}, + {"StatusTeapot", Const, 0}, + {"StatusTemporaryRedirect", Const, 0}, + {"StatusText", Func, 0}, + {"StatusTooEarly", Const, 12}, + {"StatusTooManyRequests", Const, 6}, + {"StatusUnauthorized", Const, 0}, + {"StatusUnavailableForLegalReasons", Const, 6}, + {"StatusUnprocessableEntity", Const, 7}, + {"StatusUnsupportedMediaType", Const, 0}, + {"StatusUpgradeRequired", Const, 7}, + {"StatusUseProxy", Const, 0}, + {"StatusVariantAlsoNegotiates", Const, 7}, + {"StripPrefix", Func, 0}, + {"TimeFormat", Const, 0}, + {"TimeoutHandler", Func, 0}, + {"TrailerPrefix", Const, 8}, + {"Transport", Type, 0}, + {"Transport.Dial", Field, 0}, + {"Transport.DialContext", Field, 7}, + {"Transport.DialTLS", Field, 4}, + {"Transport.DialTLSContext", Field, 14}, + {"Transport.DisableCompression", Field, 0}, + {"Transport.DisableKeepAlives", Field, 0}, + {"Transport.ExpectContinueTimeout", Field, 6}, + {"Transport.ForceAttemptHTTP2", Field, 13}, + {"Transport.GetProxyConnectHeader", Field, 16}, + {"Transport.IdleConnTimeout", Field, 7}, + {"Transport.MaxConnsPerHost", Field, 11}, + {"Transport.MaxIdleConns", Field, 7}, + {"Transport.MaxIdleConnsPerHost", Field, 0}, + {"Transport.MaxResponseHeaderBytes", Field, 7}, + {"Transport.OnProxyConnectResponse", Field, 20}, + {"Transport.Proxy", Field, 0}, + {"Transport.ProxyConnectHeader", Field, 8}, + {"Transport.ReadBufferSize", Field, 13}, + {"Transport.ResponseHeaderTimeout", Field, 1}, + {"Transport.TLSClientConfig", Field, 0}, + {"Transport.TLSHandshakeTimeout", Field, 3}, + {"Transport.TLSNextProto", Field, 6}, + {"Transport.WriteBufferSize", Field, 13}, + }, + "net/http/cgi": { + {"(*Handler).ServeHTTP", Method, 0}, + {"Handler", Type, 0}, + {"Handler.Args", Field, 0}, + {"Handler.Dir", Field, 0}, + {"Handler.Env", Field, 0}, + {"Handler.InheritEnv", Field, 0}, + {"Handler.Logger", Field, 0}, + {"Handler.Path", Field, 0}, + {"Handler.PathLocationHandler", Field, 0}, + {"Handler.Root", Field, 0}, + {"Handler.Stderr", Field, 7}, + {"Request", Func, 0}, + {"RequestFromMap", Func, 0}, + {"Serve", Func, 0}, + }, + "net/http/cookiejar": { + {"(*Jar).Cookies", Method, 1}, + {"(*Jar).SetCookies", Method, 1}, + {"Jar", Type, 1}, + {"New", Func, 1}, + {"Options", Type, 1}, + {"Options.PublicSuffixList", Field, 1}, + {"PublicSuffixList", Type, 1}, + }, + "net/http/fcgi": { + {"ErrConnClosed", Var, 5}, + {"ErrRequestAborted", Var, 5}, + {"ProcessEnv", Func, 9}, + {"Serve", Func, 0}, + }, + "net/http/httptest": { + {"(*ResponseRecorder).Flush", Method, 0}, + {"(*ResponseRecorder).Header", Method, 0}, + {"(*ResponseRecorder).Result", Method, 7}, + {"(*ResponseRecorder).Write", Method, 0}, + {"(*ResponseRecorder).WriteHeader", Method, 0}, + {"(*ResponseRecorder).WriteString", Method, 6}, + {"(*Server).Certificate", Method, 9}, + {"(*Server).Client", Method, 9}, + {"(*Server).Close", Method, 0}, + {"(*Server).CloseClientConnections", Method, 0}, + {"(*Server).Start", Method, 0}, + {"(*Server).StartTLS", Method, 0}, + {"DefaultRemoteAddr", Const, 0}, + {"NewRecorder", Func, 0}, + {"NewRequest", Func, 7}, + {"NewServer", Func, 0}, + {"NewTLSServer", Func, 0}, + {"NewUnstartedServer", Func, 0}, + {"ResponseRecorder", Type, 0}, + {"ResponseRecorder.Body", Field, 0}, + {"ResponseRecorder.Code", Field, 0}, + {"ResponseRecorder.Flushed", Field, 0}, + {"ResponseRecorder.HeaderMap", Field, 0}, + {"Server", Type, 0}, + {"Server.Config", Field, 0}, + {"Server.EnableHTTP2", Field, 14}, + {"Server.Listener", Field, 0}, + {"Server.TLS", Field, 0}, + {"Server.URL", Field, 0}, + }, + "net/http/httptrace": { + {"ClientTrace", Type, 7}, + {"ClientTrace.ConnectDone", Field, 7}, + {"ClientTrace.ConnectStart", Field, 7}, + {"ClientTrace.DNSDone", Field, 7}, + {"ClientTrace.DNSStart", Field, 7}, + {"ClientTrace.GetConn", Field, 7}, + {"ClientTrace.Got100Continue", Field, 7}, + {"ClientTrace.Got1xxResponse", Field, 11}, + {"ClientTrace.GotConn", Field, 7}, + {"ClientTrace.GotFirstResponseByte", Field, 7}, + {"ClientTrace.PutIdleConn", Field, 7}, + {"ClientTrace.TLSHandshakeDone", Field, 8}, + {"ClientTrace.TLSHandshakeStart", Field, 8}, + {"ClientTrace.Wait100Continue", Field, 7}, + {"ClientTrace.WroteHeaderField", Field, 11}, + {"ClientTrace.WroteHeaders", Field, 7}, + {"ClientTrace.WroteRequest", Field, 7}, + {"ContextClientTrace", Func, 7}, + {"DNSDoneInfo", Type, 7}, + {"DNSDoneInfo.Addrs", Field, 7}, + {"DNSDoneInfo.Coalesced", Field, 7}, + {"DNSDoneInfo.Err", Field, 7}, + {"DNSStartInfo", Type, 7}, + {"DNSStartInfo.Host", Field, 7}, + {"GotConnInfo", Type, 7}, + {"GotConnInfo.Conn", Field, 7}, + {"GotConnInfo.IdleTime", Field, 7}, + {"GotConnInfo.Reused", Field, 7}, + {"GotConnInfo.WasIdle", Field, 7}, + {"WithClientTrace", Func, 7}, + {"WroteRequestInfo", Type, 7}, + {"WroteRequestInfo.Err", Field, 7}, + }, + "net/http/httputil": { + {"(*ClientConn).Close", Method, 0}, + {"(*ClientConn).Do", Method, 0}, + {"(*ClientConn).Hijack", Method, 0}, + {"(*ClientConn).Pending", Method, 0}, + {"(*ClientConn).Read", Method, 0}, + {"(*ClientConn).Write", Method, 0}, + {"(*ProxyRequest).SetURL", Method, 20}, + {"(*ProxyRequest).SetXForwarded", Method, 20}, + {"(*ReverseProxy).ServeHTTP", Method, 0}, + {"(*ServerConn).Close", Method, 0}, + {"(*ServerConn).Hijack", Method, 0}, + {"(*ServerConn).Pending", Method, 0}, + {"(*ServerConn).Read", Method, 0}, + {"(*ServerConn).Write", Method, 0}, + {"BufferPool", Type, 6}, + {"ClientConn", Type, 0}, + {"DumpRequest", Func, 0}, + {"DumpRequestOut", Func, 0}, + {"DumpResponse", Func, 0}, + {"ErrClosed", Var, 0}, + {"ErrLineTooLong", Var, 0}, + {"ErrPersistEOF", Var, 0}, + {"ErrPipeline", Var, 0}, + {"NewChunkedReader", Func, 0}, + {"NewChunkedWriter", Func, 0}, + {"NewClientConn", Func, 0}, + {"NewProxyClientConn", Func, 0}, + {"NewServerConn", Func, 0}, + {"NewSingleHostReverseProxy", Func, 0}, + {"ProxyRequest", Type, 20}, + {"ProxyRequest.In", Field, 20}, + {"ProxyRequest.Out", Field, 20}, + {"ReverseProxy", Type, 0}, + {"ReverseProxy.BufferPool", Field, 6}, + {"ReverseProxy.Director", Field, 0}, + {"ReverseProxy.ErrorHandler", Field, 11}, + {"ReverseProxy.ErrorLog", Field, 4}, + {"ReverseProxy.FlushInterval", Field, 0}, + {"ReverseProxy.ModifyResponse", Field, 8}, + {"ReverseProxy.Rewrite", Field, 20}, + {"ReverseProxy.Transport", Field, 0}, + {"ServerConn", Type, 0}, + }, + "net/http/pprof": { + {"Cmdline", Func, 0}, + {"Handler", Func, 0}, + {"Index", Func, 0}, + {"Profile", Func, 0}, + {"Symbol", Func, 0}, + {"Trace", Func, 5}, + }, + "net/mail": { + {"(*Address).String", Method, 0}, + {"(*AddressParser).Parse", Method, 5}, + {"(*AddressParser).ParseList", Method, 5}, + {"(Header).AddressList", Method, 0}, + {"(Header).Date", Method, 0}, + {"(Header).Get", Method, 0}, + {"Address", Type, 0}, + {"Address.Address", Field, 0}, + {"Address.Name", Field, 0}, + {"AddressParser", Type, 5}, + {"AddressParser.WordDecoder", Field, 5}, + {"ErrHeaderNotPresent", Var, 0}, + {"Header", Type, 0}, + {"Message", Type, 0}, + {"Message.Body", Field, 0}, + {"Message.Header", Field, 0}, + {"ParseAddress", Func, 1}, + {"ParseAddressList", Func, 1}, + {"ParseDate", Func, 8}, + {"ReadMessage", Func, 0}, + }, + "net/netip": { + {"(*Addr).UnmarshalBinary", Method, 18}, + {"(*Addr).UnmarshalText", Method, 18}, + {"(*AddrPort).UnmarshalBinary", Method, 18}, + {"(*AddrPort).UnmarshalText", Method, 18}, + {"(*Prefix).UnmarshalBinary", Method, 18}, + {"(*Prefix).UnmarshalText", Method, 18}, + {"(Addr).AppendTo", Method, 18}, + {"(Addr).As16", Method, 18}, + {"(Addr).As4", Method, 18}, + {"(Addr).AsSlice", Method, 18}, + {"(Addr).BitLen", Method, 18}, + {"(Addr).Compare", Method, 18}, + {"(Addr).Is4", Method, 18}, + {"(Addr).Is4In6", Method, 18}, + {"(Addr).Is6", Method, 18}, + {"(Addr).IsGlobalUnicast", Method, 18}, + {"(Addr).IsInterfaceLocalMulticast", Method, 18}, + {"(Addr).IsLinkLocalMulticast", Method, 18}, + {"(Addr).IsLinkLocalUnicast", Method, 18}, + {"(Addr).IsLoopback", Method, 18}, + {"(Addr).IsMulticast", Method, 18}, + {"(Addr).IsPrivate", Method, 18}, + {"(Addr).IsUnspecified", Method, 18}, + {"(Addr).IsValid", Method, 18}, + {"(Addr).Less", Method, 18}, + {"(Addr).MarshalBinary", Method, 18}, + {"(Addr).MarshalText", Method, 18}, + {"(Addr).Next", Method, 18}, + {"(Addr).Prefix", Method, 18}, + {"(Addr).Prev", Method, 18}, + {"(Addr).String", Method, 18}, + {"(Addr).StringExpanded", Method, 18}, + {"(Addr).Unmap", Method, 18}, + {"(Addr).WithZone", Method, 18}, + {"(Addr).Zone", Method, 18}, + {"(AddrPort).Addr", Method, 18}, + {"(AddrPort).AppendTo", Method, 18}, + {"(AddrPort).Compare", Method, 22}, + {"(AddrPort).IsValid", Method, 18}, + {"(AddrPort).MarshalBinary", Method, 18}, + {"(AddrPort).MarshalText", Method, 18}, + {"(AddrPort).Port", Method, 18}, + {"(AddrPort).String", Method, 18}, + {"(Prefix).Addr", Method, 18}, + {"(Prefix).AppendTo", Method, 18}, + {"(Prefix).Bits", Method, 18}, + {"(Prefix).Contains", Method, 18}, + {"(Prefix).IsSingleIP", Method, 18}, + {"(Prefix).IsValid", Method, 18}, + {"(Prefix).MarshalBinary", Method, 18}, + {"(Prefix).MarshalText", Method, 18}, + {"(Prefix).Masked", Method, 18}, + {"(Prefix).Overlaps", Method, 18}, + {"(Prefix).String", Method, 18}, + {"Addr", Type, 18}, + {"AddrFrom16", Func, 18}, + {"AddrFrom4", Func, 18}, + {"AddrFromSlice", Func, 18}, + {"AddrPort", Type, 18}, + {"AddrPortFrom", Func, 18}, + {"IPv4Unspecified", Func, 18}, + {"IPv6LinkLocalAllNodes", Func, 18}, + {"IPv6LinkLocalAllRouters", Func, 20}, + {"IPv6Loopback", Func, 20}, + {"IPv6Unspecified", Func, 18}, + {"MustParseAddr", Func, 18}, + {"MustParseAddrPort", Func, 18}, + {"MustParsePrefix", Func, 18}, + {"ParseAddr", Func, 18}, + {"ParseAddrPort", Func, 18}, + {"ParsePrefix", Func, 18}, + {"Prefix", Type, 18}, + {"PrefixFrom", Func, 18}, + }, + "net/rpc": { + {"(*Client).Call", Method, 0}, + {"(*Client).Close", Method, 0}, + {"(*Client).Go", Method, 0}, + {"(*Server).Accept", Method, 0}, + {"(*Server).HandleHTTP", Method, 0}, + {"(*Server).Register", Method, 0}, + {"(*Server).RegisterName", Method, 0}, + {"(*Server).ServeCodec", Method, 0}, + {"(*Server).ServeConn", Method, 0}, + {"(*Server).ServeHTTP", Method, 0}, + {"(*Server).ServeRequest", Method, 0}, + {"(ServerError).Error", Method, 0}, + {"Accept", Func, 0}, + {"Call", Type, 0}, + {"Call.Args", Field, 0}, + {"Call.Done", Field, 0}, + {"Call.Error", Field, 0}, + {"Call.Reply", Field, 0}, + {"Call.ServiceMethod", Field, 0}, + {"Client", Type, 0}, + {"ClientCodec", Type, 0}, + {"DefaultDebugPath", Const, 0}, + {"DefaultRPCPath", Const, 0}, + {"DefaultServer", Var, 0}, + {"Dial", Func, 0}, + {"DialHTTP", Func, 0}, + {"DialHTTPPath", Func, 0}, + {"ErrShutdown", Var, 0}, + {"HandleHTTP", Func, 0}, + {"NewClient", Func, 0}, + {"NewClientWithCodec", Func, 0}, + {"NewServer", Func, 0}, + {"Register", Func, 0}, + {"RegisterName", Func, 0}, + {"Request", Type, 0}, + {"Request.Seq", Field, 0}, + {"Request.ServiceMethod", Field, 0}, + {"Response", Type, 0}, + {"Response.Error", Field, 0}, + {"Response.Seq", Field, 0}, + {"Response.ServiceMethod", Field, 0}, + {"ServeCodec", Func, 0}, + {"ServeConn", Func, 0}, + {"ServeRequest", Func, 0}, + {"Server", Type, 0}, + {"ServerCodec", Type, 0}, + {"ServerError", Type, 0}, + }, + "net/rpc/jsonrpc": { + {"Dial", Func, 0}, + {"NewClient", Func, 0}, + {"NewClientCodec", Func, 0}, + {"NewServerCodec", Func, 0}, + {"ServeConn", Func, 0}, + }, + "net/smtp": { + {"(*Client).Auth", Method, 0}, + {"(*Client).Close", Method, 2}, + {"(*Client).Data", Method, 0}, + {"(*Client).Extension", Method, 0}, + {"(*Client).Hello", Method, 1}, + {"(*Client).Mail", Method, 0}, + {"(*Client).Noop", Method, 10}, + {"(*Client).Quit", Method, 0}, + {"(*Client).Rcpt", Method, 0}, + {"(*Client).Reset", Method, 0}, + {"(*Client).StartTLS", Method, 0}, + {"(*Client).TLSConnectionState", Method, 5}, + {"(*Client).Verify", Method, 0}, + {"Auth", Type, 0}, + {"CRAMMD5Auth", Func, 0}, + {"Client", Type, 0}, + {"Client.Text", Field, 0}, + {"Dial", Func, 0}, + {"NewClient", Func, 0}, + {"PlainAuth", Func, 0}, + {"SendMail", Func, 0}, + {"ServerInfo", Type, 0}, + {"ServerInfo.Auth", Field, 0}, + {"ServerInfo.Name", Field, 0}, + {"ServerInfo.TLS", Field, 0}, + }, + "net/textproto": { + {"(*Conn).Close", Method, 0}, + {"(*Conn).Cmd", Method, 0}, + {"(*Conn).DotReader", Method, 0}, + {"(*Conn).DotWriter", Method, 0}, + {"(*Conn).EndRequest", Method, 0}, + {"(*Conn).EndResponse", Method, 0}, + {"(*Conn).Next", Method, 0}, + {"(*Conn).PrintfLine", Method, 0}, + {"(*Conn).ReadCodeLine", Method, 0}, + {"(*Conn).ReadContinuedLine", Method, 0}, + {"(*Conn).ReadContinuedLineBytes", Method, 0}, + {"(*Conn).ReadDotBytes", Method, 0}, + {"(*Conn).ReadDotLines", Method, 0}, + {"(*Conn).ReadLine", Method, 0}, + {"(*Conn).ReadLineBytes", Method, 0}, + {"(*Conn).ReadMIMEHeader", Method, 0}, + {"(*Conn).ReadResponse", Method, 0}, + {"(*Conn).StartRequest", Method, 0}, + {"(*Conn).StartResponse", Method, 0}, + {"(*Error).Error", Method, 0}, + {"(*Pipeline).EndRequest", Method, 0}, + {"(*Pipeline).EndResponse", Method, 0}, + {"(*Pipeline).Next", Method, 0}, + {"(*Pipeline).StartRequest", Method, 0}, + {"(*Pipeline).StartResponse", Method, 0}, + {"(*Reader).DotReader", Method, 0}, + {"(*Reader).ReadCodeLine", Method, 0}, + {"(*Reader).ReadContinuedLine", Method, 0}, + {"(*Reader).ReadContinuedLineBytes", Method, 0}, + {"(*Reader).ReadDotBytes", Method, 0}, + {"(*Reader).ReadDotLines", Method, 0}, + {"(*Reader).ReadLine", Method, 0}, + {"(*Reader).ReadLineBytes", Method, 0}, + {"(*Reader).ReadMIMEHeader", Method, 0}, + {"(*Reader).ReadResponse", Method, 0}, + {"(*Writer).DotWriter", Method, 0}, + {"(*Writer).PrintfLine", Method, 0}, + {"(MIMEHeader).Add", Method, 0}, + {"(MIMEHeader).Del", Method, 0}, + {"(MIMEHeader).Get", Method, 0}, + {"(MIMEHeader).Set", Method, 0}, + {"(MIMEHeader).Values", Method, 14}, + {"(ProtocolError).Error", Method, 0}, + {"CanonicalMIMEHeaderKey", Func, 0}, + {"Conn", Type, 0}, + {"Conn.Pipeline", Field, 0}, + {"Conn.Reader", Field, 0}, + {"Conn.Writer", Field, 0}, + {"Dial", Func, 0}, + {"Error", Type, 0}, + {"Error.Code", Field, 0}, + {"Error.Msg", Field, 0}, + {"MIMEHeader", Type, 0}, + {"NewConn", Func, 0}, + {"NewReader", Func, 0}, + {"NewWriter", Func, 0}, + {"Pipeline", Type, 0}, + {"ProtocolError", Type, 0}, + {"Reader", Type, 0}, + {"Reader.R", Field, 0}, + {"TrimBytes", Func, 1}, + {"TrimString", Func, 1}, + {"Writer", Type, 0}, + {"Writer.W", Field, 0}, + }, + "net/url": { + {"(*Error).Error", Method, 0}, + {"(*Error).Temporary", Method, 6}, + {"(*Error).Timeout", Method, 6}, + {"(*Error).Unwrap", Method, 13}, + {"(*URL).EscapedFragment", Method, 15}, + {"(*URL).EscapedPath", Method, 5}, + {"(*URL).Hostname", Method, 8}, + {"(*URL).IsAbs", Method, 0}, + {"(*URL).JoinPath", Method, 19}, + {"(*URL).MarshalBinary", Method, 8}, + {"(*URL).Parse", Method, 0}, + {"(*URL).Port", Method, 8}, + {"(*URL).Query", Method, 0}, + {"(*URL).Redacted", Method, 15}, + {"(*URL).RequestURI", Method, 0}, + {"(*URL).ResolveReference", Method, 0}, + {"(*URL).String", Method, 0}, + {"(*URL).UnmarshalBinary", Method, 8}, + {"(*Userinfo).Password", Method, 0}, + {"(*Userinfo).String", Method, 0}, + {"(*Userinfo).Username", Method, 0}, + {"(EscapeError).Error", Method, 0}, + {"(InvalidHostError).Error", Method, 6}, + {"(Values).Add", Method, 0}, + {"(Values).Del", Method, 0}, + {"(Values).Encode", Method, 0}, + {"(Values).Get", Method, 0}, + {"(Values).Has", Method, 17}, + {"(Values).Set", Method, 0}, + {"Error", Type, 0}, + {"Error.Err", Field, 0}, + {"Error.Op", Field, 0}, + {"Error.URL", Field, 0}, + {"EscapeError", Type, 0}, + {"InvalidHostError", Type, 6}, + {"JoinPath", Func, 19}, + {"Parse", Func, 0}, + {"ParseQuery", Func, 0}, + {"ParseRequestURI", Func, 0}, + {"PathEscape", Func, 8}, + {"PathUnescape", Func, 8}, + {"QueryEscape", Func, 0}, + {"QueryUnescape", Func, 0}, + {"URL", Type, 0}, + {"URL.ForceQuery", Field, 7}, + {"URL.Fragment", Field, 0}, + {"URL.Host", Field, 0}, + {"URL.OmitHost", Field, 19}, + {"URL.Opaque", Field, 0}, + {"URL.Path", Field, 0}, + {"URL.RawFragment", Field, 15}, + {"URL.RawPath", Field, 5}, + {"URL.RawQuery", Field, 0}, + {"URL.Scheme", Field, 0}, + {"URL.User", Field, 0}, + {"User", Func, 0}, + {"UserPassword", Func, 0}, + {"Userinfo", Type, 0}, + {"Values", Type, 0}, + }, + "os": { + {"(*File).Chdir", Method, 0}, + {"(*File).Chmod", Method, 0}, + {"(*File).Chown", Method, 0}, + {"(*File).Close", Method, 0}, + {"(*File).Fd", Method, 0}, + {"(*File).Name", Method, 0}, + {"(*File).Read", Method, 0}, + {"(*File).ReadAt", Method, 0}, + {"(*File).ReadDir", Method, 16}, + {"(*File).ReadFrom", Method, 15}, + {"(*File).Readdir", Method, 0}, + {"(*File).Readdirnames", Method, 0}, + {"(*File).Seek", Method, 0}, + {"(*File).SetDeadline", Method, 10}, + {"(*File).SetReadDeadline", Method, 10}, + {"(*File).SetWriteDeadline", Method, 10}, + {"(*File).Stat", Method, 0}, + {"(*File).Sync", Method, 0}, + {"(*File).SyscallConn", Method, 12}, + {"(*File).Truncate", Method, 0}, + {"(*File).Write", Method, 0}, + {"(*File).WriteAt", Method, 0}, + {"(*File).WriteString", Method, 0}, + {"(*File).WriteTo", Method, 22}, + {"(*LinkError).Error", Method, 0}, + {"(*LinkError).Unwrap", Method, 13}, + {"(*PathError).Error", Method, 0}, + {"(*PathError).Timeout", Method, 10}, + {"(*PathError).Unwrap", Method, 13}, + {"(*Process).Kill", Method, 0}, + {"(*Process).Release", Method, 0}, + {"(*Process).Signal", Method, 0}, + {"(*Process).Wait", Method, 0}, + {"(*ProcessState).ExitCode", Method, 12}, + {"(*ProcessState).Exited", Method, 0}, + {"(*ProcessState).Pid", Method, 0}, + {"(*ProcessState).String", Method, 0}, + {"(*ProcessState).Success", Method, 0}, + {"(*ProcessState).Sys", Method, 0}, + {"(*ProcessState).SysUsage", Method, 0}, + {"(*ProcessState).SystemTime", Method, 0}, + {"(*ProcessState).UserTime", Method, 0}, + {"(*SyscallError).Error", Method, 0}, + {"(*SyscallError).Timeout", Method, 10}, + {"(*SyscallError).Unwrap", Method, 13}, + {"(FileMode).IsDir", Method, 0}, + {"(FileMode).IsRegular", Method, 1}, + {"(FileMode).Perm", Method, 0}, + {"(FileMode).String", Method, 0}, + {"Args", Var, 0}, + {"Chdir", Func, 0}, + {"Chmod", Func, 0}, + {"Chown", Func, 0}, + {"Chtimes", Func, 0}, + {"Clearenv", Func, 0}, + {"Create", Func, 0}, + {"CreateTemp", Func, 16}, + {"DevNull", Const, 0}, + {"DirEntry", Type, 16}, + {"DirFS", Func, 16}, + {"Environ", Func, 0}, + {"ErrClosed", Var, 8}, + {"ErrDeadlineExceeded", Var, 15}, + {"ErrExist", Var, 0}, + {"ErrInvalid", Var, 0}, + {"ErrNoDeadline", Var, 10}, + {"ErrNotExist", Var, 0}, + {"ErrPermission", Var, 0}, + {"ErrProcessDone", Var, 16}, + {"Executable", Func, 8}, + {"Exit", Func, 0}, + {"Expand", Func, 0}, + {"ExpandEnv", Func, 0}, + {"File", Type, 0}, + {"FileInfo", Type, 0}, + {"FileMode", Type, 0}, + {"FindProcess", Func, 0}, + {"Getegid", Func, 0}, + {"Getenv", Func, 0}, + {"Geteuid", Func, 0}, + {"Getgid", Func, 0}, + {"Getgroups", Func, 0}, + {"Getpagesize", Func, 0}, + {"Getpid", Func, 0}, + {"Getppid", Func, 0}, + {"Getuid", Func, 0}, + {"Getwd", Func, 0}, + {"Hostname", Func, 0}, + {"Interrupt", Var, 0}, + {"IsExist", Func, 0}, + {"IsNotExist", Func, 0}, + {"IsPathSeparator", Func, 0}, + {"IsPermission", Func, 0}, + {"IsTimeout", Func, 10}, + {"Kill", Var, 0}, + {"Lchown", Func, 0}, + {"Link", Func, 0}, + {"LinkError", Type, 0}, + {"LinkError.Err", Field, 0}, + {"LinkError.New", Field, 0}, + {"LinkError.Old", Field, 0}, + {"LinkError.Op", Field, 0}, + {"LookupEnv", Func, 5}, + {"Lstat", Func, 0}, + {"Mkdir", Func, 0}, + {"MkdirAll", Func, 0}, + {"MkdirTemp", Func, 16}, + {"ModeAppend", Const, 0}, + {"ModeCharDevice", Const, 0}, + {"ModeDevice", Const, 0}, + {"ModeDir", Const, 0}, + {"ModeExclusive", Const, 0}, + {"ModeIrregular", Const, 11}, + {"ModeNamedPipe", Const, 0}, + {"ModePerm", Const, 0}, + {"ModeSetgid", Const, 0}, + {"ModeSetuid", Const, 0}, + {"ModeSocket", Const, 0}, + {"ModeSticky", Const, 0}, + {"ModeSymlink", Const, 0}, + {"ModeTemporary", Const, 0}, + {"ModeType", Const, 0}, + {"NewFile", Func, 0}, + {"NewSyscallError", Func, 0}, + {"O_APPEND", Const, 0}, + {"O_CREATE", Const, 0}, + {"O_EXCL", Const, 0}, + {"O_RDONLY", Const, 0}, + {"O_RDWR", Const, 0}, + {"O_SYNC", Const, 0}, + {"O_TRUNC", Const, 0}, + {"O_WRONLY", Const, 0}, + {"Open", Func, 0}, + {"OpenFile", Func, 0}, + {"PathError", Type, 0}, + {"PathError.Err", Field, 0}, + {"PathError.Op", Field, 0}, + {"PathError.Path", Field, 0}, + {"PathListSeparator", Const, 0}, + {"PathSeparator", Const, 0}, + {"Pipe", Func, 0}, + {"ProcAttr", Type, 0}, + {"ProcAttr.Dir", Field, 0}, + {"ProcAttr.Env", Field, 0}, + {"ProcAttr.Files", Field, 0}, + {"ProcAttr.Sys", Field, 0}, + {"Process", Type, 0}, + {"Process.Pid", Field, 0}, + {"ProcessState", Type, 0}, + {"ReadDir", Func, 16}, + {"ReadFile", Func, 16}, + {"Readlink", Func, 0}, + {"Remove", Func, 0}, + {"RemoveAll", Func, 0}, + {"Rename", Func, 0}, + {"SEEK_CUR", Const, 0}, + {"SEEK_END", Const, 0}, + {"SEEK_SET", Const, 0}, + {"SameFile", Func, 0}, + {"Setenv", Func, 0}, + {"Signal", Type, 0}, + {"StartProcess", Func, 0}, + {"Stat", Func, 0}, + {"Stderr", Var, 0}, + {"Stdin", Var, 0}, + {"Stdout", Var, 0}, + {"Symlink", Func, 0}, + {"SyscallError", Type, 0}, + {"SyscallError.Err", Field, 0}, + {"SyscallError.Syscall", Field, 0}, + {"TempDir", Func, 0}, + {"Truncate", Func, 0}, + {"Unsetenv", Func, 4}, + {"UserCacheDir", Func, 11}, + {"UserConfigDir", Func, 13}, + {"UserHomeDir", Func, 12}, + {"WriteFile", Func, 16}, + }, + "os/exec": { + {"(*Cmd).CombinedOutput", Method, 0}, + {"(*Cmd).Environ", Method, 19}, + {"(*Cmd).Output", Method, 0}, + {"(*Cmd).Run", Method, 0}, + {"(*Cmd).Start", Method, 0}, + {"(*Cmd).StderrPipe", Method, 0}, + {"(*Cmd).StdinPipe", Method, 0}, + {"(*Cmd).StdoutPipe", Method, 0}, + {"(*Cmd).String", Method, 13}, + {"(*Cmd).Wait", Method, 0}, + {"(*Error).Error", Method, 0}, + {"(*Error).Unwrap", Method, 13}, + {"(*ExitError).Error", Method, 0}, + {"(ExitError).ExitCode", Method, 12}, + {"(ExitError).Exited", Method, 0}, + {"(ExitError).Pid", Method, 0}, + {"(ExitError).String", Method, 0}, + {"(ExitError).Success", Method, 0}, + {"(ExitError).Sys", Method, 0}, + {"(ExitError).SysUsage", Method, 0}, + {"(ExitError).SystemTime", Method, 0}, + {"(ExitError).UserTime", Method, 0}, + {"Cmd", Type, 0}, + {"Cmd.Args", Field, 0}, + {"Cmd.Cancel", Field, 20}, + {"Cmd.Dir", Field, 0}, + {"Cmd.Env", Field, 0}, + {"Cmd.Err", Field, 19}, + {"Cmd.ExtraFiles", Field, 0}, + {"Cmd.Path", Field, 0}, + {"Cmd.Process", Field, 0}, + {"Cmd.ProcessState", Field, 0}, + {"Cmd.Stderr", Field, 0}, + {"Cmd.Stdin", Field, 0}, + {"Cmd.Stdout", Field, 0}, + {"Cmd.SysProcAttr", Field, 0}, + {"Cmd.WaitDelay", Field, 20}, + {"Command", Func, 0}, + {"CommandContext", Func, 7}, + {"ErrDot", Var, 19}, + {"ErrNotFound", Var, 0}, + {"ErrWaitDelay", Var, 20}, + {"Error", Type, 0}, + {"Error.Err", Field, 0}, + {"Error.Name", Field, 0}, + {"ExitError", Type, 0}, + {"ExitError.ProcessState", Field, 0}, + {"ExitError.Stderr", Field, 6}, + {"LookPath", Func, 0}, + }, + "os/signal": { + {"Ignore", Func, 5}, + {"Ignored", Func, 11}, + {"Notify", Func, 0}, + {"NotifyContext", Func, 16}, + {"Reset", Func, 5}, + {"Stop", Func, 1}, + }, + "os/user": { + {"(*User).GroupIds", Method, 7}, + {"(UnknownGroupError).Error", Method, 7}, + {"(UnknownGroupIdError).Error", Method, 7}, + {"(UnknownUserError).Error", Method, 0}, + {"(UnknownUserIdError).Error", Method, 0}, + {"Current", Func, 0}, + {"Group", Type, 7}, + {"Group.Gid", Field, 7}, + {"Group.Name", Field, 7}, + {"Lookup", Func, 0}, + {"LookupGroup", Func, 7}, + {"LookupGroupId", Func, 7}, + {"LookupId", Func, 0}, + {"UnknownGroupError", Type, 7}, + {"UnknownGroupIdError", Type, 7}, + {"UnknownUserError", Type, 0}, + {"UnknownUserIdError", Type, 0}, + {"User", Type, 0}, + {"User.Gid", Field, 0}, + {"User.HomeDir", Field, 0}, + {"User.Name", Field, 0}, + {"User.Uid", Field, 0}, + {"User.Username", Field, 0}, + }, + "path": { + {"Base", Func, 0}, + {"Clean", Func, 0}, + {"Dir", Func, 0}, + {"ErrBadPattern", Var, 0}, + {"Ext", Func, 0}, + {"IsAbs", Func, 0}, + {"Join", Func, 0}, + {"Match", Func, 0}, + {"Split", Func, 0}, + }, + "path/filepath": { + {"Abs", Func, 0}, + {"Base", Func, 0}, + {"Clean", Func, 0}, + {"Dir", Func, 0}, + {"ErrBadPattern", Var, 0}, + {"EvalSymlinks", Func, 0}, + {"Ext", Func, 0}, + {"FromSlash", Func, 0}, + {"Glob", Func, 0}, + {"HasPrefix", Func, 0}, + {"IsAbs", Func, 0}, + {"IsLocal", Func, 20}, + {"Join", Func, 0}, + {"ListSeparator", Const, 0}, + {"Match", Func, 0}, + {"Rel", Func, 0}, + {"Separator", Const, 0}, + {"SkipAll", Var, 20}, + {"SkipDir", Var, 0}, + {"Split", Func, 0}, + {"SplitList", Func, 0}, + {"ToSlash", Func, 0}, + {"VolumeName", Func, 0}, + {"Walk", Func, 0}, + {"WalkDir", Func, 16}, + {"WalkFunc", Type, 0}, + }, + "plugin": { + {"(*Plugin).Lookup", Method, 8}, + {"Open", Func, 8}, + {"Plugin", Type, 8}, + {"Symbol", Type, 8}, + }, + "reflect": { + {"(*MapIter).Key", Method, 12}, + {"(*MapIter).Next", Method, 12}, + {"(*MapIter).Reset", Method, 18}, + {"(*MapIter).Value", Method, 12}, + {"(*ValueError).Error", Method, 0}, + {"(ChanDir).String", Method, 0}, + {"(Kind).String", Method, 0}, + {"(Method).IsExported", Method, 17}, + {"(StructField).IsExported", Method, 17}, + {"(StructTag).Get", Method, 0}, + {"(StructTag).Lookup", Method, 7}, + {"(Value).Addr", Method, 0}, + {"(Value).Bool", Method, 0}, + {"(Value).Bytes", Method, 0}, + {"(Value).Call", Method, 0}, + {"(Value).CallSlice", Method, 0}, + {"(Value).CanAddr", Method, 0}, + {"(Value).CanComplex", Method, 18}, + {"(Value).CanConvert", Method, 17}, + {"(Value).CanFloat", Method, 18}, + {"(Value).CanInt", Method, 18}, + {"(Value).CanInterface", Method, 0}, + {"(Value).CanSet", Method, 0}, + {"(Value).CanUint", Method, 18}, + {"(Value).Cap", Method, 0}, + {"(Value).Clear", Method, 21}, + {"(Value).Close", Method, 0}, + {"(Value).Comparable", Method, 20}, + {"(Value).Complex", Method, 0}, + {"(Value).Convert", Method, 1}, + {"(Value).Elem", Method, 0}, + {"(Value).Equal", Method, 20}, + {"(Value).Field", Method, 0}, + {"(Value).FieldByIndex", Method, 0}, + {"(Value).FieldByIndexErr", Method, 18}, + {"(Value).FieldByName", Method, 0}, + {"(Value).FieldByNameFunc", Method, 0}, + {"(Value).Float", Method, 0}, + {"(Value).Grow", Method, 20}, + {"(Value).Index", Method, 0}, + {"(Value).Int", Method, 0}, + {"(Value).Interface", Method, 0}, + {"(Value).InterfaceData", Method, 0}, + {"(Value).IsNil", Method, 0}, + {"(Value).IsValid", Method, 0}, + {"(Value).IsZero", Method, 13}, + {"(Value).Kind", Method, 0}, + {"(Value).Len", Method, 0}, + {"(Value).MapIndex", Method, 0}, + {"(Value).MapKeys", Method, 0}, + {"(Value).MapRange", Method, 12}, + {"(Value).Method", Method, 0}, + {"(Value).MethodByName", Method, 0}, + {"(Value).NumField", Method, 0}, + {"(Value).NumMethod", Method, 0}, + {"(Value).OverflowComplex", Method, 0}, + {"(Value).OverflowFloat", Method, 0}, + {"(Value).OverflowInt", Method, 0}, + {"(Value).OverflowUint", Method, 0}, + {"(Value).Pointer", Method, 0}, + {"(Value).Recv", Method, 0}, + {"(Value).Send", Method, 0}, + {"(Value).Set", Method, 0}, + {"(Value).SetBool", Method, 0}, + {"(Value).SetBytes", Method, 0}, + {"(Value).SetCap", Method, 2}, + {"(Value).SetComplex", Method, 0}, + {"(Value).SetFloat", Method, 0}, + {"(Value).SetInt", Method, 0}, + {"(Value).SetIterKey", Method, 18}, + {"(Value).SetIterValue", Method, 18}, + {"(Value).SetLen", Method, 0}, + {"(Value).SetMapIndex", Method, 0}, + {"(Value).SetPointer", Method, 0}, + {"(Value).SetString", Method, 0}, + {"(Value).SetUint", Method, 0}, + {"(Value).SetZero", Method, 20}, + {"(Value).Slice", Method, 0}, + {"(Value).Slice3", Method, 2}, + {"(Value).String", Method, 0}, + {"(Value).TryRecv", Method, 0}, + {"(Value).TrySend", Method, 0}, + {"(Value).Type", Method, 0}, + {"(Value).Uint", Method, 0}, + {"(Value).UnsafeAddr", Method, 0}, + {"(Value).UnsafePointer", Method, 18}, + {"Append", Func, 0}, + {"AppendSlice", Func, 0}, + {"Array", Const, 0}, + {"ArrayOf", Func, 5}, + {"Bool", Const, 0}, + {"BothDir", Const, 0}, + {"Chan", Const, 0}, + {"ChanDir", Type, 0}, + {"ChanOf", Func, 1}, + {"Complex128", Const, 0}, + {"Complex64", Const, 0}, + {"Copy", Func, 0}, + {"DeepEqual", Func, 0}, + {"Float32", Const, 0}, + {"Float64", Const, 0}, + {"Func", Const, 0}, + {"FuncOf", Func, 5}, + {"Indirect", Func, 0}, + {"Int", Const, 0}, + {"Int16", Const, 0}, + {"Int32", Const, 0}, + {"Int64", Const, 0}, + {"Int8", Const, 0}, + {"Interface", Const, 0}, + {"Invalid", Const, 0}, + {"Kind", Type, 0}, + {"MakeChan", Func, 0}, + {"MakeFunc", Func, 1}, + {"MakeMap", Func, 0}, + {"MakeMapWithSize", Func, 9}, + {"MakeSlice", Func, 0}, + {"Map", Const, 0}, + {"MapIter", Type, 12}, + {"MapOf", Func, 1}, + {"Method", Type, 0}, + {"Method.Func", Field, 0}, + {"Method.Index", Field, 0}, + {"Method.Name", Field, 0}, + {"Method.PkgPath", Field, 0}, + {"Method.Type", Field, 0}, + {"New", Func, 0}, + {"NewAt", Func, 0}, + {"Pointer", Const, 18}, + {"PointerTo", Func, 18}, + {"Ptr", Const, 0}, + {"PtrTo", Func, 0}, + {"RecvDir", Const, 0}, + {"Select", Func, 1}, + {"SelectCase", Type, 1}, + {"SelectCase.Chan", Field, 1}, + {"SelectCase.Dir", Field, 1}, + {"SelectCase.Send", Field, 1}, + {"SelectDefault", Const, 1}, + {"SelectDir", Type, 1}, + {"SelectRecv", Const, 1}, + {"SelectSend", Const, 1}, + {"SendDir", Const, 0}, + {"Slice", Const, 0}, + {"SliceHeader", Type, 0}, + {"SliceHeader.Cap", Field, 0}, + {"SliceHeader.Data", Field, 0}, + {"SliceHeader.Len", Field, 0}, + {"SliceOf", Func, 1}, + {"String", Const, 0}, + {"StringHeader", Type, 0}, + {"StringHeader.Data", Field, 0}, + {"StringHeader.Len", Field, 0}, + {"Struct", Const, 0}, + {"StructField", Type, 0}, + {"StructField.Anonymous", Field, 0}, + {"StructField.Index", Field, 0}, + {"StructField.Name", Field, 0}, + {"StructField.Offset", Field, 0}, + {"StructField.PkgPath", Field, 0}, + {"StructField.Tag", Field, 0}, + {"StructField.Type", Field, 0}, + {"StructOf", Func, 7}, + {"StructTag", Type, 0}, + {"Swapper", Func, 8}, + {"Type", Type, 0}, + {"TypeFor", Func, 22}, + {"TypeOf", Func, 0}, + {"Uint", Const, 0}, + {"Uint16", Const, 0}, + {"Uint32", Const, 0}, + {"Uint64", Const, 0}, + {"Uint8", Const, 0}, + {"Uintptr", Const, 0}, + {"UnsafePointer", Const, 0}, + {"Value", Type, 0}, + {"ValueError", Type, 0}, + {"ValueError.Kind", Field, 0}, + {"ValueError.Method", Field, 0}, + {"ValueOf", Func, 0}, + {"VisibleFields", Func, 17}, + {"Zero", Func, 0}, + }, + "regexp": { + {"(*Regexp).Copy", Method, 6}, + {"(*Regexp).Expand", Method, 0}, + {"(*Regexp).ExpandString", Method, 0}, + {"(*Regexp).Find", Method, 0}, + {"(*Regexp).FindAll", Method, 0}, + {"(*Regexp).FindAllIndex", Method, 0}, + {"(*Regexp).FindAllString", Method, 0}, + {"(*Regexp).FindAllStringIndex", Method, 0}, + {"(*Regexp).FindAllStringSubmatch", Method, 0}, + {"(*Regexp).FindAllStringSubmatchIndex", Method, 0}, + {"(*Regexp).FindAllSubmatch", Method, 0}, + {"(*Regexp).FindAllSubmatchIndex", Method, 0}, + {"(*Regexp).FindIndex", Method, 0}, + {"(*Regexp).FindReaderIndex", Method, 0}, + {"(*Regexp).FindReaderSubmatchIndex", Method, 0}, + {"(*Regexp).FindString", Method, 0}, + {"(*Regexp).FindStringIndex", Method, 0}, + {"(*Regexp).FindStringSubmatch", Method, 0}, + {"(*Regexp).FindStringSubmatchIndex", Method, 0}, + {"(*Regexp).FindSubmatch", Method, 0}, + {"(*Regexp).FindSubmatchIndex", Method, 0}, + {"(*Regexp).LiteralPrefix", Method, 0}, + {"(*Regexp).Longest", Method, 1}, + {"(*Regexp).MarshalText", Method, 21}, + {"(*Regexp).Match", Method, 0}, + {"(*Regexp).MatchReader", Method, 0}, + {"(*Regexp).MatchString", Method, 0}, + {"(*Regexp).NumSubexp", Method, 0}, + {"(*Regexp).ReplaceAll", Method, 0}, + {"(*Regexp).ReplaceAllFunc", Method, 0}, + {"(*Regexp).ReplaceAllLiteral", Method, 0}, + {"(*Regexp).ReplaceAllLiteralString", Method, 0}, + {"(*Regexp).ReplaceAllString", Method, 0}, + {"(*Regexp).ReplaceAllStringFunc", Method, 0}, + {"(*Regexp).Split", Method, 1}, + {"(*Regexp).String", Method, 0}, + {"(*Regexp).SubexpIndex", Method, 15}, + {"(*Regexp).SubexpNames", Method, 0}, + {"(*Regexp).UnmarshalText", Method, 21}, + {"Compile", Func, 0}, + {"CompilePOSIX", Func, 0}, + {"Match", Func, 0}, + {"MatchReader", Func, 0}, + {"MatchString", Func, 0}, + {"MustCompile", Func, 0}, + {"MustCompilePOSIX", Func, 0}, + {"QuoteMeta", Func, 0}, + {"Regexp", Type, 0}, + }, + "regexp/syntax": { + {"(*Error).Error", Method, 0}, + {"(*Inst).MatchEmptyWidth", Method, 0}, + {"(*Inst).MatchRune", Method, 0}, + {"(*Inst).MatchRunePos", Method, 3}, + {"(*Inst).String", Method, 0}, + {"(*Prog).Prefix", Method, 0}, + {"(*Prog).StartCond", Method, 0}, + {"(*Prog).String", Method, 0}, + {"(*Regexp).CapNames", Method, 0}, + {"(*Regexp).Equal", Method, 0}, + {"(*Regexp).MaxCap", Method, 0}, + {"(*Regexp).Simplify", Method, 0}, + {"(*Regexp).String", Method, 0}, + {"(ErrorCode).String", Method, 0}, + {"(InstOp).String", Method, 3}, + {"(Op).String", Method, 11}, + {"ClassNL", Const, 0}, + {"Compile", Func, 0}, + {"DotNL", Const, 0}, + {"EmptyBeginLine", Const, 0}, + {"EmptyBeginText", Const, 0}, + {"EmptyEndLine", Const, 0}, + {"EmptyEndText", Const, 0}, + {"EmptyNoWordBoundary", Const, 0}, + {"EmptyOp", Type, 0}, + {"EmptyOpContext", Func, 0}, + {"EmptyWordBoundary", Const, 0}, + {"ErrInternalError", Const, 0}, + {"ErrInvalidCharClass", Const, 0}, + {"ErrInvalidCharRange", Const, 0}, + {"ErrInvalidEscape", Const, 0}, + {"ErrInvalidNamedCapture", Const, 0}, + {"ErrInvalidPerlOp", Const, 0}, + {"ErrInvalidRepeatOp", Const, 0}, + {"ErrInvalidRepeatSize", Const, 0}, + {"ErrInvalidUTF8", Const, 0}, + {"ErrLarge", Const, 20}, + {"ErrMissingBracket", Const, 0}, + {"ErrMissingParen", Const, 0}, + {"ErrMissingRepeatArgument", Const, 0}, + {"ErrNestingDepth", Const, 19}, + {"ErrTrailingBackslash", Const, 0}, + {"ErrUnexpectedParen", Const, 1}, + {"Error", Type, 0}, + {"Error.Code", Field, 0}, + {"Error.Expr", Field, 0}, + {"ErrorCode", Type, 0}, + {"Flags", Type, 0}, + {"FoldCase", Const, 0}, + {"Inst", Type, 0}, + {"Inst.Arg", Field, 0}, + {"Inst.Op", Field, 0}, + {"Inst.Out", Field, 0}, + {"Inst.Rune", Field, 0}, + {"InstAlt", Const, 0}, + {"InstAltMatch", Const, 0}, + {"InstCapture", Const, 0}, + {"InstEmptyWidth", Const, 0}, + {"InstFail", Const, 0}, + {"InstMatch", Const, 0}, + {"InstNop", Const, 0}, + {"InstOp", Type, 0}, + {"InstRune", Const, 0}, + {"InstRune1", Const, 0}, + {"InstRuneAny", Const, 0}, + {"InstRuneAnyNotNL", Const, 0}, + {"IsWordChar", Func, 0}, + {"Literal", Const, 0}, + {"MatchNL", Const, 0}, + {"NonGreedy", Const, 0}, + {"OneLine", Const, 0}, + {"Op", Type, 0}, + {"OpAlternate", Const, 0}, + {"OpAnyChar", Const, 0}, + {"OpAnyCharNotNL", Const, 0}, + {"OpBeginLine", Const, 0}, + {"OpBeginText", Const, 0}, + {"OpCapture", Const, 0}, + {"OpCharClass", Const, 0}, + {"OpConcat", Const, 0}, + {"OpEmptyMatch", Const, 0}, + {"OpEndLine", Const, 0}, + {"OpEndText", Const, 0}, + {"OpLiteral", Const, 0}, + {"OpNoMatch", Const, 0}, + {"OpNoWordBoundary", Const, 0}, + {"OpPlus", Const, 0}, + {"OpQuest", Const, 0}, + {"OpRepeat", Const, 0}, + {"OpStar", Const, 0}, + {"OpWordBoundary", Const, 0}, + {"POSIX", Const, 0}, + {"Parse", Func, 0}, + {"Perl", Const, 0}, + {"PerlX", Const, 0}, + {"Prog", Type, 0}, + {"Prog.Inst", Field, 0}, + {"Prog.NumCap", Field, 0}, + {"Prog.Start", Field, 0}, + {"Regexp", Type, 0}, + {"Regexp.Cap", Field, 0}, + {"Regexp.Flags", Field, 0}, + {"Regexp.Max", Field, 0}, + {"Regexp.Min", Field, 0}, + {"Regexp.Name", Field, 0}, + {"Regexp.Op", Field, 0}, + {"Regexp.Rune", Field, 0}, + {"Regexp.Rune0", Field, 0}, + {"Regexp.Sub", Field, 0}, + {"Regexp.Sub0", Field, 0}, + {"Simple", Const, 0}, + {"UnicodeGroups", Const, 0}, + {"WasDollar", Const, 0}, + }, + "runtime": { + {"(*BlockProfileRecord).Stack", Method, 1}, + {"(*Frames).Next", Method, 7}, + {"(*Func).Entry", Method, 0}, + {"(*Func).FileLine", Method, 0}, + {"(*Func).Name", Method, 0}, + {"(*MemProfileRecord).InUseBytes", Method, 0}, + {"(*MemProfileRecord).InUseObjects", Method, 0}, + {"(*MemProfileRecord).Stack", Method, 0}, + {"(*PanicNilError).Error", Method, 21}, + {"(*PanicNilError).RuntimeError", Method, 21}, + {"(*Pinner).Pin", Method, 21}, + {"(*Pinner).Unpin", Method, 21}, + {"(*StackRecord).Stack", Method, 0}, + {"(*TypeAssertionError).Error", Method, 0}, + {"(*TypeAssertionError).RuntimeError", Method, 0}, + {"BlockProfile", Func, 1}, + {"BlockProfileRecord", Type, 1}, + {"BlockProfileRecord.Count", Field, 1}, + {"BlockProfileRecord.Cycles", Field, 1}, + {"BlockProfileRecord.StackRecord", Field, 1}, + {"Breakpoint", Func, 0}, + {"CPUProfile", Func, 0}, + {"Caller", Func, 0}, + {"Callers", Func, 0}, + {"CallersFrames", Func, 7}, + {"Compiler", Const, 0}, + {"Error", Type, 0}, + {"Frame", Type, 7}, + {"Frame.Entry", Field, 7}, + {"Frame.File", Field, 7}, + {"Frame.Func", Field, 7}, + {"Frame.Function", Field, 7}, + {"Frame.Line", Field, 7}, + {"Frame.PC", Field, 7}, + {"Frames", Type, 7}, + {"Func", Type, 0}, + {"FuncForPC", Func, 0}, + {"GC", Func, 0}, + {"GOARCH", Const, 0}, + {"GOMAXPROCS", Func, 0}, + {"GOOS", Const, 0}, + {"GOROOT", Func, 0}, + {"Goexit", Func, 0}, + {"GoroutineProfile", Func, 0}, + {"Gosched", Func, 0}, + {"KeepAlive", Func, 7}, + {"LockOSThread", Func, 0}, + {"MemProfile", Func, 0}, + {"MemProfileRate", Var, 0}, + {"MemProfileRecord", Type, 0}, + {"MemProfileRecord.AllocBytes", Field, 0}, + {"MemProfileRecord.AllocObjects", Field, 0}, + {"MemProfileRecord.FreeBytes", Field, 0}, + {"MemProfileRecord.FreeObjects", Field, 0}, + {"MemProfileRecord.Stack0", Field, 0}, + {"MemStats", Type, 0}, + {"MemStats.Alloc", Field, 0}, + {"MemStats.BuckHashSys", Field, 0}, + {"MemStats.BySize", Field, 0}, + {"MemStats.DebugGC", Field, 0}, + {"MemStats.EnableGC", Field, 0}, + {"MemStats.Frees", Field, 0}, + {"MemStats.GCCPUFraction", Field, 5}, + {"MemStats.GCSys", Field, 2}, + {"MemStats.HeapAlloc", Field, 0}, + {"MemStats.HeapIdle", Field, 0}, + {"MemStats.HeapInuse", Field, 0}, + {"MemStats.HeapObjects", Field, 0}, + {"MemStats.HeapReleased", Field, 0}, + {"MemStats.HeapSys", Field, 0}, + {"MemStats.LastGC", Field, 0}, + {"MemStats.Lookups", Field, 0}, + {"MemStats.MCacheInuse", Field, 0}, + {"MemStats.MCacheSys", Field, 0}, + {"MemStats.MSpanInuse", Field, 0}, + {"MemStats.MSpanSys", Field, 0}, + {"MemStats.Mallocs", Field, 0}, + {"MemStats.NextGC", Field, 0}, + {"MemStats.NumForcedGC", Field, 8}, + {"MemStats.NumGC", Field, 0}, + {"MemStats.OtherSys", Field, 2}, + {"MemStats.PauseEnd", Field, 4}, + {"MemStats.PauseNs", Field, 0}, + {"MemStats.PauseTotalNs", Field, 0}, + {"MemStats.StackInuse", Field, 0}, + {"MemStats.StackSys", Field, 0}, + {"MemStats.Sys", Field, 0}, + {"MemStats.TotalAlloc", Field, 0}, + {"MutexProfile", Func, 8}, + {"NumCPU", Func, 0}, + {"NumCgoCall", Func, 0}, + {"NumGoroutine", Func, 0}, + {"PanicNilError", Type, 21}, + {"Pinner", Type, 21}, + {"ReadMemStats", Func, 0}, + {"ReadTrace", Func, 5}, + {"SetBlockProfileRate", Func, 1}, + {"SetCPUProfileRate", Func, 0}, + {"SetCgoTraceback", Func, 7}, + {"SetFinalizer", Func, 0}, + {"SetMutexProfileFraction", Func, 8}, + {"Stack", Func, 0}, + {"StackRecord", Type, 0}, + {"StackRecord.Stack0", Field, 0}, + {"StartTrace", Func, 5}, + {"StopTrace", Func, 5}, + {"ThreadCreateProfile", Func, 0}, + {"TypeAssertionError", Type, 0}, + {"UnlockOSThread", Func, 0}, + {"Version", Func, 0}, + }, + "runtime/cgo": { + {"(Handle).Delete", Method, 17}, + {"(Handle).Value", Method, 17}, + {"Handle", Type, 17}, + {"Incomplete", Type, 20}, + {"NewHandle", Func, 17}, + }, + "runtime/coverage": { + {"ClearCounters", Func, 20}, + {"WriteCounters", Func, 20}, + {"WriteCountersDir", Func, 20}, + {"WriteMeta", Func, 20}, + {"WriteMetaDir", Func, 20}, + }, + "runtime/debug": { + {"(*BuildInfo).String", Method, 18}, + {"BuildInfo", Type, 12}, + {"BuildInfo.Deps", Field, 12}, + {"BuildInfo.GoVersion", Field, 18}, + {"BuildInfo.Main", Field, 12}, + {"BuildInfo.Path", Field, 12}, + {"BuildInfo.Settings", Field, 18}, + {"BuildSetting", Type, 18}, + {"BuildSetting.Key", Field, 18}, + {"BuildSetting.Value", Field, 18}, + {"FreeOSMemory", Func, 1}, + {"GCStats", Type, 1}, + {"GCStats.LastGC", Field, 1}, + {"GCStats.NumGC", Field, 1}, + {"GCStats.Pause", Field, 1}, + {"GCStats.PauseEnd", Field, 4}, + {"GCStats.PauseQuantiles", Field, 1}, + {"GCStats.PauseTotal", Field, 1}, + {"Module", Type, 12}, + {"Module.Path", Field, 12}, + {"Module.Replace", Field, 12}, + {"Module.Sum", Field, 12}, + {"Module.Version", Field, 12}, + {"ParseBuildInfo", Func, 18}, + {"PrintStack", Func, 0}, + {"ReadBuildInfo", Func, 12}, + {"ReadGCStats", Func, 1}, + {"SetGCPercent", Func, 1}, + {"SetMaxStack", Func, 2}, + {"SetMaxThreads", Func, 2}, + {"SetMemoryLimit", Func, 19}, + {"SetPanicOnFault", Func, 3}, + {"SetTraceback", Func, 6}, + {"Stack", Func, 0}, + {"WriteHeapDump", Func, 3}, + }, + "runtime/metrics": { + {"(Value).Float64", Method, 16}, + {"(Value).Float64Histogram", Method, 16}, + {"(Value).Kind", Method, 16}, + {"(Value).Uint64", Method, 16}, + {"All", Func, 16}, + {"Description", Type, 16}, + {"Description.Cumulative", Field, 16}, + {"Description.Description", Field, 16}, + {"Description.Kind", Field, 16}, + {"Description.Name", Field, 16}, + {"Float64Histogram", Type, 16}, + {"Float64Histogram.Buckets", Field, 16}, + {"Float64Histogram.Counts", Field, 16}, + {"KindBad", Const, 16}, + {"KindFloat64", Const, 16}, + {"KindFloat64Histogram", Const, 16}, + {"KindUint64", Const, 16}, + {"Read", Func, 16}, + {"Sample", Type, 16}, + {"Sample.Name", Field, 16}, + {"Sample.Value", Field, 16}, + {"Value", Type, 16}, + {"ValueKind", Type, 16}, + }, + "runtime/pprof": { + {"(*Profile).Add", Method, 0}, + {"(*Profile).Count", Method, 0}, + {"(*Profile).Name", Method, 0}, + {"(*Profile).Remove", Method, 0}, + {"(*Profile).WriteTo", Method, 0}, + {"Do", Func, 9}, + {"ForLabels", Func, 9}, + {"Label", Func, 9}, + {"LabelSet", Type, 9}, + {"Labels", Func, 9}, + {"Lookup", Func, 0}, + {"NewProfile", Func, 0}, + {"Profile", Type, 0}, + {"Profiles", Func, 0}, + {"SetGoroutineLabels", Func, 9}, + {"StartCPUProfile", Func, 0}, + {"StopCPUProfile", Func, 0}, + {"WithLabels", Func, 9}, + {"WriteHeapProfile", Func, 0}, + }, + "runtime/trace": { + {"(*Region).End", Method, 11}, + {"(*Task).End", Method, 11}, + {"IsEnabled", Func, 11}, + {"Log", Func, 11}, + {"Logf", Func, 11}, + {"NewTask", Func, 11}, + {"Region", Type, 11}, + {"Start", Func, 5}, + {"StartRegion", Func, 11}, + {"Stop", Func, 5}, + {"Task", Type, 11}, + {"WithRegion", Func, 11}, + }, + "slices": { + {"BinarySearch", Func, 21}, + {"BinarySearchFunc", Func, 21}, + {"Clip", Func, 21}, + {"Clone", Func, 21}, + {"Compact", Func, 21}, + {"CompactFunc", Func, 21}, + {"Compare", Func, 21}, + {"CompareFunc", Func, 21}, + {"Concat", Func, 22}, + {"Contains", Func, 21}, + {"ContainsFunc", Func, 21}, + {"Delete", Func, 21}, + {"DeleteFunc", Func, 21}, + {"Equal", Func, 21}, + {"EqualFunc", Func, 21}, + {"Grow", Func, 21}, + {"Index", Func, 21}, + {"IndexFunc", Func, 21}, + {"Insert", Func, 21}, + {"IsSorted", Func, 21}, + {"IsSortedFunc", Func, 21}, + {"Max", Func, 21}, + {"MaxFunc", Func, 21}, + {"Min", Func, 21}, + {"MinFunc", Func, 21}, + {"Replace", Func, 21}, + {"Reverse", Func, 21}, + {"Sort", Func, 21}, + {"SortFunc", Func, 21}, + {"SortStableFunc", Func, 21}, + }, + "sort": { + {"(Float64Slice).Len", Method, 0}, + {"(Float64Slice).Less", Method, 0}, + {"(Float64Slice).Search", Method, 0}, + {"(Float64Slice).Sort", Method, 0}, + {"(Float64Slice).Swap", Method, 0}, + {"(IntSlice).Len", Method, 0}, + {"(IntSlice).Less", Method, 0}, + {"(IntSlice).Search", Method, 0}, + {"(IntSlice).Sort", Method, 0}, + {"(IntSlice).Swap", Method, 0}, + {"(StringSlice).Len", Method, 0}, + {"(StringSlice).Less", Method, 0}, + {"(StringSlice).Search", Method, 0}, + {"(StringSlice).Sort", Method, 0}, + {"(StringSlice).Swap", Method, 0}, + {"Find", Func, 19}, + {"Float64Slice", Type, 0}, + {"Float64s", Func, 0}, + {"Float64sAreSorted", Func, 0}, + {"IntSlice", Type, 0}, + {"Interface", Type, 0}, + {"Ints", Func, 0}, + {"IntsAreSorted", Func, 0}, + {"IsSorted", Func, 0}, + {"Reverse", Func, 1}, + {"Search", Func, 0}, + {"SearchFloat64s", Func, 0}, + {"SearchInts", Func, 0}, + {"SearchStrings", Func, 0}, + {"Slice", Func, 8}, + {"SliceIsSorted", Func, 8}, + {"SliceStable", Func, 8}, + {"Sort", Func, 0}, + {"Stable", Func, 2}, + {"StringSlice", Type, 0}, + {"Strings", Func, 0}, + {"StringsAreSorted", Func, 0}, + }, + "strconv": { + {"(*NumError).Error", Method, 0}, + {"(*NumError).Unwrap", Method, 14}, + {"AppendBool", Func, 0}, + {"AppendFloat", Func, 0}, + {"AppendInt", Func, 0}, + {"AppendQuote", Func, 0}, + {"AppendQuoteRune", Func, 0}, + {"AppendQuoteRuneToASCII", Func, 0}, + {"AppendQuoteRuneToGraphic", Func, 6}, + {"AppendQuoteToASCII", Func, 0}, + {"AppendQuoteToGraphic", Func, 6}, + {"AppendUint", Func, 0}, + {"Atoi", Func, 0}, + {"CanBackquote", Func, 0}, + {"ErrRange", Var, 0}, + {"ErrSyntax", Var, 0}, + {"FormatBool", Func, 0}, + {"FormatComplex", Func, 15}, + {"FormatFloat", Func, 0}, + {"FormatInt", Func, 0}, + {"FormatUint", Func, 0}, + {"IntSize", Const, 0}, + {"IsGraphic", Func, 6}, + {"IsPrint", Func, 0}, + {"Itoa", Func, 0}, + {"NumError", Type, 0}, + {"NumError.Err", Field, 0}, + {"NumError.Func", Field, 0}, + {"NumError.Num", Field, 0}, + {"ParseBool", Func, 0}, + {"ParseComplex", Func, 15}, + {"ParseFloat", Func, 0}, + {"ParseInt", Func, 0}, + {"ParseUint", Func, 0}, + {"Quote", Func, 0}, + {"QuoteRune", Func, 0}, + {"QuoteRuneToASCII", Func, 0}, + {"QuoteRuneToGraphic", Func, 6}, + {"QuoteToASCII", Func, 0}, + {"QuoteToGraphic", Func, 6}, + {"QuotedPrefix", Func, 17}, + {"Unquote", Func, 0}, + {"UnquoteChar", Func, 0}, + }, + "strings": { + {"(*Builder).Cap", Method, 12}, + {"(*Builder).Grow", Method, 10}, + {"(*Builder).Len", Method, 10}, + {"(*Builder).Reset", Method, 10}, + {"(*Builder).String", Method, 10}, + {"(*Builder).Write", Method, 10}, + {"(*Builder).WriteByte", Method, 10}, + {"(*Builder).WriteRune", Method, 10}, + {"(*Builder).WriteString", Method, 10}, + {"(*Reader).Len", Method, 0}, + {"(*Reader).Read", Method, 0}, + {"(*Reader).ReadAt", Method, 0}, + {"(*Reader).ReadByte", Method, 0}, + {"(*Reader).ReadRune", Method, 0}, + {"(*Reader).Reset", Method, 7}, + {"(*Reader).Seek", Method, 0}, + {"(*Reader).Size", Method, 5}, + {"(*Reader).UnreadByte", Method, 0}, + {"(*Reader).UnreadRune", Method, 0}, + {"(*Reader).WriteTo", Method, 1}, + {"(*Replacer).Replace", Method, 0}, + {"(*Replacer).WriteString", Method, 0}, + {"Builder", Type, 10}, + {"Clone", Func, 18}, + {"Compare", Func, 5}, + {"Contains", Func, 0}, + {"ContainsAny", Func, 0}, + {"ContainsFunc", Func, 21}, + {"ContainsRune", Func, 0}, + {"Count", Func, 0}, + {"Cut", Func, 18}, + {"CutPrefix", Func, 20}, + {"CutSuffix", Func, 20}, + {"EqualFold", Func, 0}, + {"Fields", Func, 0}, + {"FieldsFunc", Func, 0}, + {"HasPrefix", Func, 0}, + {"HasSuffix", Func, 0}, + {"Index", Func, 0}, + {"IndexAny", Func, 0}, + {"IndexByte", Func, 2}, + {"IndexFunc", Func, 0}, + {"IndexRune", Func, 0}, + {"Join", Func, 0}, + {"LastIndex", Func, 0}, + {"LastIndexAny", Func, 0}, + {"LastIndexByte", Func, 5}, + {"LastIndexFunc", Func, 0}, + {"Map", Func, 0}, + {"NewReader", Func, 0}, + {"NewReplacer", Func, 0}, + {"Reader", Type, 0}, + {"Repeat", Func, 0}, + {"Replace", Func, 0}, + {"ReplaceAll", Func, 12}, + {"Replacer", Type, 0}, + {"Split", Func, 0}, + {"SplitAfter", Func, 0}, + {"SplitAfterN", Func, 0}, + {"SplitN", Func, 0}, + {"Title", Func, 0}, + {"ToLower", Func, 0}, + {"ToLowerSpecial", Func, 0}, + {"ToTitle", Func, 0}, + {"ToTitleSpecial", Func, 0}, + {"ToUpper", Func, 0}, + {"ToUpperSpecial", Func, 0}, + {"ToValidUTF8", Func, 13}, + {"Trim", Func, 0}, + {"TrimFunc", Func, 0}, + {"TrimLeft", Func, 0}, + {"TrimLeftFunc", Func, 0}, + {"TrimPrefix", Func, 1}, + {"TrimRight", Func, 0}, + {"TrimRightFunc", Func, 0}, + {"TrimSpace", Func, 0}, + {"TrimSuffix", Func, 1}, + }, + "sync": { + {"(*Cond).Broadcast", Method, 0}, + {"(*Cond).Signal", Method, 0}, + {"(*Cond).Wait", Method, 0}, + {"(*Map).CompareAndDelete", Method, 20}, + {"(*Map).CompareAndSwap", Method, 20}, + {"(*Map).Delete", Method, 9}, + {"(*Map).Load", Method, 9}, + {"(*Map).LoadAndDelete", Method, 15}, + {"(*Map).LoadOrStore", Method, 9}, + {"(*Map).Range", Method, 9}, + {"(*Map).Store", Method, 9}, + {"(*Map).Swap", Method, 20}, + {"(*Mutex).Lock", Method, 0}, + {"(*Mutex).TryLock", Method, 18}, + {"(*Mutex).Unlock", Method, 0}, + {"(*Once).Do", Method, 0}, + {"(*Pool).Get", Method, 3}, + {"(*Pool).Put", Method, 3}, + {"(*RWMutex).Lock", Method, 0}, + {"(*RWMutex).RLock", Method, 0}, + {"(*RWMutex).RLocker", Method, 0}, + {"(*RWMutex).RUnlock", Method, 0}, + {"(*RWMutex).TryLock", Method, 18}, + {"(*RWMutex).TryRLock", Method, 18}, + {"(*RWMutex).Unlock", Method, 0}, + {"(*WaitGroup).Add", Method, 0}, + {"(*WaitGroup).Done", Method, 0}, + {"(*WaitGroup).Wait", Method, 0}, + {"Cond", Type, 0}, + {"Cond.L", Field, 0}, + {"Locker", Type, 0}, + {"Map", Type, 9}, + {"Mutex", Type, 0}, + {"NewCond", Func, 0}, + {"Once", Type, 0}, + {"OnceFunc", Func, 21}, + {"OnceValue", Func, 21}, + {"OnceValues", Func, 21}, + {"Pool", Type, 3}, + {"Pool.New", Field, 3}, + {"RWMutex", Type, 0}, + {"WaitGroup", Type, 0}, + }, + "sync/atomic": { + {"(*Bool).CompareAndSwap", Method, 19}, + {"(*Bool).Load", Method, 19}, + {"(*Bool).Store", Method, 19}, + {"(*Bool).Swap", Method, 19}, + {"(*Int32).Add", Method, 19}, + {"(*Int32).CompareAndSwap", Method, 19}, + {"(*Int32).Load", Method, 19}, + {"(*Int32).Store", Method, 19}, + {"(*Int32).Swap", Method, 19}, + {"(*Int64).Add", Method, 19}, + {"(*Int64).CompareAndSwap", Method, 19}, + {"(*Int64).Load", Method, 19}, + {"(*Int64).Store", Method, 19}, + {"(*Int64).Swap", Method, 19}, + {"(*Pointer).CompareAndSwap", Method, 19}, + {"(*Pointer).Load", Method, 19}, + {"(*Pointer).Store", Method, 19}, + {"(*Pointer).Swap", Method, 19}, + {"(*Uint32).Add", Method, 19}, + {"(*Uint32).CompareAndSwap", Method, 19}, + {"(*Uint32).Load", Method, 19}, + {"(*Uint32).Store", Method, 19}, + {"(*Uint32).Swap", Method, 19}, + {"(*Uint64).Add", Method, 19}, + {"(*Uint64).CompareAndSwap", Method, 19}, + {"(*Uint64).Load", Method, 19}, + {"(*Uint64).Store", Method, 19}, + {"(*Uint64).Swap", Method, 19}, + {"(*Uintptr).Add", Method, 19}, + {"(*Uintptr).CompareAndSwap", Method, 19}, + {"(*Uintptr).Load", Method, 19}, + {"(*Uintptr).Store", Method, 19}, + {"(*Uintptr).Swap", Method, 19}, + {"(*Value).CompareAndSwap", Method, 17}, + {"(*Value).Load", Method, 4}, + {"(*Value).Store", Method, 4}, + {"(*Value).Swap", Method, 17}, + {"AddInt32", Func, 0}, + {"AddInt64", Func, 0}, + {"AddUint32", Func, 0}, + {"AddUint64", Func, 0}, + {"AddUintptr", Func, 0}, + {"Bool", Type, 19}, + {"CompareAndSwapInt32", Func, 0}, + {"CompareAndSwapInt64", Func, 0}, + {"CompareAndSwapPointer", Func, 0}, + {"CompareAndSwapUint32", Func, 0}, + {"CompareAndSwapUint64", Func, 0}, + {"CompareAndSwapUintptr", Func, 0}, + {"Int32", Type, 19}, + {"Int64", Type, 19}, + {"LoadInt32", Func, 0}, + {"LoadInt64", Func, 0}, + {"LoadPointer", Func, 0}, + {"LoadUint32", Func, 0}, + {"LoadUint64", Func, 0}, + {"LoadUintptr", Func, 0}, + {"Pointer", Type, 19}, + {"StoreInt32", Func, 0}, + {"StoreInt64", Func, 0}, + {"StorePointer", Func, 0}, + {"StoreUint32", Func, 0}, + {"StoreUint64", Func, 0}, + {"StoreUintptr", Func, 0}, + {"SwapInt32", Func, 2}, + {"SwapInt64", Func, 2}, + {"SwapPointer", Func, 2}, + {"SwapUint32", Func, 2}, + {"SwapUint64", Func, 2}, + {"SwapUintptr", Func, 2}, + {"Uint32", Type, 19}, + {"Uint64", Type, 19}, + {"Uintptr", Type, 19}, + {"Value", Type, 4}, + }, + "syscall": { + {"(*Cmsghdr).SetLen", Method, 0}, + {"(*DLL).FindProc", Method, 0}, + {"(*DLL).MustFindProc", Method, 0}, + {"(*DLL).Release", Method, 0}, + {"(*DLLError).Error", Method, 0}, + {"(*DLLError).Unwrap", Method, 16}, + {"(*Filetime).Nanoseconds", Method, 0}, + {"(*Iovec).SetLen", Method, 0}, + {"(*LazyDLL).Handle", Method, 0}, + {"(*LazyDLL).Load", Method, 0}, + {"(*LazyDLL).NewProc", Method, 0}, + {"(*LazyProc).Addr", Method, 0}, + {"(*LazyProc).Call", Method, 0}, + {"(*LazyProc).Find", Method, 0}, + {"(*Msghdr).SetControllen", Method, 0}, + {"(*Proc).Addr", Method, 0}, + {"(*Proc).Call", Method, 0}, + {"(*PtraceRegs).PC", Method, 0}, + {"(*PtraceRegs).SetPC", Method, 0}, + {"(*RawSockaddrAny).Sockaddr", Method, 0}, + {"(*SID).Copy", Method, 0}, + {"(*SID).Len", Method, 0}, + {"(*SID).LookupAccount", Method, 0}, + {"(*SID).String", Method, 0}, + {"(*Timespec).Nano", Method, 0}, + {"(*Timespec).Unix", Method, 0}, + {"(*Timeval).Nano", Method, 0}, + {"(*Timeval).Nanoseconds", Method, 0}, + {"(*Timeval).Unix", Method, 0}, + {"(Errno).Error", Method, 0}, + {"(Errno).Is", Method, 13}, + {"(Errno).Temporary", Method, 0}, + {"(Errno).Timeout", Method, 0}, + {"(Signal).Signal", Method, 0}, + {"(Signal).String", Method, 0}, + {"(Token).Close", Method, 0}, + {"(Token).GetTokenPrimaryGroup", Method, 0}, + {"(Token).GetTokenUser", Method, 0}, + {"(Token).GetUserProfileDirectory", Method, 0}, + {"(WaitStatus).Continued", Method, 0}, + {"(WaitStatus).CoreDump", Method, 0}, + {"(WaitStatus).ExitStatus", Method, 0}, + {"(WaitStatus).Exited", Method, 0}, + {"(WaitStatus).Signal", Method, 0}, + {"(WaitStatus).Signaled", Method, 0}, + {"(WaitStatus).StopSignal", Method, 0}, + {"(WaitStatus).Stopped", Method, 0}, + {"(WaitStatus).TrapCause", Method, 0}, + {"AF_ALG", Const, 0}, + {"AF_APPLETALK", Const, 0}, + {"AF_ARP", Const, 0}, + {"AF_ASH", Const, 0}, + {"AF_ATM", Const, 0}, + {"AF_ATMPVC", Const, 0}, + {"AF_ATMSVC", Const, 0}, + {"AF_AX25", Const, 0}, + {"AF_BLUETOOTH", Const, 0}, + {"AF_BRIDGE", Const, 0}, + {"AF_CAIF", Const, 0}, + {"AF_CAN", Const, 0}, + {"AF_CCITT", Const, 0}, + {"AF_CHAOS", Const, 0}, + {"AF_CNT", Const, 0}, + {"AF_COIP", Const, 0}, + {"AF_DATAKIT", Const, 0}, + {"AF_DECnet", Const, 0}, + {"AF_DLI", Const, 0}, + {"AF_E164", Const, 0}, + {"AF_ECMA", Const, 0}, + {"AF_ECONET", Const, 0}, + {"AF_ENCAP", Const, 1}, + {"AF_FILE", Const, 0}, + {"AF_HYLINK", Const, 0}, + {"AF_IEEE80211", Const, 0}, + {"AF_IEEE802154", Const, 0}, + {"AF_IMPLINK", Const, 0}, + {"AF_INET", Const, 0}, + {"AF_INET6", Const, 0}, + {"AF_INET6_SDP", Const, 3}, + {"AF_INET_SDP", Const, 3}, + {"AF_IPX", Const, 0}, + {"AF_IRDA", Const, 0}, + {"AF_ISDN", Const, 0}, + {"AF_ISO", Const, 0}, + {"AF_IUCV", Const, 0}, + {"AF_KEY", Const, 0}, + {"AF_LAT", Const, 0}, + {"AF_LINK", Const, 0}, + {"AF_LLC", Const, 0}, + {"AF_LOCAL", Const, 0}, + {"AF_MAX", Const, 0}, + {"AF_MPLS", Const, 1}, + {"AF_NATM", Const, 0}, + {"AF_NDRV", Const, 0}, + {"AF_NETBEUI", Const, 0}, + {"AF_NETBIOS", Const, 0}, + {"AF_NETGRAPH", Const, 0}, + {"AF_NETLINK", Const, 0}, + {"AF_NETROM", Const, 0}, + {"AF_NS", Const, 0}, + {"AF_OROUTE", Const, 1}, + {"AF_OSI", Const, 0}, + {"AF_PACKET", Const, 0}, + {"AF_PHONET", Const, 0}, + {"AF_PPP", Const, 0}, + {"AF_PPPOX", Const, 0}, + {"AF_PUP", Const, 0}, + {"AF_RDS", Const, 0}, + {"AF_RESERVED_36", Const, 0}, + {"AF_ROSE", Const, 0}, + {"AF_ROUTE", Const, 0}, + {"AF_RXRPC", Const, 0}, + {"AF_SCLUSTER", Const, 0}, + {"AF_SECURITY", Const, 0}, + {"AF_SIP", Const, 0}, + {"AF_SLOW", Const, 0}, + {"AF_SNA", Const, 0}, + {"AF_SYSTEM", Const, 0}, + {"AF_TIPC", Const, 0}, + {"AF_UNIX", Const, 0}, + {"AF_UNSPEC", Const, 0}, + {"AF_UTUN", Const, 16}, + {"AF_VENDOR00", Const, 0}, + {"AF_VENDOR01", Const, 0}, + {"AF_VENDOR02", Const, 0}, + {"AF_VENDOR03", Const, 0}, + {"AF_VENDOR04", Const, 0}, + {"AF_VENDOR05", Const, 0}, + {"AF_VENDOR06", Const, 0}, + {"AF_VENDOR07", Const, 0}, + {"AF_VENDOR08", Const, 0}, + {"AF_VENDOR09", Const, 0}, + {"AF_VENDOR10", Const, 0}, + {"AF_VENDOR11", Const, 0}, + {"AF_VENDOR12", Const, 0}, + {"AF_VENDOR13", Const, 0}, + {"AF_VENDOR14", Const, 0}, + {"AF_VENDOR15", Const, 0}, + {"AF_VENDOR16", Const, 0}, + {"AF_VENDOR17", Const, 0}, + {"AF_VENDOR18", Const, 0}, + {"AF_VENDOR19", Const, 0}, + {"AF_VENDOR20", Const, 0}, + {"AF_VENDOR21", Const, 0}, + {"AF_VENDOR22", Const, 0}, + {"AF_VENDOR23", Const, 0}, + {"AF_VENDOR24", Const, 0}, + {"AF_VENDOR25", Const, 0}, + {"AF_VENDOR26", Const, 0}, + {"AF_VENDOR27", Const, 0}, + {"AF_VENDOR28", Const, 0}, + {"AF_VENDOR29", Const, 0}, + {"AF_VENDOR30", Const, 0}, + {"AF_VENDOR31", Const, 0}, + {"AF_VENDOR32", Const, 0}, + {"AF_VENDOR33", Const, 0}, + {"AF_VENDOR34", Const, 0}, + {"AF_VENDOR35", Const, 0}, + {"AF_VENDOR36", Const, 0}, + {"AF_VENDOR37", Const, 0}, + {"AF_VENDOR38", Const, 0}, + {"AF_VENDOR39", Const, 0}, + {"AF_VENDOR40", Const, 0}, + {"AF_VENDOR41", Const, 0}, + {"AF_VENDOR42", Const, 0}, + {"AF_VENDOR43", Const, 0}, + {"AF_VENDOR44", Const, 0}, + {"AF_VENDOR45", Const, 0}, + {"AF_VENDOR46", Const, 0}, + {"AF_VENDOR47", Const, 0}, + {"AF_WANPIPE", Const, 0}, + {"AF_X25", Const, 0}, + {"AI_CANONNAME", Const, 1}, + {"AI_NUMERICHOST", Const, 1}, + {"AI_PASSIVE", Const, 1}, + {"APPLICATION_ERROR", Const, 0}, + {"ARPHRD_ADAPT", Const, 0}, + {"ARPHRD_APPLETLK", Const, 0}, + {"ARPHRD_ARCNET", Const, 0}, + {"ARPHRD_ASH", Const, 0}, + {"ARPHRD_ATM", Const, 0}, + {"ARPHRD_AX25", Const, 0}, + {"ARPHRD_BIF", Const, 0}, + {"ARPHRD_CHAOS", Const, 0}, + {"ARPHRD_CISCO", Const, 0}, + {"ARPHRD_CSLIP", Const, 0}, + {"ARPHRD_CSLIP6", Const, 0}, + {"ARPHRD_DDCMP", Const, 0}, + {"ARPHRD_DLCI", Const, 0}, + {"ARPHRD_ECONET", Const, 0}, + {"ARPHRD_EETHER", Const, 0}, + {"ARPHRD_ETHER", Const, 0}, + {"ARPHRD_EUI64", Const, 0}, + {"ARPHRD_FCAL", Const, 0}, + {"ARPHRD_FCFABRIC", Const, 0}, + {"ARPHRD_FCPL", Const, 0}, + {"ARPHRD_FCPP", Const, 0}, + {"ARPHRD_FDDI", Const, 0}, + {"ARPHRD_FRAD", Const, 0}, + {"ARPHRD_FRELAY", Const, 1}, + {"ARPHRD_HDLC", Const, 0}, + {"ARPHRD_HIPPI", Const, 0}, + {"ARPHRD_HWX25", Const, 0}, + {"ARPHRD_IEEE1394", Const, 0}, + {"ARPHRD_IEEE802", Const, 0}, + {"ARPHRD_IEEE80211", Const, 0}, + {"ARPHRD_IEEE80211_PRISM", Const, 0}, + {"ARPHRD_IEEE80211_RADIOTAP", Const, 0}, + {"ARPHRD_IEEE802154", Const, 0}, + {"ARPHRD_IEEE802154_PHY", Const, 0}, + {"ARPHRD_IEEE802_TR", Const, 0}, + {"ARPHRD_INFINIBAND", Const, 0}, + {"ARPHRD_IPDDP", Const, 0}, + {"ARPHRD_IPGRE", Const, 0}, + {"ARPHRD_IRDA", Const, 0}, + {"ARPHRD_LAPB", Const, 0}, + {"ARPHRD_LOCALTLK", Const, 0}, + {"ARPHRD_LOOPBACK", Const, 0}, + {"ARPHRD_METRICOM", Const, 0}, + {"ARPHRD_NETROM", Const, 0}, + {"ARPHRD_NONE", Const, 0}, + {"ARPHRD_PIMREG", Const, 0}, + {"ARPHRD_PPP", Const, 0}, + {"ARPHRD_PRONET", Const, 0}, + {"ARPHRD_RAWHDLC", Const, 0}, + {"ARPHRD_ROSE", Const, 0}, + {"ARPHRD_RSRVD", Const, 0}, + {"ARPHRD_SIT", Const, 0}, + {"ARPHRD_SKIP", Const, 0}, + {"ARPHRD_SLIP", Const, 0}, + {"ARPHRD_SLIP6", Const, 0}, + {"ARPHRD_STRIP", Const, 1}, + {"ARPHRD_TUNNEL", Const, 0}, + {"ARPHRD_TUNNEL6", Const, 0}, + {"ARPHRD_VOID", Const, 0}, + {"ARPHRD_X25", Const, 0}, + {"AUTHTYPE_CLIENT", Const, 0}, + {"AUTHTYPE_SERVER", Const, 0}, + {"Accept", Func, 0}, + {"Accept4", Func, 1}, + {"AcceptEx", Func, 0}, + {"Access", Func, 0}, + {"Acct", Func, 0}, + {"AddrinfoW", Type, 1}, + {"AddrinfoW.Addr", Field, 1}, + {"AddrinfoW.Addrlen", Field, 1}, + {"AddrinfoW.Canonname", Field, 1}, + {"AddrinfoW.Family", Field, 1}, + {"AddrinfoW.Flags", Field, 1}, + {"AddrinfoW.Next", Field, 1}, + {"AddrinfoW.Protocol", Field, 1}, + {"AddrinfoW.Socktype", Field, 1}, + {"Adjtime", Func, 0}, + {"Adjtimex", Func, 0}, + {"AllThreadsSyscall", Func, 16}, + {"AllThreadsSyscall6", Func, 16}, + {"AttachLsf", Func, 0}, + {"B0", Const, 0}, + {"B1000000", Const, 0}, + {"B110", Const, 0}, + {"B115200", Const, 0}, + {"B1152000", Const, 0}, + {"B1200", Const, 0}, + {"B134", Const, 0}, + {"B14400", Const, 1}, + {"B150", Const, 0}, + {"B1500000", Const, 0}, + {"B1800", Const, 0}, + {"B19200", Const, 0}, + {"B200", Const, 0}, + {"B2000000", Const, 0}, + {"B230400", Const, 0}, + {"B2400", Const, 0}, + {"B2500000", Const, 0}, + {"B28800", Const, 1}, + {"B300", Const, 0}, + {"B3000000", Const, 0}, + {"B3500000", Const, 0}, + {"B38400", Const, 0}, + {"B4000000", Const, 0}, + {"B460800", Const, 0}, + {"B4800", Const, 0}, + {"B50", Const, 0}, + {"B500000", Const, 0}, + {"B57600", Const, 0}, + {"B576000", Const, 0}, + {"B600", Const, 0}, + {"B7200", Const, 1}, + {"B75", Const, 0}, + {"B76800", Const, 1}, + {"B921600", Const, 0}, + {"B9600", Const, 0}, + {"BASE_PROTOCOL", Const, 2}, + {"BIOCFEEDBACK", Const, 0}, + {"BIOCFLUSH", Const, 0}, + {"BIOCGBLEN", Const, 0}, + {"BIOCGDIRECTION", Const, 0}, + {"BIOCGDIRFILT", Const, 1}, + {"BIOCGDLT", Const, 0}, + {"BIOCGDLTLIST", Const, 0}, + {"BIOCGETBUFMODE", Const, 0}, + {"BIOCGETIF", Const, 0}, + {"BIOCGETZMAX", Const, 0}, + {"BIOCGFEEDBACK", Const, 1}, + {"BIOCGFILDROP", Const, 1}, + {"BIOCGHDRCMPLT", Const, 0}, + {"BIOCGRSIG", Const, 0}, + {"BIOCGRTIMEOUT", Const, 0}, + {"BIOCGSEESENT", Const, 0}, + {"BIOCGSTATS", Const, 0}, + {"BIOCGSTATSOLD", Const, 1}, + {"BIOCGTSTAMP", Const, 1}, + {"BIOCIMMEDIATE", Const, 0}, + {"BIOCLOCK", Const, 0}, + {"BIOCPROMISC", Const, 0}, + {"BIOCROTZBUF", Const, 0}, + {"BIOCSBLEN", Const, 0}, + {"BIOCSDIRECTION", Const, 0}, + {"BIOCSDIRFILT", Const, 1}, + {"BIOCSDLT", Const, 0}, + {"BIOCSETBUFMODE", Const, 0}, + {"BIOCSETF", Const, 0}, + {"BIOCSETFNR", Const, 0}, + {"BIOCSETIF", Const, 0}, + {"BIOCSETWF", Const, 0}, + {"BIOCSETZBUF", Const, 0}, + {"BIOCSFEEDBACK", Const, 1}, + {"BIOCSFILDROP", Const, 1}, + {"BIOCSHDRCMPLT", Const, 0}, + {"BIOCSRSIG", Const, 0}, + {"BIOCSRTIMEOUT", Const, 0}, + {"BIOCSSEESENT", Const, 0}, + {"BIOCSTCPF", Const, 1}, + {"BIOCSTSTAMP", Const, 1}, + {"BIOCSUDPF", Const, 1}, + {"BIOCVERSION", Const, 0}, + {"BPF_A", Const, 0}, + {"BPF_ABS", Const, 0}, + {"BPF_ADD", Const, 0}, + {"BPF_ALIGNMENT", Const, 0}, + {"BPF_ALIGNMENT32", Const, 1}, + {"BPF_ALU", Const, 0}, + {"BPF_AND", Const, 0}, + {"BPF_B", Const, 0}, + {"BPF_BUFMODE_BUFFER", Const, 0}, + {"BPF_BUFMODE_ZBUF", Const, 0}, + {"BPF_DFLTBUFSIZE", Const, 1}, + {"BPF_DIRECTION_IN", Const, 1}, + {"BPF_DIRECTION_OUT", Const, 1}, + {"BPF_DIV", Const, 0}, + {"BPF_H", Const, 0}, + {"BPF_IMM", Const, 0}, + {"BPF_IND", Const, 0}, + {"BPF_JA", Const, 0}, + {"BPF_JEQ", Const, 0}, + {"BPF_JGE", Const, 0}, + {"BPF_JGT", Const, 0}, + {"BPF_JMP", Const, 0}, + {"BPF_JSET", Const, 0}, + {"BPF_K", Const, 0}, + {"BPF_LD", Const, 0}, + {"BPF_LDX", Const, 0}, + {"BPF_LEN", Const, 0}, + {"BPF_LSH", Const, 0}, + {"BPF_MAJOR_VERSION", Const, 0}, + {"BPF_MAXBUFSIZE", Const, 0}, + {"BPF_MAXINSNS", Const, 0}, + {"BPF_MEM", Const, 0}, + {"BPF_MEMWORDS", Const, 0}, + {"BPF_MINBUFSIZE", Const, 0}, + {"BPF_MINOR_VERSION", Const, 0}, + {"BPF_MISC", Const, 0}, + {"BPF_MSH", Const, 0}, + {"BPF_MUL", Const, 0}, + {"BPF_NEG", Const, 0}, + {"BPF_OR", Const, 0}, + {"BPF_RELEASE", Const, 0}, + {"BPF_RET", Const, 0}, + {"BPF_RSH", Const, 0}, + {"BPF_ST", Const, 0}, + {"BPF_STX", Const, 0}, + {"BPF_SUB", Const, 0}, + {"BPF_TAX", Const, 0}, + {"BPF_TXA", Const, 0}, + {"BPF_T_BINTIME", Const, 1}, + {"BPF_T_BINTIME_FAST", Const, 1}, + {"BPF_T_BINTIME_MONOTONIC", Const, 1}, + {"BPF_T_BINTIME_MONOTONIC_FAST", Const, 1}, + {"BPF_T_FAST", Const, 1}, + {"BPF_T_FLAG_MASK", Const, 1}, + {"BPF_T_FORMAT_MASK", Const, 1}, + {"BPF_T_MICROTIME", Const, 1}, + {"BPF_T_MICROTIME_FAST", Const, 1}, + {"BPF_T_MICROTIME_MONOTONIC", Const, 1}, + {"BPF_T_MICROTIME_MONOTONIC_FAST", Const, 1}, + {"BPF_T_MONOTONIC", Const, 1}, + {"BPF_T_MONOTONIC_FAST", Const, 1}, + {"BPF_T_NANOTIME", Const, 1}, + {"BPF_T_NANOTIME_FAST", Const, 1}, + {"BPF_T_NANOTIME_MONOTONIC", Const, 1}, + {"BPF_T_NANOTIME_MONOTONIC_FAST", Const, 1}, + {"BPF_T_NONE", Const, 1}, + {"BPF_T_NORMAL", Const, 1}, + {"BPF_W", Const, 0}, + {"BPF_X", Const, 0}, + {"BRKINT", Const, 0}, + {"Bind", Func, 0}, + {"BindToDevice", Func, 0}, + {"BpfBuflen", Func, 0}, + {"BpfDatalink", Func, 0}, + {"BpfHdr", Type, 0}, + {"BpfHdr.Caplen", Field, 0}, + {"BpfHdr.Datalen", Field, 0}, + {"BpfHdr.Hdrlen", Field, 0}, + {"BpfHdr.Pad_cgo_0", Field, 0}, + {"BpfHdr.Tstamp", Field, 0}, + {"BpfHeadercmpl", Func, 0}, + {"BpfInsn", Type, 0}, + {"BpfInsn.Code", Field, 0}, + {"BpfInsn.Jf", Field, 0}, + {"BpfInsn.Jt", Field, 0}, + {"BpfInsn.K", Field, 0}, + {"BpfInterface", Func, 0}, + {"BpfJump", Func, 0}, + {"BpfProgram", Type, 0}, + {"BpfProgram.Insns", Field, 0}, + {"BpfProgram.Len", Field, 0}, + {"BpfProgram.Pad_cgo_0", Field, 0}, + {"BpfStat", Type, 0}, + {"BpfStat.Capt", Field, 2}, + {"BpfStat.Drop", Field, 0}, + {"BpfStat.Padding", Field, 2}, + {"BpfStat.Recv", Field, 0}, + {"BpfStats", Func, 0}, + {"BpfStmt", Func, 0}, + {"BpfTimeout", Func, 0}, + {"BpfTimeval", Type, 2}, + {"BpfTimeval.Sec", Field, 2}, + {"BpfTimeval.Usec", Field, 2}, + {"BpfVersion", Type, 0}, + {"BpfVersion.Major", Field, 0}, + {"BpfVersion.Minor", Field, 0}, + {"BpfZbuf", Type, 0}, + {"BpfZbuf.Bufa", Field, 0}, + {"BpfZbuf.Bufb", Field, 0}, + {"BpfZbuf.Buflen", Field, 0}, + {"BpfZbufHeader", Type, 0}, + {"BpfZbufHeader.Kernel_gen", Field, 0}, + {"BpfZbufHeader.Kernel_len", Field, 0}, + {"BpfZbufHeader.User_gen", Field, 0}, + {"BpfZbufHeader.X_bzh_pad", Field, 0}, + {"ByHandleFileInformation", Type, 0}, + {"ByHandleFileInformation.CreationTime", Field, 0}, + {"ByHandleFileInformation.FileAttributes", Field, 0}, + {"ByHandleFileInformation.FileIndexHigh", Field, 0}, + {"ByHandleFileInformation.FileIndexLow", Field, 0}, + {"ByHandleFileInformation.FileSizeHigh", Field, 0}, + {"ByHandleFileInformation.FileSizeLow", Field, 0}, + {"ByHandleFileInformation.LastAccessTime", Field, 0}, + {"ByHandleFileInformation.LastWriteTime", Field, 0}, + {"ByHandleFileInformation.NumberOfLinks", Field, 0}, + {"ByHandleFileInformation.VolumeSerialNumber", Field, 0}, + {"BytePtrFromString", Func, 1}, + {"ByteSliceFromString", Func, 1}, + {"CCR0_FLUSH", Const, 1}, + {"CERT_CHAIN_POLICY_AUTHENTICODE", Const, 0}, + {"CERT_CHAIN_POLICY_AUTHENTICODE_TS", Const, 0}, + {"CERT_CHAIN_POLICY_BASE", Const, 0}, + {"CERT_CHAIN_POLICY_BASIC_CONSTRAINTS", Const, 0}, + {"CERT_CHAIN_POLICY_EV", Const, 0}, + {"CERT_CHAIN_POLICY_MICROSOFT_ROOT", Const, 0}, + {"CERT_CHAIN_POLICY_NT_AUTH", Const, 0}, + {"CERT_CHAIN_POLICY_SSL", Const, 0}, + {"CERT_E_CN_NO_MATCH", Const, 0}, + {"CERT_E_EXPIRED", Const, 0}, + {"CERT_E_PURPOSE", Const, 0}, + {"CERT_E_ROLE", Const, 0}, + {"CERT_E_UNTRUSTEDROOT", Const, 0}, + {"CERT_STORE_ADD_ALWAYS", Const, 0}, + {"CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG", Const, 0}, + {"CERT_STORE_PROV_MEMORY", Const, 0}, + {"CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT", Const, 0}, + {"CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT", Const, 0}, + {"CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT", Const, 0}, + {"CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT", Const, 0}, + {"CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT", Const, 0}, + {"CERT_TRUST_INVALID_BASIC_CONSTRAINTS", Const, 0}, + {"CERT_TRUST_INVALID_EXTENSION", Const, 0}, + {"CERT_TRUST_INVALID_NAME_CONSTRAINTS", Const, 0}, + {"CERT_TRUST_INVALID_POLICY_CONSTRAINTS", Const, 0}, + {"CERT_TRUST_IS_CYCLIC", Const, 0}, + {"CERT_TRUST_IS_EXPLICIT_DISTRUST", Const, 0}, + {"CERT_TRUST_IS_NOT_SIGNATURE_VALID", Const, 0}, + {"CERT_TRUST_IS_NOT_TIME_VALID", Const, 0}, + {"CERT_TRUST_IS_NOT_VALID_FOR_USAGE", Const, 0}, + {"CERT_TRUST_IS_OFFLINE_REVOCATION", Const, 0}, + {"CERT_TRUST_IS_REVOKED", Const, 0}, + {"CERT_TRUST_IS_UNTRUSTED_ROOT", Const, 0}, + {"CERT_TRUST_NO_ERROR", Const, 0}, + {"CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY", Const, 0}, + {"CERT_TRUST_REVOCATION_STATUS_UNKNOWN", Const, 0}, + {"CFLUSH", Const, 1}, + {"CLOCAL", Const, 0}, + {"CLONE_CHILD_CLEARTID", Const, 2}, + {"CLONE_CHILD_SETTID", Const, 2}, + {"CLONE_CLEAR_SIGHAND", Const, 20}, + {"CLONE_CSIGNAL", Const, 3}, + {"CLONE_DETACHED", Const, 2}, + {"CLONE_FILES", Const, 2}, + {"CLONE_FS", Const, 2}, + {"CLONE_INTO_CGROUP", Const, 20}, + {"CLONE_IO", Const, 2}, + {"CLONE_NEWCGROUP", Const, 20}, + {"CLONE_NEWIPC", Const, 2}, + {"CLONE_NEWNET", Const, 2}, + {"CLONE_NEWNS", Const, 2}, + {"CLONE_NEWPID", Const, 2}, + {"CLONE_NEWTIME", Const, 20}, + {"CLONE_NEWUSER", Const, 2}, + {"CLONE_NEWUTS", Const, 2}, + {"CLONE_PARENT", Const, 2}, + {"CLONE_PARENT_SETTID", Const, 2}, + {"CLONE_PID", Const, 3}, + {"CLONE_PIDFD", Const, 20}, + {"CLONE_PTRACE", Const, 2}, + {"CLONE_SETTLS", Const, 2}, + {"CLONE_SIGHAND", Const, 2}, + {"CLONE_SYSVSEM", Const, 2}, + {"CLONE_THREAD", Const, 2}, + {"CLONE_UNTRACED", Const, 2}, + {"CLONE_VFORK", Const, 2}, + {"CLONE_VM", Const, 2}, + {"CPUID_CFLUSH", Const, 1}, + {"CREAD", Const, 0}, + {"CREATE_ALWAYS", Const, 0}, + {"CREATE_NEW", Const, 0}, + {"CREATE_NEW_PROCESS_GROUP", Const, 1}, + {"CREATE_UNICODE_ENVIRONMENT", Const, 0}, + {"CRYPT_DEFAULT_CONTAINER_OPTIONAL", Const, 0}, + {"CRYPT_DELETEKEYSET", Const, 0}, + {"CRYPT_MACHINE_KEYSET", Const, 0}, + {"CRYPT_NEWKEYSET", Const, 0}, + {"CRYPT_SILENT", Const, 0}, + {"CRYPT_VERIFYCONTEXT", Const, 0}, + {"CS5", Const, 0}, + {"CS6", Const, 0}, + {"CS7", Const, 0}, + {"CS8", Const, 0}, + {"CSIZE", Const, 0}, + {"CSTART", Const, 1}, + {"CSTATUS", Const, 1}, + {"CSTOP", Const, 1}, + {"CSTOPB", Const, 0}, + {"CSUSP", Const, 1}, + {"CTL_MAXNAME", Const, 0}, + {"CTL_NET", Const, 0}, + {"CTL_QUERY", Const, 1}, + {"CTRL_BREAK_EVENT", Const, 1}, + {"CTRL_CLOSE_EVENT", Const, 14}, + {"CTRL_C_EVENT", Const, 1}, + {"CTRL_LOGOFF_EVENT", Const, 14}, + {"CTRL_SHUTDOWN_EVENT", Const, 14}, + {"CancelIo", Func, 0}, + {"CancelIoEx", Func, 1}, + {"CertAddCertificateContextToStore", Func, 0}, + {"CertChainContext", Type, 0}, + {"CertChainContext.ChainCount", Field, 0}, + {"CertChainContext.Chains", Field, 0}, + {"CertChainContext.HasRevocationFreshnessTime", Field, 0}, + {"CertChainContext.LowerQualityChainCount", Field, 0}, + {"CertChainContext.LowerQualityChains", Field, 0}, + {"CertChainContext.RevocationFreshnessTime", Field, 0}, + {"CertChainContext.Size", Field, 0}, + {"CertChainContext.TrustStatus", Field, 0}, + {"CertChainElement", Type, 0}, + {"CertChainElement.ApplicationUsage", Field, 0}, + {"CertChainElement.CertContext", Field, 0}, + {"CertChainElement.ExtendedErrorInfo", Field, 0}, + {"CertChainElement.IssuanceUsage", Field, 0}, + {"CertChainElement.RevocationInfo", Field, 0}, + {"CertChainElement.Size", Field, 0}, + {"CertChainElement.TrustStatus", Field, 0}, + {"CertChainPara", Type, 0}, + {"CertChainPara.CacheResync", Field, 0}, + {"CertChainPara.CheckRevocationFreshnessTime", Field, 0}, + {"CertChainPara.RequestedUsage", Field, 0}, + {"CertChainPara.RequstedIssuancePolicy", Field, 0}, + {"CertChainPara.RevocationFreshnessTime", Field, 0}, + {"CertChainPara.Size", Field, 0}, + {"CertChainPara.URLRetrievalTimeout", Field, 0}, + {"CertChainPolicyPara", Type, 0}, + {"CertChainPolicyPara.ExtraPolicyPara", Field, 0}, + {"CertChainPolicyPara.Flags", Field, 0}, + {"CertChainPolicyPara.Size", Field, 0}, + {"CertChainPolicyStatus", Type, 0}, + {"CertChainPolicyStatus.ChainIndex", Field, 0}, + {"CertChainPolicyStatus.ElementIndex", Field, 0}, + {"CertChainPolicyStatus.Error", Field, 0}, + {"CertChainPolicyStatus.ExtraPolicyStatus", Field, 0}, + {"CertChainPolicyStatus.Size", Field, 0}, + {"CertCloseStore", Func, 0}, + {"CertContext", Type, 0}, + {"CertContext.CertInfo", Field, 0}, + {"CertContext.EncodedCert", Field, 0}, + {"CertContext.EncodingType", Field, 0}, + {"CertContext.Length", Field, 0}, + {"CertContext.Store", Field, 0}, + {"CertCreateCertificateContext", Func, 0}, + {"CertEnhKeyUsage", Type, 0}, + {"CertEnhKeyUsage.Length", Field, 0}, + {"CertEnhKeyUsage.UsageIdentifiers", Field, 0}, + {"CertEnumCertificatesInStore", Func, 0}, + {"CertFreeCertificateChain", Func, 0}, + {"CertFreeCertificateContext", Func, 0}, + {"CertGetCertificateChain", Func, 0}, + {"CertInfo", Type, 11}, + {"CertOpenStore", Func, 0}, + {"CertOpenSystemStore", Func, 0}, + {"CertRevocationCrlInfo", Type, 11}, + {"CertRevocationInfo", Type, 0}, + {"CertRevocationInfo.CrlInfo", Field, 0}, + {"CertRevocationInfo.FreshnessTime", Field, 0}, + {"CertRevocationInfo.HasFreshnessTime", Field, 0}, + {"CertRevocationInfo.OidSpecificInfo", Field, 0}, + {"CertRevocationInfo.RevocationOid", Field, 0}, + {"CertRevocationInfo.RevocationResult", Field, 0}, + {"CertRevocationInfo.Size", Field, 0}, + {"CertSimpleChain", Type, 0}, + {"CertSimpleChain.Elements", Field, 0}, + {"CertSimpleChain.HasRevocationFreshnessTime", Field, 0}, + {"CertSimpleChain.NumElements", Field, 0}, + {"CertSimpleChain.RevocationFreshnessTime", Field, 0}, + {"CertSimpleChain.Size", Field, 0}, + {"CertSimpleChain.TrustListInfo", Field, 0}, + {"CertSimpleChain.TrustStatus", Field, 0}, + {"CertTrustListInfo", Type, 11}, + {"CertTrustStatus", Type, 0}, + {"CertTrustStatus.ErrorStatus", Field, 0}, + {"CertTrustStatus.InfoStatus", Field, 0}, + {"CertUsageMatch", Type, 0}, + {"CertUsageMatch.Type", Field, 0}, + {"CertUsageMatch.Usage", Field, 0}, + {"CertVerifyCertificateChainPolicy", Func, 0}, + {"Chdir", Func, 0}, + {"CheckBpfVersion", Func, 0}, + {"Chflags", Func, 0}, + {"Chmod", Func, 0}, + {"Chown", Func, 0}, + {"Chroot", Func, 0}, + {"Clearenv", Func, 0}, + {"Close", Func, 0}, + {"CloseHandle", Func, 0}, + {"CloseOnExec", Func, 0}, + {"Closesocket", Func, 0}, + {"CmsgLen", Func, 0}, + {"CmsgSpace", Func, 0}, + {"Cmsghdr", Type, 0}, + {"Cmsghdr.Len", Field, 0}, + {"Cmsghdr.Level", Field, 0}, + {"Cmsghdr.Type", Field, 0}, + {"Cmsghdr.X__cmsg_data", Field, 0}, + {"CommandLineToArgv", Func, 0}, + {"ComputerName", Func, 0}, + {"Conn", Type, 9}, + {"Connect", Func, 0}, + {"ConnectEx", Func, 1}, + {"ConvertSidToStringSid", Func, 0}, + {"ConvertStringSidToSid", Func, 0}, + {"CopySid", Func, 0}, + {"Creat", Func, 0}, + {"CreateDirectory", Func, 0}, + {"CreateFile", Func, 0}, + {"CreateFileMapping", Func, 0}, + {"CreateHardLink", Func, 4}, + {"CreateIoCompletionPort", Func, 0}, + {"CreatePipe", Func, 0}, + {"CreateProcess", Func, 0}, + {"CreateProcessAsUser", Func, 10}, + {"CreateSymbolicLink", Func, 4}, + {"CreateToolhelp32Snapshot", Func, 4}, + {"Credential", Type, 0}, + {"Credential.Gid", Field, 0}, + {"Credential.Groups", Field, 0}, + {"Credential.NoSetGroups", Field, 9}, + {"Credential.Uid", Field, 0}, + {"CryptAcquireContext", Func, 0}, + {"CryptGenRandom", Func, 0}, + {"CryptReleaseContext", Func, 0}, + {"DIOCBSFLUSH", Const, 1}, + {"DIOCOSFPFLUSH", Const, 1}, + {"DLL", Type, 0}, + {"DLL.Handle", Field, 0}, + {"DLL.Name", Field, 0}, + {"DLLError", Type, 0}, + {"DLLError.Err", Field, 0}, + {"DLLError.Msg", Field, 0}, + {"DLLError.ObjName", Field, 0}, + {"DLT_A429", Const, 0}, + {"DLT_A653_ICM", Const, 0}, + {"DLT_AIRONET_HEADER", Const, 0}, + {"DLT_AOS", Const, 1}, + {"DLT_APPLE_IP_OVER_IEEE1394", Const, 0}, + {"DLT_ARCNET", Const, 0}, + {"DLT_ARCNET_LINUX", Const, 0}, + {"DLT_ATM_CLIP", Const, 0}, + {"DLT_ATM_RFC1483", Const, 0}, + {"DLT_AURORA", Const, 0}, + {"DLT_AX25", Const, 0}, + {"DLT_AX25_KISS", Const, 0}, + {"DLT_BACNET_MS_TP", Const, 0}, + {"DLT_BLUETOOTH_HCI_H4", Const, 0}, + {"DLT_BLUETOOTH_HCI_H4_WITH_PHDR", Const, 0}, + {"DLT_CAN20B", Const, 0}, + {"DLT_CAN_SOCKETCAN", Const, 1}, + {"DLT_CHAOS", Const, 0}, + {"DLT_CHDLC", Const, 0}, + {"DLT_CISCO_IOS", Const, 0}, + {"DLT_C_HDLC", Const, 0}, + {"DLT_C_HDLC_WITH_DIR", Const, 0}, + {"DLT_DBUS", Const, 1}, + {"DLT_DECT", Const, 1}, + {"DLT_DOCSIS", Const, 0}, + {"DLT_DVB_CI", Const, 1}, + {"DLT_ECONET", Const, 0}, + {"DLT_EN10MB", Const, 0}, + {"DLT_EN3MB", Const, 0}, + {"DLT_ENC", Const, 0}, + {"DLT_ERF", Const, 0}, + {"DLT_ERF_ETH", Const, 0}, + {"DLT_ERF_POS", Const, 0}, + {"DLT_FC_2", Const, 1}, + {"DLT_FC_2_WITH_FRAME_DELIMS", Const, 1}, + {"DLT_FDDI", Const, 0}, + {"DLT_FLEXRAY", Const, 0}, + {"DLT_FRELAY", Const, 0}, + {"DLT_FRELAY_WITH_DIR", Const, 0}, + {"DLT_GCOM_SERIAL", Const, 0}, + {"DLT_GCOM_T1E1", Const, 0}, + {"DLT_GPF_F", Const, 0}, + {"DLT_GPF_T", Const, 0}, + {"DLT_GPRS_LLC", Const, 0}, + {"DLT_GSMTAP_ABIS", Const, 1}, + {"DLT_GSMTAP_UM", Const, 1}, + {"DLT_HDLC", Const, 1}, + {"DLT_HHDLC", Const, 0}, + {"DLT_HIPPI", Const, 1}, + {"DLT_IBM_SN", Const, 0}, + {"DLT_IBM_SP", Const, 0}, + {"DLT_IEEE802", Const, 0}, + {"DLT_IEEE802_11", Const, 0}, + {"DLT_IEEE802_11_RADIO", Const, 0}, + {"DLT_IEEE802_11_RADIO_AVS", Const, 0}, + {"DLT_IEEE802_15_4", Const, 0}, + {"DLT_IEEE802_15_4_LINUX", Const, 0}, + {"DLT_IEEE802_15_4_NOFCS", Const, 1}, + {"DLT_IEEE802_15_4_NONASK_PHY", Const, 0}, + {"DLT_IEEE802_16_MAC_CPS", Const, 0}, + {"DLT_IEEE802_16_MAC_CPS_RADIO", Const, 0}, + {"DLT_IPFILTER", Const, 0}, + {"DLT_IPMB", Const, 0}, + {"DLT_IPMB_LINUX", Const, 0}, + {"DLT_IPNET", Const, 1}, + {"DLT_IPOIB", Const, 1}, + {"DLT_IPV4", Const, 1}, + {"DLT_IPV6", Const, 1}, + {"DLT_IP_OVER_FC", Const, 0}, + {"DLT_JUNIPER_ATM1", Const, 0}, + {"DLT_JUNIPER_ATM2", Const, 0}, + {"DLT_JUNIPER_ATM_CEMIC", Const, 1}, + {"DLT_JUNIPER_CHDLC", Const, 0}, + {"DLT_JUNIPER_ES", Const, 0}, + {"DLT_JUNIPER_ETHER", Const, 0}, + {"DLT_JUNIPER_FIBRECHANNEL", Const, 1}, + {"DLT_JUNIPER_FRELAY", Const, 0}, + {"DLT_JUNIPER_GGSN", Const, 0}, + {"DLT_JUNIPER_ISM", Const, 0}, + {"DLT_JUNIPER_MFR", Const, 0}, + {"DLT_JUNIPER_MLFR", Const, 0}, + {"DLT_JUNIPER_MLPPP", Const, 0}, + {"DLT_JUNIPER_MONITOR", Const, 0}, + {"DLT_JUNIPER_PIC_PEER", Const, 0}, + {"DLT_JUNIPER_PPP", Const, 0}, + {"DLT_JUNIPER_PPPOE", Const, 0}, + {"DLT_JUNIPER_PPPOE_ATM", Const, 0}, + {"DLT_JUNIPER_SERVICES", Const, 0}, + {"DLT_JUNIPER_SRX_E2E", Const, 1}, + {"DLT_JUNIPER_ST", Const, 0}, + {"DLT_JUNIPER_VP", Const, 0}, + {"DLT_JUNIPER_VS", Const, 1}, + {"DLT_LAPB_WITH_DIR", Const, 0}, + {"DLT_LAPD", Const, 0}, + {"DLT_LIN", Const, 0}, + {"DLT_LINUX_EVDEV", Const, 1}, + {"DLT_LINUX_IRDA", Const, 0}, + {"DLT_LINUX_LAPD", Const, 0}, + {"DLT_LINUX_PPP_WITHDIRECTION", Const, 0}, + {"DLT_LINUX_SLL", Const, 0}, + {"DLT_LOOP", Const, 0}, + {"DLT_LTALK", Const, 0}, + {"DLT_MATCHING_MAX", Const, 1}, + {"DLT_MATCHING_MIN", Const, 1}, + {"DLT_MFR", Const, 0}, + {"DLT_MOST", Const, 0}, + {"DLT_MPEG_2_TS", Const, 1}, + {"DLT_MPLS", Const, 1}, + {"DLT_MTP2", Const, 0}, + {"DLT_MTP2_WITH_PHDR", Const, 0}, + {"DLT_MTP3", Const, 0}, + {"DLT_MUX27010", Const, 1}, + {"DLT_NETANALYZER", Const, 1}, + {"DLT_NETANALYZER_TRANSPARENT", Const, 1}, + {"DLT_NFC_LLCP", Const, 1}, + {"DLT_NFLOG", Const, 1}, + {"DLT_NG40", Const, 1}, + {"DLT_NULL", Const, 0}, + {"DLT_PCI_EXP", Const, 0}, + {"DLT_PFLOG", Const, 0}, + {"DLT_PFSYNC", Const, 0}, + {"DLT_PPI", Const, 0}, + {"DLT_PPP", Const, 0}, + {"DLT_PPP_BSDOS", Const, 0}, + {"DLT_PPP_ETHER", Const, 0}, + {"DLT_PPP_PPPD", Const, 0}, + {"DLT_PPP_SERIAL", Const, 0}, + {"DLT_PPP_WITH_DIR", Const, 0}, + {"DLT_PPP_WITH_DIRECTION", Const, 0}, + {"DLT_PRISM_HEADER", Const, 0}, + {"DLT_PRONET", Const, 0}, + {"DLT_RAIF1", Const, 0}, + {"DLT_RAW", Const, 0}, + {"DLT_RAWAF_MASK", Const, 1}, + {"DLT_RIO", Const, 0}, + {"DLT_SCCP", Const, 0}, + {"DLT_SITA", Const, 0}, + {"DLT_SLIP", Const, 0}, + {"DLT_SLIP_BSDOS", Const, 0}, + {"DLT_STANAG_5066_D_PDU", Const, 1}, + {"DLT_SUNATM", Const, 0}, + {"DLT_SYMANTEC_FIREWALL", Const, 0}, + {"DLT_TZSP", Const, 0}, + {"DLT_USB", Const, 0}, + {"DLT_USB_LINUX", Const, 0}, + {"DLT_USB_LINUX_MMAPPED", Const, 1}, + {"DLT_USER0", Const, 0}, + {"DLT_USER1", Const, 0}, + {"DLT_USER10", Const, 0}, + {"DLT_USER11", Const, 0}, + {"DLT_USER12", Const, 0}, + {"DLT_USER13", Const, 0}, + {"DLT_USER14", Const, 0}, + {"DLT_USER15", Const, 0}, + {"DLT_USER2", Const, 0}, + {"DLT_USER3", Const, 0}, + {"DLT_USER4", Const, 0}, + {"DLT_USER5", Const, 0}, + {"DLT_USER6", Const, 0}, + {"DLT_USER7", Const, 0}, + {"DLT_USER8", Const, 0}, + {"DLT_USER9", Const, 0}, + {"DLT_WIHART", Const, 1}, + {"DLT_X2E_SERIAL", Const, 0}, + {"DLT_X2E_XORAYA", Const, 0}, + {"DNSMXData", Type, 0}, + {"DNSMXData.NameExchange", Field, 0}, + {"DNSMXData.Pad", Field, 0}, + {"DNSMXData.Preference", Field, 0}, + {"DNSPTRData", Type, 0}, + {"DNSPTRData.Host", Field, 0}, + {"DNSRecord", Type, 0}, + {"DNSRecord.Data", Field, 0}, + {"DNSRecord.Dw", Field, 0}, + {"DNSRecord.Length", Field, 0}, + {"DNSRecord.Name", Field, 0}, + {"DNSRecord.Next", Field, 0}, + {"DNSRecord.Reserved", Field, 0}, + {"DNSRecord.Ttl", Field, 0}, + {"DNSRecord.Type", Field, 0}, + {"DNSSRVData", Type, 0}, + {"DNSSRVData.Pad", Field, 0}, + {"DNSSRVData.Port", Field, 0}, + {"DNSSRVData.Priority", Field, 0}, + {"DNSSRVData.Target", Field, 0}, + {"DNSSRVData.Weight", Field, 0}, + {"DNSTXTData", Type, 0}, + {"DNSTXTData.StringArray", Field, 0}, + {"DNSTXTData.StringCount", Field, 0}, + {"DNS_INFO_NO_RECORDS", Const, 4}, + {"DNS_TYPE_A", Const, 0}, + {"DNS_TYPE_A6", Const, 0}, + {"DNS_TYPE_AAAA", Const, 0}, + {"DNS_TYPE_ADDRS", Const, 0}, + {"DNS_TYPE_AFSDB", Const, 0}, + {"DNS_TYPE_ALL", Const, 0}, + {"DNS_TYPE_ANY", Const, 0}, + {"DNS_TYPE_ATMA", Const, 0}, + {"DNS_TYPE_AXFR", Const, 0}, + {"DNS_TYPE_CERT", Const, 0}, + {"DNS_TYPE_CNAME", Const, 0}, + {"DNS_TYPE_DHCID", Const, 0}, + {"DNS_TYPE_DNAME", Const, 0}, + {"DNS_TYPE_DNSKEY", Const, 0}, + {"DNS_TYPE_DS", Const, 0}, + {"DNS_TYPE_EID", Const, 0}, + {"DNS_TYPE_GID", Const, 0}, + {"DNS_TYPE_GPOS", Const, 0}, + {"DNS_TYPE_HINFO", Const, 0}, + {"DNS_TYPE_ISDN", Const, 0}, + {"DNS_TYPE_IXFR", Const, 0}, + {"DNS_TYPE_KEY", Const, 0}, + {"DNS_TYPE_KX", Const, 0}, + {"DNS_TYPE_LOC", Const, 0}, + {"DNS_TYPE_MAILA", Const, 0}, + {"DNS_TYPE_MAILB", Const, 0}, + {"DNS_TYPE_MB", Const, 0}, + {"DNS_TYPE_MD", Const, 0}, + {"DNS_TYPE_MF", Const, 0}, + {"DNS_TYPE_MG", Const, 0}, + {"DNS_TYPE_MINFO", Const, 0}, + {"DNS_TYPE_MR", Const, 0}, + {"DNS_TYPE_MX", Const, 0}, + {"DNS_TYPE_NAPTR", Const, 0}, + {"DNS_TYPE_NBSTAT", Const, 0}, + {"DNS_TYPE_NIMLOC", Const, 0}, + {"DNS_TYPE_NS", Const, 0}, + {"DNS_TYPE_NSAP", Const, 0}, + {"DNS_TYPE_NSAPPTR", Const, 0}, + {"DNS_TYPE_NSEC", Const, 0}, + {"DNS_TYPE_NULL", Const, 0}, + {"DNS_TYPE_NXT", Const, 0}, + {"DNS_TYPE_OPT", Const, 0}, + {"DNS_TYPE_PTR", Const, 0}, + {"DNS_TYPE_PX", Const, 0}, + {"DNS_TYPE_RP", Const, 0}, + {"DNS_TYPE_RRSIG", Const, 0}, + {"DNS_TYPE_RT", Const, 0}, + {"DNS_TYPE_SIG", Const, 0}, + {"DNS_TYPE_SINK", Const, 0}, + {"DNS_TYPE_SOA", Const, 0}, + {"DNS_TYPE_SRV", Const, 0}, + {"DNS_TYPE_TEXT", Const, 0}, + {"DNS_TYPE_TKEY", Const, 0}, + {"DNS_TYPE_TSIG", Const, 0}, + {"DNS_TYPE_UID", Const, 0}, + {"DNS_TYPE_UINFO", Const, 0}, + {"DNS_TYPE_UNSPEC", Const, 0}, + {"DNS_TYPE_WINS", Const, 0}, + {"DNS_TYPE_WINSR", Const, 0}, + {"DNS_TYPE_WKS", Const, 0}, + {"DNS_TYPE_X25", Const, 0}, + {"DT_BLK", Const, 0}, + {"DT_CHR", Const, 0}, + {"DT_DIR", Const, 0}, + {"DT_FIFO", Const, 0}, + {"DT_LNK", Const, 0}, + {"DT_REG", Const, 0}, + {"DT_SOCK", Const, 0}, + {"DT_UNKNOWN", Const, 0}, + {"DT_WHT", Const, 0}, + {"DUPLICATE_CLOSE_SOURCE", Const, 0}, + {"DUPLICATE_SAME_ACCESS", Const, 0}, + {"DeleteFile", Func, 0}, + {"DetachLsf", Func, 0}, + {"DeviceIoControl", Func, 4}, + {"Dirent", Type, 0}, + {"Dirent.Fileno", Field, 0}, + {"Dirent.Ino", Field, 0}, + {"Dirent.Name", Field, 0}, + {"Dirent.Namlen", Field, 0}, + {"Dirent.Off", Field, 0}, + {"Dirent.Pad0", Field, 12}, + {"Dirent.Pad1", Field, 12}, + {"Dirent.Pad_cgo_0", Field, 0}, + {"Dirent.Reclen", Field, 0}, + {"Dirent.Seekoff", Field, 0}, + {"Dirent.Type", Field, 0}, + {"Dirent.X__d_padding", Field, 3}, + {"DnsNameCompare", Func, 4}, + {"DnsQuery", Func, 0}, + {"DnsRecordListFree", Func, 0}, + {"DnsSectionAdditional", Const, 4}, + {"DnsSectionAnswer", Const, 4}, + {"DnsSectionAuthority", Const, 4}, + {"DnsSectionQuestion", Const, 4}, + {"Dup", Func, 0}, + {"Dup2", Func, 0}, + {"Dup3", Func, 2}, + {"DuplicateHandle", Func, 0}, + {"E2BIG", Const, 0}, + {"EACCES", Const, 0}, + {"EADDRINUSE", Const, 0}, + {"EADDRNOTAVAIL", Const, 0}, + {"EADV", Const, 0}, + {"EAFNOSUPPORT", Const, 0}, + {"EAGAIN", Const, 0}, + {"EALREADY", Const, 0}, + {"EAUTH", Const, 0}, + {"EBADARCH", Const, 0}, + {"EBADE", Const, 0}, + {"EBADEXEC", Const, 0}, + {"EBADF", Const, 0}, + {"EBADFD", Const, 0}, + {"EBADMACHO", Const, 0}, + {"EBADMSG", Const, 0}, + {"EBADR", Const, 0}, + {"EBADRPC", Const, 0}, + {"EBADRQC", Const, 0}, + {"EBADSLT", Const, 0}, + {"EBFONT", Const, 0}, + {"EBUSY", Const, 0}, + {"ECANCELED", Const, 0}, + {"ECAPMODE", Const, 1}, + {"ECHILD", Const, 0}, + {"ECHO", Const, 0}, + {"ECHOCTL", Const, 0}, + {"ECHOE", Const, 0}, + {"ECHOK", Const, 0}, + {"ECHOKE", Const, 0}, + {"ECHONL", Const, 0}, + {"ECHOPRT", Const, 0}, + {"ECHRNG", Const, 0}, + {"ECOMM", Const, 0}, + {"ECONNABORTED", Const, 0}, + {"ECONNREFUSED", Const, 0}, + {"ECONNRESET", Const, 0}, + {"EDEADLK", Const, 0}, + {"EDEADLOCK", Const, 0}, + {"EDESTADDRREQ", Const, 0}, + {"EDEVERR", Const, 0}, + {"EDOM", Const, 0}, + {"EDOOFUS", Const, 0}, + {"EDOTDOT", Const, 0}, + {"EDQUOT", Const, 0}, + {"EEXIST", Const, 0}, + {"EFAULT", Const, 0}, + {"EFBIG", Const, 0}, + {"EFER_LMA", Const, 1}, + {"EFER_LME", Const, 1}, + {"EFER_NXE", Const, 1}, + {"EFER_SCE", Const, 1}, + {"EFTYPE", Const, 0}, + {"EHOSTDOWN", Const, 0}, + {"EHOSTUNREACH", Const, 0}, + {"EHWPOISON", Const, 0}, + {"EIDRM", Const, 0}, + {"EILSEQ", Const, 0}, + {"EINPROGRESS", Const, 0}, + {"EINTR", Const, 0}, + {"EINVAL", Const, 0}, + {"EIO", Const, 0}, + {"EIPSEC", Const, 1}, + {"EISCONN", Const, 0}, + {"EISDIR", Const, 0}, + {"EISNAM", Const, 0}, + {"EKEYEXPIRED", Const, 0}, + {"EKEYREJECTED", Const, 0}, + {"EKEYREVOKED", Const, 0}, + {"EL2HLT", Const, 0}, + {"EL2NSYNC", Const, 0}, + {"EL3HLT", Const, 0}, + {"EL3RST", Const, 0}, + {"ELAST", Const, 0}, + {"ELF_NGREG", Const, 0}, + {"ELF_PRARGSZ", Const, 0}, + {"ELIBACC", Const, 0}, + {"ELIBBAD", Const, 0}, + {"ELIBEXEC", Const, 0}, + {"ELIBMAX", Const, 0}, + {"ELIBSCN", Const, 0}, + {"ELNRNG", Const, 0}, + {"ELOOP", Const, 0}, + {"EMEDIUMTYPE", Const, 0}, + {"EMFILE", Const, 0}, + {"EMLINK", Const, 0}, + {"EMSGSIZE", Const, 0}, + {"EMT_TAGOVF", Const, 1}, + {"EMULTIHOP", Const, 0}, + {"EMUL_ENABLED", Const, 1}, + {"EMUL_LINUX", Const, 1}, + {"EMUL_LINUX32", Const, 1}, + {"EMUL_MAXID", Const, 1}, + {"EMUL_NATIVE", Const, 1}, + {"ENAMETOOLONG", Const, 0}, + {"ENAVAIL", Const, 0}, + {"ENDRUNDISC", Const, 1}, + {"ENEEDAUTH", Const, 0}, + {"ENETDOWN", Const, 0}, + {"ENETRESET", Const, 0}, + {"ENETUNREACH", Const, 0}, + {"ENFILE", Const, 0}, + {"ENOANO", Const, 0}, + {"ENOATTR", Const, 0}, + {"ENOBUFS", Const, 0}, + {"ENOCSI", Const, 0}, + {"ENODATA", Const, 0}, + {"ENODEV", Const, 0}, + {"ENOENT", Const, 0}, + {"ENOEXEC", Const, 0}, + {"ENOKEY", Const, 0}, + {"ENOLCK", Const, 0}, + {"ENOLINK", Const, 0}, + {"ENOMEDIUM", Const, 0}, + {"ENOMEM", Const, 0}, + {"ENOMSG", Const, 0}, + {"ENONET", Const, 0}, + {"ENOPKG", Const, 0}, + {"ENOPOLICY", Const, 0}, + {"ENOPROTOOPT", Const, 0}, + {"ENOSPC", Const, 0}, + {"ENOSR", Const, 0}, + {"ENOSTR", Const, 0}, + {"ENOSYS", Const, 0}, + {"ENOTBLK", Const, 0}, + {"ENOTCAPABLE", Const, 0}, + {"ENOTCONN", Const, 0}, + {"ENOTDIR", Const, 0}, + {"ENOTEMPTY", Const, 0}, + {"ENOTNAM", Const, 0}, + {"ENOTRECOVERABLE", Const, 0}, + {"ENOTSOCK", Const, 0}, + {"ENOTSUP", Const, 0}, + {"ENOTTY", Const, 0}, + {"ENOTUNIQ", Const, 0}, + {"ENXIO", Const, 0}, + {"EN_SW_CTL_INF", Const, 1}, + {"EN_SW_CTL_PREC", Const, 1}, + {"EN_SW_CTL_ROUND", Const, 1}, + {"EN_SW_DATACHAIN", Const, 1}, + {"EN_SW_DENORM", Const, 1}, + {"EN_SW_INVOP", Const, 1}, + {"EN_SW_OVERFLOW", Const, 1}, + {"EN_SW_PRECLOSS", Const, 1}, + {"EN_SW_UNDERFLOW", Const, 1}, + {"EN_SW_ZERODIV", Const, 1}, + {"EOPNOTSUPP", Const, 0}, + {"EOVERFLOW", Const, 0}, + {"EOWNERDEAD", Const, 0}, + {"EPERM", Const, 0}, + {"EPFNOSUPPORT", Const, 0}, + {"EPIPE", Const, 0}, + {"EPOLLERR", Const, 0}, + {"EPOLLET", Const, 0}, + {"EPOLLHUP", Const, 0}, + {"EPOLLIN", Const, 0}, + {"EPOLLMSG", Const, 0}, + {"EPOLLONESHOT", Const, 0}, + {"EPOLLOUT", Const, 0}, + {"EPOLLPRI", Const, 0}, + {"EPOLLRDBAND", Const, 0}, + {"EPOLLRDHUP", Const, 0}, + {"EPOLLRDNORM", Const, 0}, + {"EPOLLWRBAND", Const, 0}, + {"EPOLLWRNORM", Const, 0}, + {"EPOLL_CLOEXEC", Const, 0}, + {"EPOLL_CTL_ADD", Const, 0}, + {"EPOLL_CTL_DEL", Const, 0}, + {"EPOLL_CTL_MOD", Const, 0}, + {"EPOLL_NONBLOCK", Const, 0}, + {"EPROCLIM", Const, 0}, + {"EPROCUNAVAIL", Const, 0}, + {"EPROGMISMATCH", Const, 0}, + {"EPROGUNAVAIL", Const, 0}, + {"EPROTO", Const, 0}, + {"EPROTONOSUPPORT", Const, 0}, + {"EPROTOTYPE", Const, 0}, + {"EPWROFF", Const, 0}, + {"EQFULL", Const, 16}, + {"ERANGE", Const, 0}, + {"EREMCHG", Const, 0}, + {"EREMOTE", Const, 0}, + {"EREMOTEIO", Const, 0}, + {"ERESTART", Const, 0}, + {"ERFKILL", Const, 0}, + {"EROFS", Const, 0}, + {"ERPCMISMATCH", Const, 0}, + {"ERROR_ACCESS_DENIED", Const, 0}, + {"ERROR_ALREADY_EXISTS", Const, 0}, + {"ERROR_BROKEN_PIPE", Const, 0}, + {"ERROR_BUFFER_OVERFLOW", Const, 0}, + {"ERROR_DIR_NOT_EMPTY", Const, 8}, + {"ERROR_ENVVAR_NOT_FOUND", Const, 0}, + {"ERROR_FILE_EXISTS", Const, 0}, + {"ERROR_FILE_NOT_FOUND", Const, 0}, + {"ERROR_HANDLE_EOF", Const, 2}, + {"ERROR_INSUFFICIENT_BUFFER", Const, 0}, + {"ERROR_IO_PENDING", Const, 0}, + {"ERROR_MOD_NOT_FOUND", Const, 0}, + {"ERROR_MORE_DATA", Const, 3}, + {"ERROR_NETNAME_DELETED", Const, 3}, + {"ERROR_NOT_FOUND", Const, 1}, + {"ERROR_NO_MORE_FILES", Const, 0}, + {"ERROR_OPERATION_ABORTED", Const, 0}, + {"ERROR_PATH_NOT_FOUND", Const, 0}, + {"ERROR_PRIVILEGE_NOT_HELD", Const, 4}, + {"ERROR_PROC_NOT_FOUND", Const, 0}, + {"ESHLIBVERS", Const, 0}, + {"ESHUTDOWN", Const, 0}, + {"ESOCKTNOSUPPORT", Const, 0}, + {"ESPIPE", Const, 0}, + {"ESRCH", Const, 0}, + {"ESRMNT", Const, 0}, + {"ESTALE", Const, 0}, + {"ESTRPIPE", Const, 0}, + {"ETHERCAP_JUMBO_MTU", Const, 1}, + {"ETHERCAP_VLAN_HWTAGGING", Const, 1}, + {"ETHERCAP_VLAN_MTU", Const, 1}, + {"ETHERMIN", Const, 1}, + {"ETHERMTU", Const, 1}, + {"ETHERMTU_JUMBO", Const, 1}, + {"ETHERTYPE_8023", Const, 1}, + {"ETHERTYPE_AARP", Const, 1}, + {"ETHERTYPE_ACCTON", Const, 1}, + {"ETHERTYPE_AEONIC", Const, 1}, + {"ETHERTYPE_ALPHA", Const, 1}, + {"ETHERTYPE_AMBER", Const, 1}, + {"ETHERTYPE_AMOEBA", Const, 1}, + {"ETHERTYPE_AOE", Const, 1}, + {"ETHERTYPE_APOLLO", Const, 1}, + {"ETHERTYPE_APOLLODOMAIN", Const, 1}, + {"ETHERTYPE_APPLETALK", Const, 1}, + {"ETHERTYPE_APPLITEK", Const, 1}, + {"ETHERTYPE_ARGONAUT", Const, 1}, + {"ETHERTYPE_ARP", Const, 1}, + {"ETHERTYPE_AT", Const, 1}, + {"ETHERTYPE_ATALK", Const, 1}, + {"ETHERTYPE_ATOMIC", Const, 1}, + {"ETHERTYPE_ATT", Const, 1}, + {"ETHERTYPE_ATTSTANFORD", Const, 1}, + {"ETHERTYPE_AUTOPHON", Const, 1}, + {"ETHERTYPE_AXIS", Const, 1}, + {"ETHERTYPE_BCLOOP", Const, 1}, + {"ETHERTYPE_BOFL", Const, 1}, + {"ETHERTYPE_CABLETRON", Const, 1}, + {"ETHERTYPE_CHAOS", Const, 1}, + {"ETHERTYPE_COMDESIGN", Const, 1}, + {"ETHERTYPE_COMPUGRAPHIC", Const, 1}, + {"ETHERTYPE_COUNTERPOINT", Const, 1}, + {"ETHERTYPE_CRONUS", Const, 1}, + {"ETHERTYPE_CRONUSVLN", Const, 1}, + {"ETHERTYPE_DCA", Const, 1}, + {"ETHERTYPE_DDE", Const, 1}, + {"ETHERTYPE_DEBNI", Const, 1}, + {"ETHERTYPE_DECAM", Const, 1}, + {"ETHERTYPE_DECCUST", Const, 1}, + {"ETHERTYPE_DECDIAG", Const, 1}, + {"ETHERTYPE_DECDNS", Const, 1}, + {"ETHERTYPE_DECDTS", Const, 1}, + {"ETHERTYPE_DECEXPER", Const, 1}, + {"ETHERTYPE_DECLAST", Const, 1}, + {"ETHERTYPE_DECLTM", Const, 1}, + {"ETHERTYPE_DECMUMPS", Const, 1}, + {"ETHERTYPE_DECNETBIOS", Const, 1}, + {"ETHERTYPE_DELTACON", Const, 1}, + {"ETHERTYPE_DIDDLE", Const, 1}, + {"ETHERTYPE_DLOG1", Const, 1}, + {"ETHERTYPE_DLOG2", Const, 1}, + {"ETHERTYPE_DN", Const, 1}, + {"ETHERTYPE_DOGFIGHT", Const, 1}, + {"ETHERTYPE_DSMD", Const, 1}, + {"ETHERTYPE_ECMA", Const, 1}, + {"ETHERTYPE_ENCRYPT", Const, 1}, + {"ETHERTYPE_ES", Const, 1}, + {"ETHERTYPE_EXCELAN", Const, 1}, + {"ETHERTYPE_EXPERDATA", Const, 1}, + {"ETHERTYPE_FLIP", Const, 1}, + {"ETHERTYPE_FLOWCONTROL", Const, 1}, + {"ETHERTYPE_FRARP", Const, 1}, + {"ETHERTYPE_GENDYN", Const, 1}, + {"ETHERTYPE_HAYES", Const, 1}, + {"ETHERTYPE_HIPPI_FP", Const, 1}, + {"ETHERTYPE_HITACHI", Const, 1}, + {"ETHERTYPE_HP", Const, 1}, + {"ETHERTYPE_IEEEPUP", Const, 1}, + {"ETHERTYPE_IEEEPUPAT", Const, 1}, + {"ETHERTYPE_IMLBL", Const, 1}, + {"ETHERTYPE_IMLBLDIAG", Const, 1}, + {"ETHERTYPE_IP", Const, 1}, + {"ETHERTYPE_IPAS", Const, 1}, + {"ETHERTYPE_IPV6", Const, 1}, + {"ETHERTYPE_IPX", Const, 1}, + {"ETHERTYPE_IPXNEW", Const, 1}, + {"ETHERTYPE_KALPANA", Const, 1}, + {"ETHERTYPE_LANBRIDGE", Const, 1}, + {"ETHERTYPE_LANPROBE", Const, 1}, + {"ETHERTYPE_LAT", Const, 1}, + {"ETHERTYPE_LBACK", Const, 1}, + {"ETHERTYPE_LITTLE", Const, 1}, + {"ETHERTYPE_LLDP", Const, 1}, + {"ETHERTYPE_LOGICRAFT", Const, 1}, + {"ETHERTYPE_LOOPBACK", Const, 1}, + {"ETHERTYPE_MATRA", Const, 1}, + {"ETHERTYPE_MAX", Const, 1}, + {"ETHERTYPE_MERIT", Const, 1}, + {"ETHERTYPE_MICP", Const, 1}, + {"ETHERTYPE_MOPDL", Const, 1}, + {"ETHERTYPE_MOPRC", Const, 1}, + {"ETHERTYPE_MOTOROLA", Const, 1}, + {"ETHERTYPE_MPLS", Const, 1}, + {"ETHERTYPE_MPLS_MCAST", Const, 1}, + {"ETHERTYPE_MUMPS", Const, 1}, + {"ETHERTYPE_NBPCC", Const, 1}, + {"ETHERTYPE_NBPCLAIM", Const, 1}, + {"ETHERTYPE_NBPCLREQ", Const, 1}, + {"ETHERTYPE_NBPCLRSP", Const, 1}, + {"ETHERTYPE_NBPCREQ", Const, 1}, + {"ETHERTYPE_NBPCRSP", Const, 1}, + {"ETHERTYPE_NBPDG", Const, 1}, + {"ETHERTYPE_NBPDGB", Const, 1}, + {"ETHERTYPE_NBPDLTE", Const, 1}, + {"ETHERTYPE_NBPRAR", Const, 1}, + {"ETHERTYPE_NBPRAS", Const, 1}, + {"ETHERTYPE_NBPRST", Const, 1}, + {"ETHERTYPE_NBPSCD", Const, 1}, + {"ETHERTYPE_NBPVCD", Const, 1}, + {"ETHERTYPE_NBS", Const, 1}, + {"ETHERTYPE_NCD", Const, 1}, + {"ETHERTYPE_NESTAR", Const, 1}, + {"ETHERTYPE_NETBEUI", Const, 1}, + {"ETHERTYPE_NOVELL", Const, 1}, + {"ETHERTYPE_NS", Const, 1}, + {"ETHERTYPE_NSAT", Const, 1}, + {"ETHERTYPE_NSCOMPAT", Const, 1}, + {"ETHERTYPE_NTRAILER", Const, 1}, + {"ETHERTYPE_OS9", Const, 1}, + {"ETHERTYPE_OS9NET", Const, 1}, + {"ETHERTYPE_PACER", Const, 1}, + {"ETHERTYPE_PAE", Const, 1}, + {"ETHERTYPE_PCS", Const, 1}, + {"ETHERTYPE_PLANNING", Const, 1}, + {"ETHERTYPE_PPP", Const, 1}, + {"ETHERTYPE_PPPOE", Const, 1}, + {"ETHERTYPE_PPPOEDISC", Const, 1}, + {"ETHERTYPE_PRIMENTS", Const, 1}, + {"ETHERTYPE_PUP", Const, 1}, + {"ETHERTYPE_PUPAT", Const, 1}, + {"ETHERTYPE_QINQ", Const, 1}, + {"ETHERTYPE_RACAL", Const, 1}, + {"ETHERTYPE_RATIONAL", Const, 1}, + {"ETHERTYPE_RAWFR", Const, 1}, + {"ETHERTYPE_RCL", Const, 1}, + {"ETHERTYPE_RDP", Const, 1}, + {"ETHERTYPE_RETIX", Const, 1}, + {"ETHERTYPE_REVARP", Const, 1}, + {"ETHERTYPE_SCA", Const, 1}, + {"ETHERTYPE_SECTRA", Const, 1}, + {"ETHERTYPE_SECUREDATA", Const, 1}, + {"ETHERTYPE_SGITW", Const, 1}, + {"ETHERTYPE_SG_BOUNCE", Const, 1}, + {"ETHERTYPE_SG_DIAG", Const, 1}, + {"ETHERTYPE_SG_NETGAMES", Const, 1}, + {"ETHERTYPE_SG_RESV", Const, 1}, + {"ETHERTYPE_SIMNET", Const, 1}, + {"ETHERTYPE_SLOW", Const, 1}, + {"ETHERTYPE_SLOWPROTOCOLS", Const, 1}, + {"ETHERTYPE_SNA", Const, 1}, + {"ETHERTYPE_SNMP", Const, 1}, + {"ETHERTYPE_SONIX", Const, 1}, + {"ETHERTYPE_SPIDER", Const, 1}, + {"ETHERTYPE_SPRITE", Const, 1}, + {"ETHERTYPE_STP", Const, 1}, + {"ETHERTYPE_TALARIS", Const, 1}, + {"ETHERTYPE_TALARISMC", Const, 1}, + {"ETHERTYPE_TCPCOMP", Const, 1}, + {"ETHERTYPE_TCPSM", Const, 1}, + {"ETHERTYPE_TEC", Const, 1}, + {"ETHERTYPE_TIGAN", Const, 1}, + {"ETHERTYPE_TRAIL", Const, 1}, + {"ETHERTYPE_TRANSETHER", Const, 1}, + {"ETHERTYPE_TYMSHARE", Const, 1}, + {"ETHERTYPE_UBBST", Const, 1}, + {"ETHERTYPE_UBDEBUG", Const, 1}, + {"ETHERTYPE_UBDIAGLOOP", Const, 1}, + {"ETHERTYPE_UBDL", Const, 1}, + {"ETHERTYPE_UBNIU", Const, 1}, + {"ETHERTYPE_UBNMC", Const, 1}, + {"ETHERTYPE_VALID", Const, 1}, + {"ETHERTYPE_VARIAN", Const, 1}, + {"ETHERTYPE_VAXELN", Const, 1}, + {"ETHERTYPE_VEECO", Const, 1}, + {"ETHERTYPE_VEXP", Const, 1}, + {"ETHERTYPE_VGLAB", Const, 1}, + {"ETHERTYPE_VINES", Const, 1}, + {"ETHERTYPE_VINESECHO", Const, 1}, + {"ETHERTYPE_VINESLOOP", Const, 1}, + {"ETHERTYPE_VITAL", Const, 1}, + {"ETHERTYPE_VLAN", Const, 1}, + {"ETHERTYPE_VLTLMAN", Const, 1}, + {"ETHERTYPE_VPROD", Const, 1}, + {"ETHERTYPE_VURESERVED", Const, 1}, + {"ETHERTYPE_WATERLOO", Const, 1}, + {"ETHERTYPE_WELLFLEET", Const, 1}, + {"ETHERTYPE_X25", Const, 1}, + {"ETHERTYPE_X75", Const, 1}, + {"ETHERTYPE_XNSSM", Const, 1}, + {"ETHERTYPE_XTP", Const, 1}, + {"ETHER_ADDR_LEN", Const, 1}, + {"ETHER_ALIGN", Const, 1}, + {"ETHER_CRC_LEN", Const, 1}, + {"ETHER_CRC_POLY_BE", Const, 1}, + {"ETHER_CRC_POLY_LE", Const, 1}, + {"ETHER_HDR_LEN", Const, 1}, + {"ETHER_MAX_DIX_LEN", Const, 1}, + {"ETHER_MAX_LEN", Const, 1}, + {"ETHER_MAX_LEN_JUMBO", Const, 1}, + {"ETHER_MIN_LEN", Const, 1}, + {"ETHER_PPPOE_ENCAP_LEN", Const, 1}, + {"ETHER_TYPE_LEN", Const, 1}, + {"ETHER_VLAN_ENCAP_LEN", Const, 1}, + {"ETH_P_1588", Const, 0}, + {"ETH_P_8021Q", Const, 0}, + {"ETH_P_802_2", Const, 0}, + {"ETH_P_802_3", Const, 0}, + {"ETH_P_AARP", Const, 0}, + {"ETH_P_ALL", Const, 0}, + {"ETH_P_AOE", Const, 0}, + {"ETH_P_ARCNET", Const, 0}, + {"ETH_P_ARP", Const, 0}, + {"ETH_P_ATALK", Const, 0}, + {"ETH_P_ATMFATE", Const, 0}, + {"ETH_P_ATMMPOA", Const, 0}, + {"ETH_P_AX25", Const, 0}, + {"ETH_P_BPQ", Const, 0}, + {"ETH_P_CAIF", Const, 0}, + {"ETH_P_CAN", Const, 0}, + {"ETH_P_CONTROL", Const, 0}, + {"ETH_P_CUST", Const, 0}, + {"ETH_P_DDCMP", Const, 0}, + {"ETH_P_DEC", Const, 0}, + {"ETH_P_DIAG", Const, 0}, + {"ETH_P_DNA_DL", Const, 0}, + {"ETH_P_DNA_RC", Const, 0}, + {"ETH_P_DNA_RT", Const, 0}, + {"ETH_P_DSA", Const, 0}, + {"ETH_P_ECONET", Const, 0}, + {"ETH_P_EDSA", Const, 0}, + {"ETH_P_FCOE", Const, 0}, + {"ETH_P_FIP", Const, 0}, + {"ETH_P_HDLC", Const, 0}, + {"ETH_P_IEEE802154", Const, 0}, + {"ETH_P_IEEEPUP", Const, 0}, + {"ETH_P_IEEEPUPAT", Const, 0}, + {"ETH_P_IP", Const, 0}, + {"ETH_P_IPV6", Const, 0}, + {"ETH_P_IPX", Const, 0}, + {"ETH_P_IRDA", Const, 0}, + {"ETH_P_LAT", Const, 0}, + {"ETH_P_LINK_CTL", Const, 0}, + {"ETH_P_LOCALTALK", Const, 0}, + {"ETH_P_LOOP", Const, 0}, + {"ETH_P_MOBITEX", Const, 0}, + {"ETH_P_MPLS_MC", Const, 0}, + {"ETH_P_MPLS_UC", Const, 0}, + {"ETH_P_PAE", Const, 0}, + {"ETH_P_PAUSE", Const, 0}, + {"ETH_P_PHONET", Const, 0}, + {"ETH_P_PPPTALK", Const, 0}, + {"ETH_P_PPP_DISC", Const, 0}, + {"ETH_P_PPP_MP", Const, 0}, + {"ETH_P_PPP_SES", Const, 0}, + {"ETH_P_PUP", Const, 0}, + {"ETH_P_PUPAT", Const, 0}, + {"ETH_P_RARP", Const, 0}, + {"ETH_P_SCA", Const, 0}, + {"ETH_P_SLOW", Const, 0}, + {"ETH_P_SNAP", Const, 0}, + {"ETH_P_TEB", Const, 0}, + {"ETH_P_TIPC", Const, 0}, + {"ETH_P_TRAILER", Const, 0}, + {"ETH_P_TR_802_2", Const, 0}, + {"ETH_P_WAN_PPP", Const, 0}, + {"ETH_P_WCCP", Const, 0}, + {"ETH_P_X25", Const, 0}, + {"ETIME", Const, 0}, + {"ETIMEDOUT", Const, 0}, + {"ETOOMANYREFS", Const, 0}, + {"ETXTBSY", Const, 0}, + {"EUCLEAN", Const, 0}, + {"EUNATCH", Const, 0}, + {"EUSERS", Const, 0}, + {"EVFILT_AIO", Const, 0}, + {"EVFILT_FS", Const, 0}, + {"EVFILT_LIO", Const, 0}, + {"EVFILT_MACHPORT", Const, 0}, + {"EVFILT_PROC", Const, 0}, + {"EVFILT_READ", Const, 0}, + {"EVFILT_SIGNAL", Const, 0}, + {"EVFILT_SYSCOUNT", Const, 0}, + {"EVFILT_THREADMARKER", Const, 0}, + {"EVFILT_TIMER", Const, 0}, + {"EVFILT_USER", Const, 0}, + {"EVFILT_VM", Const, 0}, + {"EVFILT_VNODE", Const, 0}, + {"EVFILT_WRITE", Const, 0}, + {"EV_ADD", Const, 0}, + {"EV_CLEAR", Const, 0}, + {"EV_DELETE", Const, 0}, + {"EV_DISABLE", Const, 0}, + {"EV_DISPATCH", Const, 0}, + {"EV_DROP", Const, 3}, + {"EV_ENABLE", Const, 0}, + {"EV_EOF", Const, 0}, + {"EV_ERROR", Const, 0}, + {"EV_FLAG0", Const, 0}, + {"EV_FLAG1", Const, 0}, + {"EV_ONESHOT", Const, 0}, + {"EV_OOBAND", Const, 0}, + {"EV_POLL", Const, 0}, + {"EV_RECEIPT", Const, 0}, + {"EV_SYSFLAGS", Const, 0}, + {"EWINDOWS", Const, 0}, + {"EWOULDBLOCK", Const, 0}, + {"EXDEV", Const, 0}, + {"EXFULL", Const, 0}, + {"EXTA", Const, 0}, + {"EXTB", Const, 0}, + {"EXTPROC", Const, 0}, + {"Environ", Func, 0}, + {"EpollCreate", Func, 0}, + {"EpollCreate1", Func, 0}, + {"EpollCtl", Func, 0}, + {"EpollEvent", Type, 0}, + {"EpollEvent.Events", Field, 0}, + {"EpollEvent.Fd", Field, 0}, + {"EpollEvent.Pad", Field, 0}, + {"EpollEvent.PadFd", Field, 0}, + {"EpollWait", Func, 0}, + {"Errno", Type, 0}, + {"EscapeArg", Func, 0}, + {"Exchangedata", Func, 0}, + {"Exec", Func, 0}, + {"Exit", Func, 0}, + {"ExitProcess", Func, 0}, + {"FD_CLOEXEC", Const, 0}, + {"FD_SETSIZE", Const, 0}, + {"FILE_ACTION_ADDED", Const, 0}, + {"FILE_ACTION_MODIFIED", Const, 0}, + {"FILE_ACTION_REMOVED", Const, 0}, + {"FILE_ACTION_RENAMED_NEW_NAME", Const, 0}, + {"FILE_ACTION_RENAMED_OLD_NAME", Const, 0}, + {"FILE_APPEND_DATA", Const, 0}, + {"FILE_ATTRIBUTE_ARCHIVE", Const, 0}, + {"FILE_ATTRIBUTE_DIRECTORY", Const, 0}, + {"FILE_ATTRIBUTE_HIDDEN", Const, 0}, + {"FILE_ATTRIBUTE_NORMAL", Const, 0}, + {"FILE_ATTRIBUTE_READONLY", Const, 0}, + {"FILE_ATTRIBUTE_REPARSE_POINT", Const, 4}, + {"FILE_ATTRIBUTE_SYSTEM", Const, 0}, + {"FILE_BEGIN", Const, 0}, + {"FILE_CURRENT", Const, 0}, + {"FILE_END", Const, 0}, + {"FILE_FLAG_BACKUP_SEMANTICS", Const, 0}, + {"FILE_FLAG_OPEN_REPARSE_POINT", Const, 4}, + {"FILE_FLAG_OVERLAPPED", Const, 0}, + {"FILE_LIST_DIRECTORY", Const, 0}, + {"FILE_MAP_COPY", Const, 0}, + {"FILE_MAP_EXECUTE", Const, 0}, + {"FILE_MAP_READ", Const, 0}, + {"FILE_MAP_WRITE", Const, 0}, + {"FILE_NOTIFY_CHANGE_ATTRIBUTES", Const, 0}, + {"FILE_NOTIFY_CHANGE_CREATION", Const, 0}, + {"FILE_NOTIFY_CHANGE_DIR_NAME", Const, 0}, + {"FILE_NOTIFY_CHANGE_FILE_NAME", Const, 0}, + {"FILE_NOTIFY_CHANGE_LAST_ACCESS", Const, 0}, + {"FILE_NOTIFY_CHANGE_LAST_WRITE", Const, 0}, + {"FILE_NOTIFY_CHANGE_SIZE", Const, 0}, + {"FILE_SHARE_DELETE", Const, 0}, + {"FILE_SHARE_READ", Const, 0}, + {"FILE_SHARE_WRITE", Const, 0}, + {"FILE_SKIP_COMPLETION_PORT_ON_SUCCESS", Const, 2}, + {"FILE_SKIP_SET_EVENT_ON_HANDLE", Const, 2}, + {"FILE_TYPE_CHAR", Const, 0}, + {"FILE_TYPE_DISK", Const, 0}, + {"FILE_TYPE_PIPE", Const, 0}, + {"FILE_TYPE_REMOTE", Const, 0}, + {"FILE_TYPE_UNKNOWN", Const, 0}, + {"FILE_WRITE_ATTRIBUTES", Const, 0}, + {"FLUSHO", Const, 0}, + {"FORMAT_MESSAGE_ALLOCATE_BUFFER", Const, 0}, + {"FORMAT_MESSAGE_ARGUMENT_ARRAY", Const, 0}, + {"FORMAT_MESSAGE_FROM_HMODULE", Const, 0}, + {"FORMAT_MESSAGE_FROM_STRING", Const, 0}, + {"FORMAT_MESSAGE_FROM_SYSTEM", Const, 0}, + {"FORMAT_MESSAGE_IGNORE_INSERTS", Const, 0}, + {"FORMAT_MESSAGE_MAX_WIDTH_MASK", Const, 0}, + {"FSCTL_GET_REPARSE_POINT", Const, 4}, + {"F_ADDFILESIGS", Const, 0}, + {"F_ADDSIGS", Const, 0}, + {"F_ALLOCATEALL", Const, 0}, + {"F_ALLOCATECONTIG", Const, 0}, + {"F_CANCEL", Const, 0}, + {"F_CHKCLEAN", Const, 0}, + {"F_CLOSEM", Const, 1}, + {"F_DUP2FD", Const, 0}, + {"F_DUP2FD_CLOEXEC", Const, 1}, + {"F_DUPFD", Const, 0}, + {"F_DUPFD_CLOEXEC", Const, 0}, + {"F_EXLCK", Const, 0}, + {"F_FINDSIGS", Const, 16}, + {"F_FLUSH_DATA", Const, 0}, + {"F_FREEZE_FS", Const, 0}, + {"F_FSCTL", Const, 1}, + {"F_FSDIRMASK", Const, 1}, + {"F_FSIN", Const, 1}, + {"F_FSINOUT", Const, 1}, + {"F_FSOUT", Const, 1}, + {"F_FSPRIV", Const, 1}, + {"F_FSVOID", Const, 1}, + {"F_FULLFSYNC", Const, 0}, + {"F_GETCODEDIR", Const, 16}, + {"F_GETFD", Const, 0}, + {"F_GETFL", Const, 0}, + {"F_GETLEASE", Const, 0}, + {"F_GETLK", Const, 0}, + {"F_GETLK64", Const, 0}, + {"F_GETLKPID", Const, 0}, + {"F_GETNOSIGPIPE", Const, 0}, + {"F_GETOWN", Const, 0}, + {"F_GETOWN_EX", Const, 0}, + {"F_GETPATH", Const, 0}, + {"F_GETPATH_MTMINFO", Const, 0}, + {"F_GETPIPE_SZ", Const, 0}, + {"F_GETPROTECTIONCLASS", Const, 0}, + {"F_GETPROTECTIONLEVEL", Const, 16}, + {"F_GETSIG", Const, 0}, + {"F_GLOBAL_NOCACHE", Const, 0}, + {"F_LOCK", Const, 0}, + {"F_LOG2PHYS", Const, 0}, + {"F_LOG2PHYS_EXT", Const, 0}, + {"F_MARKDEPENDENCY", Const, 0}, + {"F_MAXFD", Const, 1}, + {"F_NOCACHE", Const, 0}, + {"F_NODIRECT", Const, 0}, + {"F_NOTIFY", Const, 0}, + {"F_OGETLK", Const, 0}, + {"F_OK", Const, 0}, + {"F_OSETLK", Const, 0}, + {"F_OSETLKW", Const, 0}, + {"F_PARAM_MASK", Const, 1}, + {"F_PARAM_MAX", Const, 1}, + {"F_PATHPKG_CHECK", Const, 0}, + {"F_PEOFPOSMODE", Const, 0}, + {"F_PREALLOCATE", Const, 0}, + {"F_RDADVISE", Const, 0}, + {"F_RDAHEAD", Const, 0}, + {"F_RDLCK", Const, 0}, + {"F_READAHEAD", Const, 0}, + {"F_READBOOTSTRAP", Const, 0}, + {"F_SETBACKINGSTORE", Const, 0}, + {"F_SETFD", Const, 0}, + {"F_SETFL", Const, 0}, + {"F_SETLEASE", Const, 0}, + {"F_SETLK", Const, 0}, + {"F_SETLK64", Const, 0}, + {"F_SETLKW", Const, 0}, + {"F_SETLKW64", Const, 0}, + {"F_SETLKWTIMEOUT", Const, 16}, + {"F_SETLK_REMOTE", Const, 0}, + {"F_SETNOSIGPIPE", Const, 0}, + {"F_SETOWN", Const, 0}, + {"F_SETOWN_EX", Const, 0}, + {"F_SETPIPE_SZ", Const, 0}, + {"F_SETPROTECTIONCLASS", Const, 0}, + {"F_SETSIG", Const, 0}, + {"F_SETSIZE", Const, 0}, + {"F_SHLCK", Const, 0}, + {"F_SINGLE_WRITER", Const, 16}, + {"F_TEST", Const, 0}, + {"F_THAW_FS", Const, 0}, + {"F_TLOCK", Const, 0}, + {"F_TRANSCODEKEY", Const, 16}, + {"F_ULOCK", Const, 0}, + {"F_UNLCK", Const, 0}, + {"F_UNLCKSYS", Const, 0}, + {"F_VOLPOSMODE", Const, 0}, + {"F_WRITEBOOTSTRAP", Const, 0}, + {"F_WRLCK", Const, 0}, + {"Faccessat", Func, 0}, + {"Fallocate", Func, 0}, + {"Fbootstraptransfer_t", Type, 0}, + {"Fbootstraptransfer_t.Buffer", Field, 0}, + {"Fbootstraptransfer_t.Length", Field, 0}, + {"Fbootstraptransfer_t.Offset", Field, 0}, + {"Fchdir", Func, 0}, + {"Fchflags", Func, 0}, + {"Fchmod", Func, 0}, + {"Fchmodat", Func, 0}, + {"Fchown", Func, 0}, + {"Fchownat", Func, 0}, + {"FcntlFlock", Func, 3}, + {"FdSet", Type, 0}, + {"FdSet.Bits", Field, 0}, + {"FdSet.X__fds_bits", Field, 0}, + {"Fdatasync", Func, 0}, + {"FileNotifyInformation", Type, 0}, + {"FileNotifyInformation.Action", Field, 0}, + {"FileNotifyInformation.FileName", Field, 0}, + {"FileNotifyInformation.FileNameLength", Field, 0}, + {"FileNotifyInformation.NextEntryOffset", Field, 0}, + {"Filetime", Type, 0}, + {"Filetime.HighDateTime", Field, 0}, + {"Filetime.LowDateTime", Field, 0}, + {"FindClose", Func, 0}, + {"FindFirstFile", Func, 0}, + {"FindNextFile", Func, 0}, + {"Flock", Func, 0}, + {"Flock_t", Type, 0}, + {"Flock_t.Len", Field, 0}, + {"Flock_t.Pad_cgo_0", Field, 0}, + {"Flock_t.Pad_cgo_1", Field, 3}, + {"Flock_t.Pid", Field, 0}, + {"Flock_t.Start", Field, 0}, + {"Flock_t.Sysid", Field, 0}, + {"Flock_t.Type", Field, 0}, + {"Flock_t.Whence", Field, 0}, + {"FlushBpf", Func, 0}, + {"FlushFileBuffers", Func, 0}, + {"FlushViewOfFile", Func, 0}, + {"ForkExec", Func, 0}, + {"ForkLock", Var, 0}, + {"FormatMessage", Func, 0}, + {"Fpathconf", Func, 0}, + {"FreeAddrInfoW", Func, 1}, + {"FreeEnvironmentStrings", Func, 0}, + {"FreeLibrary", Func, 0}, + {"Fsid", Type, 0}, + {"Fsid.Val", Field, 0}, + {"Fsid.X__fsid_val", Field, 2}, + {"Fsid.X__val", Field, 0}, + {"Fstat", Func, 0}, + {"Fstatat", Func, 12}, + {"Fstatfs", Func, 0}, + {"Fstore_t", Type, 0}, + {"Fstore_t.Bytesalloc", Field, 0}, + {"Fstore_t.Flags", Field, 0}, + {"Fstore_t.Length", Field, 0}, + {"Fstore_t.Offset", Field, 0}, + {"Fstore_t.Posmode", Field, 0}, + {"Fsync", Func, 0}, + {"Ftruncate", Func, 0}, + {"FullPath", Func, 4}, + {"Futimes", Func, 0}, + {"Futimesat", Func, 0}, + {"GENERIC_ALL", Const, 0}, + {"GENERIC_EXECUTE", Const, 0}, + {"GENERIC_READ", Const, 0}, + {"GENERIC_WRITE", Const, 0}, + {"GUID", Type, 1}, + {"GUID.Data1", Field, 1}, + {"GUID.Data2", Field, 1}, + {"GUID.Data3", Field, 1}, + {"GUID.Data4", Field, 1}, + {"GetAcceptExSockaddrs", Func, 0}, + {"GetAdaptersInfo", Func, 0}, + {"GetAddrInfoW", Func, 1}, + {"GetCommandLine", Func, 0}, + {"GetComputerName", Func, 0}, + {"GetConsoleMode", Func, 1}, + {"GetCurrentDirectory", Func, 0}, + {"GetCurrentProcess", Func, 0}, + {"GetEnvironmentStrings", Func, 0}, + {"GetEnvironmentVariable", Func, 0}, + {"GetExitCodeProcess", Func, 0}, + {"GetFileAttributes", Func, 0}, + {"GetFileAttributesEx", Func, 0}, + {"GetFileExInfoStandard", Const, 0}, + {"GetFileExMaxInfoLevel", Const, 0}, + {"GetFileInformationByHandle", Func, 0}, + {"GetFileType", Func, 0}, + {"GetFullPathName", Func, 0}, + {"GetHostByName", Func, 0}, + {"GetIfEntry", Func, 0}, + {"GetLastError", Func, 0}, + {"GetLengthSid", Func, 0}, + {"GetLongPathName", Func, 0}, + {"GetProcAddress", Func, 0}, + {"GetProcessTimes", Func, 0}, + {"GetProtoByName", Func, 0}, + {"GetQueuedCompletionStatus", Func, 0}, + {"GetServByName", Func, 0}, + {"GetShortPathName", Func, 0}, + {"GetStartupInfo", Func, 0}, + {"GetStdHandle", Func, 0}, + {"GetSystemTimeAsFileTime", Func, 0}, + {"GetTempPath", Func, 0}, + {"GetTimeZoneInformation", Func, 0}, + {"GetTokenInformation", Func, 0}, + {"GetUserNameEx", Func, 0}, + {"GetUserProfileDirectory", Func, 0}, + {"GetVersion", Func, 0}, + {"Getcwd", Func, 0}, + {"Getdents", Func, 0}, + {"Getdirentries", Func, 0}, + {"Getdtablesize", Func, 0}, + {"Getegid", Func, 0}, + {"Getenv", Func, 0}, + {"Geteuid", Func, 0}, + {"Getfsstat", Func, 0}, + {"Getgid", Func, 0}, + {"Getgroups", Func, 0}, + {"Getpagesize", Func, 0}, + {"Getpeername", Func, 0}, + {"Getpgid", Func, 0}, + {"Getpgrp", Func, 0}, + {"Getpid", Func, 0}, + {"Getppid", Func, 0}, + {"Getpriority", Func, 0}, + {"Getrlimit", Func, 0}, + {"Getrusage", Func, 0}, + {"Getsid", Func, 0}, + {"Getsockname", Func, 0}, + {"Getsockopt", Func, 1}, + {"GetsockoptByte", Func, 0}, + {"GetsockoptICMPv6Filter", Func, 2}, + {"GetsockoptIPMreq", Func, 0}, + {"GetsockoptIPMreqn", Func, 0}, + {"GetsockoptIPv6MTUInfo", Func, 2}, + {"GetsockoptIPv6Mreq", Func, 0}, + {"GetsockoptInet4Addr", Func, 0}, + {"GetsockoptInt", Func, 0}, + {"GetsockoptUcred", Func, 1}, + {"Gettid", Func, 0}, + {"Gettimeofday", Func, 0}, + {"Getuid", Func, 0}, + {"Getwd", Func, 0}, + {"Getxattr", Func, 1}, + {"HANDLE_FLAG_INHERIT", Const, 0}, + {"HKEY_CLASSES_ROOT", Const, 0}, + {"HKEY_CURRENT_CONFIG", Const, 0}, + {"HKEY_CURRENT_USER", Const, 0}, + {"HKEY_DYN_DATA", Const, 0}, + {"HKEY_LOCAL_MACHINE", Const, 0}, + {"HKEY_PERFORMANCE_DATA", Const, 0}, + {"HKEY_USERS", Const, 0}, + {"HUPCL", Const, 0}, + {"Handle", Type, 0}, + {"Hostent", Type, 0}, + {"Hostent.AddrList", Field, 0}, + {"Hostent.AddrType", Field, 0}, + {"Hostent.Aliases", Field, 0}, + {"Hostent.Length", Field, 0}, + {"Hostent.Name", Field, 0}, + {"ICANON", Const, 0}, + {"ICMP6_FILTER", Const, 2}, + {"ICMPV6_FILTER", Const, 2}, + {"ICMPv6Filter", Type, 2}, + {"ICMPv6Filter.Data", Field, 2}, + {"ICMPv6Filter.Filt", Field, 2}, + {"ICRNL", Const, 0}, + {"IEXTEN", Const, 0}, + {"IFAN_ARRIVAL", Const, 1}, + {"IFAN_DEPARTURE", Const, 1}, + {"IFA_ADDRESS", Const, 0}, + {"IFA_ANYCAST", Const, 0}, + {"IFA_BROADCAST", Const, 0}, + {"IFA_CACHEINFO", Const, 0}, + {"IFA_F_DADFAILED", Const, 0}, + {"IFA_F_DEPRECATED", Const, 0}, + {"IFA_F_HOMEADDRESS", Const, 0}, + {"IFA_F_NODAD", Const, 0}, + {"IFA_F_OPTIMISTIC", Const, 0}, + {"IFA_F_PERMANENT", Const, 0}, + {"IFA_F_SECONDARY", Const, 0}, + {"IFA_F_TEMPORARY", Const, 0}, + {"IFA_F_TENTATIVE", Const, 0}, + {"IFA_LABEL", Const, 0}, + {"IFA_LOCAL", Const, 0}, + {"IFA_MAX", Const, 0}, + {"IFA_MULTICAST", Const, 0}, + {"IFA_ROUTE", Const, 1}, + {"IFA_UNSPEC", Const, 0}, + {"IFF_ALLMULTI", Const, 0}, + {"IFF_ALTPHYS", Const, 0}, + {"IFF_AUTOMEDIA", Const, 0}, + {"IFF_BROADCAST", Const, 0}, + {"IFF_CANTCHANGE", Const, 0}, + {"IFF_CANTCONFIG", Const, 1}, + {"IFF_DEBUG", Const, 0}, + {"IFF_DRV_OACTIVE", Const, 0}, + {"IFF_DRV_RUNNING", Const, 0}, + {"IFF_DYING", Const, 0}, + {"IFF_DYNAMIC", Const, 0}, + {"IFF_LINK0", Const, 0}, + {"IFF_LINK1", Const, 0}, + {"IFF_LINK2", Const, 0}, + {"IFF_LOOPBACK", Const, 0}, + {"IFF_MASTER", Const, 0}, + {"IFF_MONITOR", Const, 0}, + {"IFF_MULTICAST", Const, 0}, + {"IFF_NOARP", Const, 0}, + {"IFF_NOTRAILERS", Const, 0}, + {"IFF_NO_PI", Const, 0}, + {"IFF_OACTIVE", Const, 0}, + {"IFF_ONE_QUEUE", Const, 0}, + {"IFF_POINTOPOINT", Const, 0}, + {"IFF_POINTTOPOINT", Const, 0}, + {"IFF_PORTSEL", Const, 0}, + {"IFF_PPROMISC", Const, 0}, + {"IFF_PROMISC", Const, 0}, + {"IFF_RENAMING", Const, 0}, + {"IFF_RUNNING", Const, 0}, + {"IFF_SIMPLEX", Const, 0}, + {"IFF_SLAVE", Const, 0}, + {"IFF_SMART", Const, 0}, + {"IFF_STATICARP", Const, 0}, + {"IFF_TAP", Const, 0}, + {"IFF_TUN", Const, 0}, + {"IFF_TUN_EXCL", Const, 0}, + {"IFF_UP", Const, 0}, + {"IFF_VNET_HDR", Const, 0}, + {"IFLA_ADDRESS", Const, 0}, + {"IFLA_BROADCAST", Const, 0}, + {"IFLA_COST", Const, 0}, + {"IFLA_IFALIAS", Const, 0}, + {"IFLA_IFNAME", Const, 0}, + {"IFLA_LINK", Const, 0}, + {"IFLA_LINKINFO", Const, 0}, + {"IFLA_LINKMODE", Const, 0}, + {"IFLA_MAP", Const, 0}, + {"IFLA_MASTER", Const, 0}, + {"IFLA_MAX", Const, 0}, + {"IFLA_MTU", Const, 0}, + {"IFLA_NET_NS_PID", Const, 0}, + {"IFLA_OPERSTATE", Const, 0}, + {"IFLA_PRIORITY", Const, 0}, + {"IFLA_PROTINFO", Const, 0}, + {"IFLA_QDISC", Const, 0}, + {"IFLA_STATS", Const, 0}, + {"IFLA_TXQLEN", Const, 0}, + {"IFLA_UNSPEC", Const, 0}, + {"IFLA_WEIGHT", Const, 0}, + {"IFLA_WIRELESS", Const, 0}, + {"IFNAMSIZ", Const, 0}, + {"IFT_1822", Const, 0}, + {"IFT_A12MPPSWITCH", Const, 0}, + {"IFT_AAL2", Const, 0}, + {"IFT_AAL5", Const, 0}, + {"IFT_ADSL", Const, 0}, + {"IFT_AFLANE8023", Const, 0}, + {"IFT_AFLANE8025", Const, 0}, + {"IFT_ARAP", Const, 0}, + {"IFT_ARCNET", Const, 0}, + {"IFT_ARCNETPLUS", Const, 0}, + {"IFT_ASYNC", Const, 0}, + {"IFT_ATM", Const, 0}, + {"IFT_ATMDXI", Const, 0}, + {"IFT_ATMFUNI", Const, 0}, + {"IFT_ATMIMA", Const, 0}, + {"IFT_ATMLOGICAL", Const, 0}, + {"IFT_ATMRADIO", Const, 0}, + {"IFT_ATMSUBINTERFACE", Const, 0}, + {"IFT_ATMVCIENDPT", Const, 0}, + {"IFT_ATMVIRTUAL", Const, 0}, + {"IFT_BGPPOLICYACCOUNTING", Const, 0}, + {"IFT_BLUETOOTH", Const, 1}, + {"IFT_BRIDGE", Const, 0}, + {"IFT_BSC", Const, 0}, + {"IFT_CARP", Const, 0}, + {"IFT_CCTEMUL", Const, 0}, + {"IFT_CELLULAR", Const, 0}, + {"IFT_CEPT", Const, 0}, + {"IFT_CES", Const, 0}, + {"IFT_CHANNEL", Const, 0}, + {"IFT_CNR", Const, 0}, + {"IFT_COFFEE", Const, 0}, + {"IFT_COMPOSITELINK", Const, 0}, + {"IFT_DCN", Const, 0}, + {"IFT_DIGITALPOWERLINE", Const, 0}, + {"IFT_DIGITALWRAPPEROVERHEADCHANNEL", Const, 0}, + {"IFT_DLSW", Const, 0}, + {"IFT_DOCSCABLEDOWNSTREAM", Const, 0}, + {"IFT_DOCSCABLEMACLAYER", Const, 0}, + {"IFT_DOCSCABLEUPSTREAM", Const, 0}, + {"IFT_DOCSCABLEUPSTREAMCHANNEL", Const, 1}, + {"IFT_DS0", Const, 0}, + {"IFT_DS0BUNDLE", Const, 0}, + {"IFT_DS1FDL", Const, 0}, + {"IFT_DS3", Const, 0}, + {"IFT_DTM", Const, 0}, + {"IFT_DUMMY", Const, 1}, + {"IFT_DVBASILN", Const, 0}, + {"IFT_DVBASIOUT", Const, 0}, + {"IFT_DVBRCCDOWNSTREAM", Const, 0}, + {"IFT_DVBRCCMACLAYER", Const, 0}, + {"IFT_DVBRCCUPSTREAM", Const, 0}, + {"IFT_ECONET", Const, 1}, + {"IFT_ENC", Const, 0}, + {"IFT_EON", Const, 0}, + {"IFT_EPLRS", Const, 0}, + {"IFT_ESCON", Const, 0}, + {"IFT_ETHER", Const, 0}, + {"IFT_FAITH", Const, 0}, + {"IFT_FAST", Const, 0}, + {"IFT_FASTETHER", Const, 0}, + {"IFT_FASTETHERFX", Const, 0}, + {"IFT_FDDI", Const, 0}, + {"IFT_FIBRECHANNEL", Const, 0}, + {"IFT_FRAMERELAYINTERCONNECT", Const, 0}, + {"IFT_FRAMERELAYMPI", Const, 0}, + {"IFT_FRDLCIENDPT", Const, 0}, + {"IFT_FRELAY", Const, 0}, + {"IFT_FRELAYDCE", Const, 0}, + {"IFT_FRF16MFRBUNDLE", Const, 0}, + {"IFT_FRFORWARD", Const, 0}, + {"IFT_G703AT2MB", Const, 0}, + {"IFT_G703AT64K", Const, 0}, + {"IFT_GIF", Const, 0}, + {"IFT_GIGABITETHERNET", Const, 0}, + {"IFT_GR303IDT", Const, 0}, + {"IFT_GR303RDT", Const, 0}, + {"IFT_H323GATEKEEPER", Const, 0}, + {"IFT_H323PROXY", Const, 0}, + {"IFT_HDH1822", Const, 0}, + {"IFT_HDLC", Const, 0}, + {"IFT_HDSL2", Const, 0}, + {"IFT_HIPERLAN2", Const, 0}, + {"IFT_HIPPI", Const, 0}, + {"IFT_HIPPIINTERFACE", Const, 0}, + {"IFT_HOSTPAD", Const, 0}, + {"IFT_HSSI", Const, 0}, + {"IFT_HY", Const, 0}, + {"IFT_IBM370PARCHAN", Const, 0}, + {"IFT_IDSL", Const, 0}, + {"IFT_IEEE1394", Const, 0}, + {"IFT_IEEE80211", Const, 0}, + {"IFT_IEEE80212", Const, 0}, + {"IFT_IEEE8023ADLAG", Const, 0}, + {"IFT_IFGSN", Const, 0}, + {"IFT_IMT", Const, 0}, + {"IFT_INFINIBAND", Const, 1}, + {"IFT_INTERLEAVE", Const, 0}, + {"IFT_IP", Const, 0}, + {"IFT_IPFORWARD", Const, 0}, + {"IFT_IPOVERATM", Const, 0}, + {"IFT_IPOVERCDLC", Const, 0}, + {"IFT_IPOVERCLAW", Const, 0}, + {"IFT_IPSWITCH", Const, 0}, + {"IFT_IPXIP", Const, 0}, + {"IFT_ISDN", Const, 0}, + {"IFT_ISDNBASIC", Const, 0}, + {"IFT_ISDNPRIMARY", Const, 0}, + {"IFT_ISDNS", Const, 0}, + {"IFT_ISDNU", Const, 0}, + {"IFT_ISO88022LLC", Const, 0}, + {"IFT_ISO88023", Const, 0}, + {"IFT_ISO88024", Const, 0}, + {"IFT_ISO88025", Const, 0}, + {"IFT_ISO88025CRFPINT", Const, 0}, + {"IFT_ISO88025DTR", Const, 0}, + {"IFT_ISO88025FIBER", Const, 0}, + {"IFT_ISO88026", Const, 0}, + {"IFT_ISUP", Const, 0}, + {"IFT_L2VLAN", Const, 0}, + {"IFT_L3IPVLAN", Const, 0}, + {"IFT_L3IPXVLAN", Const, 0}, + {"IFT_LAPB", Const, 0}, + {"IFT_LAPD", Const, 0}, + {"IFT_LAPF", Const, 0}, + {"IFT_LINEGROUP", Const, 1}, + {"IFT_LOCALTALK", Const, 0}, + {"IFT_LOOP", Const, 0}, + {"IFT_MEDIAMAILOVERIP", Const, 0}, + {"IFT_MFSIGLINK", Const, 0}, + {"IFT_MIOX25", Const, 0}, + {"IFT_MODEM", Const, 0}, + {"IFT_MPC", Const, 0}, + {"IFT_MPLS", Const, 0}, + {"IFT_MPLSTUNNEL", Const, 0}, + {"IFT_MSDSL", Const, 0}, + {"IFT_MVL", Const, 0}, + {"IFT_MYRINET", Const, 0}, + {"IFT_NFAS", Const, 0}, + {"IFT_NSIP", Const, 0}, + {"IFT_OPTICALCHANNEL", Const, 0}, + {"IFT_OPTICALTRANSPORT", Const, 0}, + {"IFT_OTHER", Const, 0}, + {"IFT_P10", Const, 0}, + {"IFT_P80", Const, 0}, + {"IFT_PARA", Const, 0}, + {"IFT_PDP", Const, 0}, + {"IFT_PFLOG", Const, 0}, + {"IFT_PFLOW", Const, 1}, + {"IFT_PFSYNC", Const, 0}, + {"IFT_PLC", Const, 0}, + {"IFT_PON155", Const, 1}, + {"IFT_PON622", Const, 1}, + {"IFT_POS", Const, 0}, + {"IFT_PPP", Const, 0}, + {"IFT_PPPMULTILINKBUNDLE", Const, 0}, + {"IFT_PROPATM", Const, 1}, + {"IFT_PROPBWAP2MP", Const, 0}, + {"IFT_PROPCNLS", Const, 0}, + {"IFT_PROPDOCSWIRELESSDOWNSTREAM", Const, 0}, + {"IFT_PROPDOCSWIRELESSMACLAYER", Const, 0}, + {"IFT_PROPDOCSWIRELESSUPSTREAM", Const, 0}, + {"IFT_PROPMUX", Const, 0}, + {"IFT_PROPVIRTUAL", Const, 0}, + {"IFT_PROPWIRELESSP2P", Const, 0}, + {"IFT_PTPSERIAL", Const, 0}, + {"IFT_PVC", Const, 0}, + {"IFT_Q2931", Const, 1}, + {"IFT_QLLC", Const, 0}, + {"IFT_RADIOMAC", Const, 0}, + {"IFT_RADSL", Const, 0}, + {"IFT_REACHDSL", Const, 0}, + {"IFT_RFC1483", Const, 0}, + {"IFT_RS232", Const, 0}, + {"IFT_RSRB", Const, 0}, + {"IFT_SDLC", Const, 0}, + {"IFT_SDSL", Const, 0}, + {"IFT_SHDSL", Const, 0}, + {"IFT_SIP", Const, 0}, + {"IFT_SIPSIG", Const, 1}, + {"IFT_SIPTG", Const, 1}, + {"IFT_SLIP", Const, 0}, + {"IFT_SMDSDXI", Const, 0}, + {"IFT_SMDSICIP", Const, 0}, + {"IFT_SONET", Const, 0}, + {"IFT_SONETOVERHEADCHANNEL", Const, 0}, + {"IFT_SONETPATH", Const, 0}, + {"IFT_SONETVT", Const, 0}, + {"IFT_SRP", Const, 0}, + {"IFT_SS7SIGLINK", Const, 0}, + {"IFT_STACKTOSTACK", Const, 0}, + {"IFT_STARLAN", Const, 0}, + {"IFT_STF", Const, 0}, + {"IFT_T1", Const, 0}, + {"IFT_TDLC", Const, 0}, + {"IFT_TELINK", Const, 1}, + {"IFT_TERMPAD", Const, 0}, + {"IFT_TR008", Const, 0}, + {"IFT_TRANSPHDLC", Const, 0}, + {"IFT_TUNNEL", Const, 0}, + {"IFT_ULTRA", Const, 0}, + {"IFT_USB", Const, 0}, + {"IFT_V11", Const, 0}, + {"IFT_V35", Const, 0}, + {"IFT_V36", Const, 0}, + {"IFT_V37", Const, 0}, + {"IFT_VDSL", Const, 0}, + {"IFT_VIRTUALIPADDRESS", Const, 0}, + {"IFT_VIRTUALTG", Const, 1}, + {"IFT_VOICEDID", Const, 1}, + {"IFT_VOICEEM", Const, 0}, + {"IFT_VOICEEMFGD", Const, 1}, + {"IFT_VOICEENCAP", Const, 0}, + {"IFT_VOICEFGDEANA", Const, 1}, + {"IFT_VOICEFXO", Const, 0}, + {"IFT_VOICEFXS", Const, 0}, + {"IFT_VOICEOVERATM", Const, 0}, + {"IFT_VOICEOVERCABLE", Const, 1}, + {"IFT_VOICEOVERFRAMERELAY", Const, 0}, + {"IFT_VOICEOVERIP", Const, 0}, + {"IFT_X213", Const, 0}, + {"IFT_X25", Const, 0}, + {"IFT_X25DDN", Const, 0}, + {"IFT_X25HUNTGROUP", Const, 0}, + {"IFT_X25MLP", Const, 0}, + {"IFT_X25PLE", Const, 0}, + {"IFT_XETHER", Const, 0}, + {"IGNBRK", Const, 0}, + {"IGNCR", Const, 0}, + {"IGNORE", Const, 0}, + {"IGNPAR", Const, 0}, + {"IMAXBEL", Const, 0}, + {"INFINITE", Const, 0}, + {"INLCR", Const, 0}, + {"INPCK", Const, 0}, + {"INVALID_FILE_ATTRIBUTES", Const, 0}, + {"IN_ACCESS", Const, 0}, + {"IN_ALL_EVENTS", Const, 0}, + {"IN_ATTRIB", Const, 0}, + {"IN_CLASSA_HOST", Const, 0}, + {"IN_CLASSA_MAX", Const, 0}, + {"IN_CLASSA_NET", Const, 0}, + {"IN_CLASSA_NSHIFT", Const, 0}, + {"IN_CLASSB_HOST", Const, 0}, + {"IN_CLASSB_MAX", Const, 0}, + {"IN_CLASSB_NET", Const, 0}, + {"IN_CLASSB_NSHIFT", Const, 0}, + {"IN_CLASSC_HOST", Const, 0}, + {"IN_CLASSC_NET", Const, 0}, + {"IN_CLASSC_NSHIFT", Const, 0}, + {"IN_CLASSD_HOST", Const, 0}, + {"IN_CLASSD_NET", Const, 0}, + {"IN_CLASSD_NSHIFT", Const, 0}, + {"IN_CLOEXEC", Const, 0}, + {"IN_CLOSE", Const, 0}, + {"IN_CLOSE_NOWRITE", Const, 0}, + {"IN_CLOSE_WRITE", Const, 0}, + {"IN_CREATE", Const, 0}, + {"IN_DELETE", Const, 0}, + {"IN_DELETE_SELF", Const, 0}, + {"IN_DONT_FOLLOW", Const, 0}, + {"IN_EXCL_UNLINK", Const, 0}, + {"IN_IGNORED", Const, 0}, + {"IN_ISDIR", Const, 0}, + {"IN_LINKLOCALNETNUM", Const, 0}, + {"IN_LOOPBACKNET", Const, 0}, + {"IN_MASK_ADD", Const, 0}, + {"IN_MODIFY", Const, 0}, + {"IN_MOVE", Const, 0}, + {"IN_MOVED_FROM", Const, 0}, + {"IN_MOVED_TO", Const, 0}, + {"IN_MOVE_SELF", Const, 0}, + {"IN_NONBLOCK", Const, 0}, + {"IN_ONESHOT", Const, 0}, + {"IN_ONLYDIR", Const, 0}, + {"IN_OPEN", Const, 0}, + {"IN_Q_OVERFLOW", Const, 0}, + {"IN_RFC3021_HOST", Const, 1}, + {"IN_RFC3021_MASK", Const, 1}, + {"IN_RFC3021_NET", Const, 1}, + {"IN_RFC3021_NSHIFT", Const, 1}, + {"IN_UNMOUNT", Const, 0}, + {"IOC_IN", Const, 1}, + {"IOC_INOUT", Const, 1}, + {"IOC_OUT", Const, 1}, + {"IOC_VENDOR", Const, 3}, + {"IOC_WS2", Const, 1}, + {"IO_REPARSE_TAG_SYMLINK", Const, 4}, + {"IPMreq", Type, 0}, + {"IPMreq.Interface", Field, 0}, + {"IPMreq.Multiaddr", Field, 0}, + {"IPMreqn", Type, 0}, + {"IPMreqn.Address", Field, 0}, + {"IPMreqn.Ifindex", Field, 0}, + {"IPMreqn.Multiaddr", Field, 0}, + {"IPPROTO_3PC", Const, 0}, + {"IPPROTO_ADFS", Const, 0}, + {"IPPROTO_AH", Const, 0}, + {"IPPROTO_AHIP", Const, 0}, + {"IPPROTO_APES", Const, 0}, + {"IPPROTO_ARGUS", Const, 0}, + {"IPPROTO_AX25", Const, 0}, + {"IPPROTO_BHA", Const, 0}, + {"IPPROTO_BLT", Const, 0}, + {"IPPROTO_BRSATMON", Const, 0}, + {"IPPROTO_CARP", Const, 0}, + {"IPPROTO_CFTP", Const, 0}, + {"IPPROTO_CHAOS", Const, 0}, + {"IPPROTO_CMTP", Const, 0}, + {"IPPROTO_COMP", Const, 0}, + {"IPPROTO_CPHB", Const, 0}, + {"IPPROTO_CPNX", Const, 0}, + {"IPPROTO_DCCP", Const, 0}, + {"IPPROTO_DDP", Const, 0}, + {"IPPROTO_DGP", Const, 0}, + {"IPPROTO_DIVERT", Const, 0}, + {"IPPROTO_DIVERT_INIT", Const, 3}, + {"IPPROTO_DIVERT_RESP", Const, 3}, + {"IPPROTO_DONE", Const, 0}, + {"IPPROTO_DSTOPTS", Const, 0}, + {"IPPROTO_EGP", Const, 0}, + {"IPPROTO_EMCON", Const, 0}, + {"IPPROTO_ENCAP", Const, 0}, + {"IPPROTO_EON", Const, 0}, + {"IPPROTO_ESP", Const, 0}, + {"IPPROTO_ETHERIP", Const, 0}, + {"IPPROTO_FRAGMENT", Const, 0}, + {"IPPROTO_GGP", Const, 0}, + {"IPPROTO_GMTP", Const, 0}, + {"IPPROTO_GRE", Const, 0}, + {"IPPROTO_HELLO", Const, 0}, + {"IPPROTO_HMP", Const, 0}, + {"IPPROTO_HOPOPTS", Const, 0}, + {"IPPROTO_ICMP", Const, 0}, + {"IPPROTO_ICMPV6", Const, 0}, + {"IPPROTO_IDP", Const, 0}, + {"IPPROTO_IDPR", Const, 0}, + {"IPPROTO_IDRP", Const, 0}, + {"IPPROTO_IGMP", Const, 0}, + {"IPPROTO_IGP", Const, 0}, + {"IPPROTO_IGRP", Const, 0}, + {"IPPROTO_IL", Const, 0}, + {"IPPROTO_INLSP", Const, 0}, + {"IPPROTO_INP", Const, 0}, + {"IPPROTO_IP", Const, 0}, + {"IPPROTO_IPCOMP", Const, 0}, + {"IPPROTO_IPCV", Const, 0}, + {"IPPROTO_IPEIP", Const, 0}, + {"IPPROTO_IPIP", Const, 0}, + {"IPPROTO_IPPC", Const, 0}, + {"IPPROTO_IPV4", Const, 0}, + {"IPPROTO_IPV6", Const, 0}, + {"IPPROTO_IPV6_ICMP", Const, 1}, + {"IPPROTO_IRTP", Const, 0}, + {"IPPROTO_KRYPTOLAN", Const, 0}, + {"IPPROTO_LARP", Const, 0}, + {"IPPROTO_LEAF1", Const, 0}, + {"IPPROTO_LEAF2", Const, 0}, + {"IPPROTO_MAX", Const, 0}, + {"IPPROTO_MAXID", Const, 0}, + {"IPPROTO_MEAS", Const, 0}, + {"IPPROTO_MH", Const, 1}, + {"IPPROTO_MHRP", Const, 0}, + {"IPPROTO_MICP", Const, 0}, + {"IPPROTO_MOBILE", Const, 0}, + {"IPPROTO_MPLS", Const, 1}, + {"IPPROTO_MTP", Const, 0}, + {"IPPROTO_MUX", Const, 0}, + {"IPPROTO_ND", Const, 0}, + {"IPPROTO_NHRP", Const, 0}, + {"IPPROTO_NONE", Const, 0}, + {"IPPROTO_NSP", Const, 0}, + {"IPPROTO_NVPII", Const, 0}, + {"IPPROTO_OLD_DIVERT", Const, 0}, + {"IPPROTO_OSPFIGP", Const, 0}, + {"IPPROTO_PFSYNC", Const, 0}, + {"IPPROTO_PGM", Const, 0}, + {"IPPROTO_PIGP", Const, 0}, + {"IPPROTO_PIM", Const, 0}, + {"IPPROTO_PRM", Const, 0}, + {"IPPROTO_PUP", Const, 0}, + {"IPPROTO_PVP", Const, 0}, + {"IPPROTO_RAW", Const, 0}, + {"IPPROTO_RCCMON", Const, 0}, + {"IPPROTO_RDP", Const, 0}, + {"IPPROTO_ROUTING", Const, 0}, + {"IPPROTO_RSVP", Const, 0}, + {"IPPROTO_RVD", Const, 0}, + {"IPPROTO_SATEXPAK", Const, 0}, + {"IPPROTO_SATMON", Const, 0}, + {"IPPROTO_SCCSP", Const, 0}, + {"IPPROTO_SCTP", Const, 0}, + {"IPPROTO_SDRP", Const, 0}, + {"IPPROTO_SEND", Const, 1}, + {"IPPROTO_SEP", Const, 0}, + {"IPPROTO_SKIP", Const, 0}, + {"IPPROTO_SPACER", Const, 0}, + {"IPPROTO_SRPC", Const, 0}, + {"IPPROTO_ST", Const, 0}, + {"IPPROTO_SVMTP", Const, 0}, + {"IPPROTO_SWIPE", Const, 0}, + {"IPPROTO_TCF", Const, 0}, + {"IPPROTO_TCP", Const, 0}, + {"IPPROTO_TLSP", Const, 0}, + {"IPPROTO_TP", Const, 0}, + {"IPPROTO_TPXX", Const, 0}, + {"IPPROTO_TRUNK1", Const, 0}, + {"IPPROTO_TRUNK2", Const, 0}, + {"IPPROTO_TTP", Const, 0}, + {"IPPROTO_UDP", Const, 0}, + {"IPPROTO_UDPLITE", Const, 0}, + {"IPPROTO_VINES", Const, 0}, + {"IPPROTO_VISA", Const, 0}, + {"IPPROTO_VMTP", Const, 0}, + {"IPPROTO_VRRP", Const, 1}, + {"IPPROTO_WBEXPAK", Const, 0}, + {"IPPROTO_WBMON", Const, 0}, + {"IPPROTO_WSN", Const, 0}, + {"IPPROTO_XNET", Const, 0}, + {"IPPROTO_XTP", Const, 0}, + {"IPV6_2292DSTOPTS", Const, 0}, + {"IPV6_2292HOPLIMIT", Const, 0}, + {"IPV6_2292HOPOPTS", Const, 0}, + {"IPV6_2292NEXTHOP", Const, 0}, + {"IPV6_2292PKTINFO", Const, 0}, + {"IPV6_2292PKTOPTIONS", Const, 0}, + {"IPV6_2292RTHDR", Const, 0}, + {"IPV6_ADDRFORM", Const, 0}, + {"IPV6_ADD_MEMBERSHIP", Const, 0}, + {"IPV6_AUTHHDR", Const, 0}, + {"IPV6_AUTH_LEVEL", Const, 1}, + {"IPV6_AUTOFLOWLABEL", Const, 0}, + {"IPV6_BINDANY", Const, 0}, + {"IPV6_BINDV6ONLY", Const, 0}, + {"IPV6_BOUND_IF", Const, 0}, + {"IPV6_CHECKSUM", Const, 0}, + {"IPV6_DEFAULT_MULTICAST_HOPS", Const, 0}, + {"IPV6_DEFAULT_MULTICAST_LOOP", Const, 0}, + {"IPV6_DEFHLIM", Const, 0}, + {"IPV6_DONTFRAG", Const, 0}, + {"IPV6_DROP_MEMBERSHIP", Const, 0}, + {"IPV6_DSTOPTS", Const, 0}, + {"IPV6_ESP_NETWORK_LEVEL", Const, 1}, + {"IPV6_ESP_TRANS_LEVEL", Const, 1}, + {"IPV6_FAITH", Const, 0}, + {"IPV6_FLOWINFO_MASK", Const, 0}, + {"IPV6_FLOWLABEL_MASK", Const, 0}, + {"IPV6_FRAGTTL", Const, 0}, + {"IPV6_FW_ADD", Const, 0}, + {"IPV6_FW_DEL", Const, 0}, + {"IPV6_FW_FLUSH", Const, 0}, + {"IPV6_FW_GET", Const, 0}, + {"IPV6_FW_ZERO", Const, 0}, + {"IPV6_HLIMDEC", Const, 0}, + {"IPV6_HOPLIMIT", Const, 0}, + {"IPV6_HOPOPTS", Const, 0}, + {"IPV6_IPCOMP_LEVEL", Const, 1}, + {"IPV6_IPSEC_POLICY", Const, 0}, + {"IPV6_JOIN_ANYCAST", Const, 0}, + {"IPV6_JOIN_GROUP", Const, 0}, + {"IPV6_LEAVE_ANYCAST", Const, 0}, + {"IPV6_LEAVE_GROUP", Const, 0}, + {"IPV6_MAXHLIM", Const, 0}, + {"IPV6_MAXOPTHDR", Const, 0}, + {"IPV6_MAXPACKET", Const, 0}, + {"IPV6_MAX_GROUP_SRC_FILTER", Const, 0}, + {"IPV6_MAX_MEMBERSHIPS", Const, 0}, + {"IPV6_MAX_SOCK_SRC_FILTER", Const, 0}, + {"IPV6_MIN_MEMBERSHIPS", Const, 0}, + {"IPV6_MMTU", Const, 0}, + {"IPV6_MSFILTER", Const, 0}, + {"IPV6_MTU", Const, 0}, + {"IPV6_MTU_DISCOVER", Const, 0}, + {"IPV6_MULTICAST_HOPS", Const, 0}, + {"IPV6_MULTICAST_IF", Const, 0}, + {"IPV6_MULTICAST_LOOP", Const, 0}, + {"IPV6_NEXTHOP", Const, 0}, + {"IPV6_OPTIONS", Const, 1}, + {"IPV6_PATHMTU", Const, 0}, + {"IPV6_PIPEX", Const, 1}, + {"IPV6_PKTINFO", Const, 0}, + {"IPV6_PMTUDISC_DO", Const, 0}, + {"IPV6_PMTUDISC_DONT", Const, 0}, + {"IPV6_PMTUDISC_PROBE", Const, 0}, + {"IPV6_PMTUDISC_WANT", Const, 0}, + {"IPV6_PORTRANGE", Const, 0}, + {"IPV6_PORTRANGE_DEFAULT", Const, 0}, + {"IPV6_PORTRANGE_HIGH", Const, 0}, + {"IPV6_PORTRANGE_LOW", Const, 0}, + {"IPV6_PREFER_TEMPADDR", Const, 0}, + {"IPV6_RECVDSTOPTS", Const, 0}, + {"IPV6_RECVDSTPORT", Const, 3}, + {"IPV6_RECVERR", Const, 0}, + {"IPV6_RECVHOPLIMIT", Const, 0}, + {"IPV6_RECVHOPOPTS", Const, 0}, + {"IPV6_RECVPATHMTU", Const, 0}, + {"IPV6_RECVPKTINFO", Const, 0}, + {"IPV6_RECVRTHDR", Const, 0}, + {"IPV6_RECVTCLASS", Const, 0}, + {"IPV6_ROUTER_ALERT", Const, 0}, + {"IPV6_RTABLE", Const, 1}, + {"IPV6_RTHDR", Const, 0}, + {"IPV6_RTHDRDSTOPTS", Const, 0}, + {"IPV6_RTHDR_LOOSE", Const, 0}, + {"IPV6_RTHDR_STRICT", Const, 0}, + {"IPV6_RTHDR_TYPE_0", Const, 0}, + {"IPV6_RXDSTOPTS", Const, 0}, + {"IPV6_RXHOPOPTS", Const, 0}, + {"IPV6_SOCKOPT_RESERVED1", Const, 0}, + {"IPV6_TCLASS", Const, 0}, + {"IPV6_UNICAST_HOPS", Const, 0}, + {"IPV6_USE_MIN_MTU", Const, 0}, + {"IPV6_V6ONLY", Const, 0}, + {"IPV6_VERSION", Const, 0}, + {"IPV6_VERSION_MASK", Const, 0}, + {"IPV6_XFRM_POLICY", Const, 0}, + {"IP_ADD_MEMBERSHIP", Const, 0}, + {"IP_ADD_SOURCE_MEMBERSHIP", Const, 0}, + {"IP_AUTH_LEVEL", Const, 1}, + {"IP_BINDANY", Const, 0}, + {"IP_BLOCK_SOURCE", Const, 0}, + {"IP_BOUND_IF", Const, 0}, + {"IP_DEFAULT_MULTICAST_LOOP", Const, 0}, + {"IP_DEFAULT_MULTICAST_TTL", Const, 0}, + {"IP_DF", Const, 0}, + {"IP_DIVERTFL", Const, 3}, + {"IP_DONTFRAG", Const, 0}, + {"IP_DROP_MEMBERSHIP", Const, 0}, + {"IP_DROP_SOURCE_MEMBERSHIP", Const, 0}, + {"IP_DUMMYNET3", Const, 0}, + {"IP_DUMMYNET_CONFIGURE", Const, 0}, + {"IP_DUMMYNET_DEL", Const, 0}, + {"IP_DUMMYNET_FLUSH", Const, 0}, + {"IP_DUMMYNET_GET", Const, 0}, + {"IP_EF", Const, 1}, + {"IP_ERRORMTU", Const, 1}, + {"IP_ESP_NETWORK_LEVEL", Const, 1}, + {"IP_ESP_TRANS_LEVEL", Const, 1}, + {"IP_FAITH", Const, 0}, + {"IP_FREEBIND", Const, 0}, + {"IP_FW3", Const, 0}, + {"IP_FW_ADD", Const, 0}, + {"IP_FW_DEL", Const, 0}, + {"IP_FW_FLUSH", Const, 0}, + {"IP_FW_GET", Const, 0}, + {"IP_FW_NAT_CFG", Const, 0}, + {"IP_FW_NAT_DEL", Const, 0}, + {"IP_FW_NAT_GET_CONFIG", Const, 0}, + {"IP_FW_NAT_GET_LOG", Const, 0}, + {"IP_FW_RESETLOG", Const, 0}, + {"IP_FW_TABLE_ADD", Const, 0}, + {"IP_FW_TABLE_DEL", Const, 0}, + {"IP_FW_TABLE_FLUSH", Const, 0}, + {"IP_FW_TABLE_GETSIZE", Const, 0}, + {"IP_FW_TABLE_LIST", Const, 0}, + {"IP_FW_ZERO", Const, 0}, + {"IP_HDRINCL", Const, 0}, + {"IP_IPCOMP_LEVEL", Const, 1}, + {"IP_IPSECFLOWINFO", Const, 1}, + {"IP_IPSEC_LOCAL_AUTH", Const, 1}, + {"IP_IPSEC_LOCAL_CRED", Const, 1}, + {"IP_IPSEC_LOCAL_ID", Const, 1}, + {"IP_IPSEC_POLICY", Const, 0}, + {"IP_IPSEC_REMOTE_AUTH", Const, 1}, + {"IP_IPSEC_REMOTE_CRED", Const, 1}, + {"IP_IPSEC_REMOTE_ID", Const, 1}, + {"IP_MAXPACKET", Const, 0}, + {"IP_MAX_GROUP_SRC_FILTER", Const, 0}, + {"IP_MAX_MEMBERSHIPS", Const, 0}, + {"IP_MAX_SOCK_MUTE_FILTER", Const, 0}, + {"IP_MAX_SOCK_SRC_FILTER", Const, 0}, + {"IP_MAX_SOURCE_FILTER", Const, 0}, + {"IP_MF", Const, 0}, + {"IP_MINFRAGSIZE", Const, 1}, + {"IP_MINTTL", Const, 0}, + {"IP_MIN_MEMBERSHIPS", Const, 0}, + {"IP_MSFILTER", Const, 0}, + {"IP_MSS", Const, 0}, + {"IP_MTU", Const, 0}, + {"IP_MTU_DISCOVER", Const, 0}, + {"IP_MULTICAST_IF", Const, 0}, + {"IP_MULTICAST_IFINDEX", Const, 0}, + {"IP_MULTICAST_LOOP", Const, 0}, + {"IP_MULTICAST_TTL", Const, 0}, + {"IP_MULTICAST_VIF", Const, 0}, + {"IP_NAT__XXX", Const, 0}, + {"IP_OFFMASK", Const, 0}, + {"IP_OLD_FW_ADD", Const, 0}, + {"IP_OLD_FW_DEL", Const, 0}, + {"IP_OLD_FW_FLUSH", Const, 0}, + {"IP_OLD_FW_GET", Const, 0}, + {"IP_OLD_FW_RESETLOG", Const, 0}, + {"IP_OLD_FW_ZERO", Const, 0}, + {"IP_ONESBCAST", Const, 0}, + {"IP_OPTIONS", Const, 0}, + {"IP_ORIGDSTADDR", Const, 0}, + {"IP_PASSSEC", Const, 0}, + {"IP_PIPEX", Const, 1}, + {"IP_PKTINFO", Const, 0}, + {"IP_PKTOPTIONS", Const, 0}, + {"IP_PMTUDISC", Const, 0}, + {"IP_PMTUDISC_DO", Const, 0}, + {"IP_PMTUDISC_DONT", Const, 0}, + {"IP_PMTUDISC_PROBE", Const, 0}, + {"IP_PMTUDISC_WANT", Const, 0}, + {"IP_PORTRANGE", Const, 0}, + {"IP_PORTRANGE_DEFAULT", Const, 0}, + {"IP_PORTRANGE_HIGH", Const, 0}, + {"IP_PORTRANGE_LOW", Const, 0}, + {"IP_RECVDSTADDR", Const, 0}, + {"IP_RECVDSTPORT", Const, 1}, + {"IP_RECVERR", Const, 0}, + {"IP_RECVIF", Const, 0}, + {"IP_RECVOPTS", Const, 0}, + {"IP_RECVORIGDSTADDR", Const, 0}, + {"IP_RECVPKTINFO", Const, 0}, + {"IP_RECVRETOPTS", Const, 0}, + {"IP_RECVRTABLE", Const, 1}, + {"IP_RECVTOS", Const, 0}, + {"IP_RECVTTL", Const, 0}, + {"IP_RETOPTS", Const, 0}, + {"IP_RF", Const, 0}, + {"IP_ROUTER_ALERT", Const, 0}, + {"IP_RSVP_OFF", Const, 0}, + {"IP_RSVP_ON", Const, 0}, + {"IP_RSVP_VIF_OFF", Const, 0}, + {"IP_RSVP_VIF_ON", Const, 0}, + {"IP_RTABLE", Const, 1}, + {"IP_SENDSRCADDR", Const, 0}, + {"IP_STRIPHDR", Const, 0}, + {"IP_TOS", Const, 0}, + {"IP_TRAFFIC_MGT_BACKGROUND", Const, 0}, + {"IP_TRANSPARENT", Const, 0}, + {"IP_TTL", Const, 0}, + {"IP_UNBLOCK_SOURCE", Const, 0}, + {"IP_XFRM_POLICY", Const, 0}, + {"IPv6MTUInfo", Type, 2}, + {"IPv6MTUInfo.Addr", Field, 2}, + {"IPv6MTUInfo.Mtu", Field, 2}, + {"IPv6Mreq", Type, 0}, + {"IPv6Mreq.Interface", Field, 0}, + {"IPv6Mreq.Multiaddr", Field, 0}, + {"ISIG", Const, 0}, + {"ISTRIP", Const, 0}, + {"IUCLC", Const, 0}, + {"IUTF8", Const, 0}, + {"IXANY", Const, 0}, + {"IXOFF", Const, 0}, + {"IXON", Const, 0}, + {"IfAddrmsg", Type, 0}, + {"IfAddrmsg.Family", Field, 0}, + {"IfAddrmsg.Flags", Field, 0}, + {"IfAddrmsg.Index", Field, 0}, + {"IfAddrmsg.Prefixlen", Field, 0}, + {"IfAddrmsg.Scope", Field, 0}, + {"IfAnnounceMsghdr", Type, 1}, + {"IfAnnounceMsghdr.Hdrlen", Field, 2}, + {"IfAnnounceMsghdr.Index", Field, 1}, + {"IfAnnounceMsghdr.Msglen", Field, 1}, + {"IfAnnounceMsghdr.Name", Field, 1}, + {"IfAnnounceMsghdr.Type", Field, 1}, + {"IfAnnounceMsghdr.Version", Field, 1}, + {"IfAnnounceMsghdr.What", Field, 1}, + {"IfData", Type, 0}, + {"IfData.Addrlen", Field, 0}, + {"IfData.Baudrate", Field, 0}, + {"IfData.Capabilities", Field, 2}, + {"IfData.Collisions", Field, 0}, + {"IfData.Datalen", Field, 0}, + {"IfData.Epoch", Field, 0}, + {"IfData.Hdrlen", Field, 0}, + {"IfData.Hwassist", Field, 0}, + {"IfData.Ibytes", Field, 0}, + {"IfData.Ierrors", Field, 0}, + {"IfData.Imcasts", Field, 0}, + {"IfData.Ipackets", Field, 0}, + {"IfData.Iqdrops", Field, 0}, + {"IfData.Lastchange", Field, 0}, + {"IfData.Link_state", Field, 0}, + {"IfData.Mclpool", Field, 2}, + {"IfData.Metric", Field, 0}, + {"IfData.Mtu", Field, 0}, + {"IfData.Noproto", Field, 0}, + {"IfData.Obytes", Field, 0}, + {"IfData.Oerrors", Field, 0}, + {"IfData.Omcasts", Field, 0}, + {"IfData.Opackets", Field, 0}, + {"IfData.Pad", Field, 2}, + {"IfData.Pad_cgo_0", Field, 2}, + {"IfData.Pad_cgo_1", Field, 2}, + {"IfData.Physical", Field, 0}, + {"IfData.Recvquota", Field, 0}, + {"IfData.Recvtiming", Field, 0}, + {"IfData.Reserved1", Field, 0}, + {"IfData.Reserved2", Field, 0}, + {"IfData.Spare_char1", Field, 0}, + {"IfData.Spare_char2", Field, 0}, + {"IfData.Type", Field, 0}, + {"IfData.Typelen", Field, 0}, + {"IfData.Unused1", Field, 0}, + {"IfData.Unused2", Field, 0}, + {"IfData.Xmitquota", Field, 0}, + {"IfData.Xmittiming", Field, 0}, + {"IfInfomsg", Type, 0}, + {"IfInfomsg.Change", Field, 0}, + {"IfInfomsg.Family", Field, 0}, + {"IfInfomsg.Flags", Field, 0}, + {"IfInfomsg.Index", Field, 0}, + {"IfInfomsg.Type", Field, 0}, + {"IfInfomsg.X__ifi_pad", Field, 0}, + {"IfMsghdr", Type, 0}, + {"IfMsghdr.Addrs", Field, 0}, + {"IfMsghdr.Data", Field, 0}, + {"IfMsghdr.Flags", Field, 0}, + {"IfMsghdr.Hdrlen", Field, 2}, + {"IfMsghdr.Index", Field, 0}, + {"IfMsghdr.Msglen", Field, 0}, + {"IfMsghdr.Pad1", Field, 2}, + {"IfMsghdr.Pad2", Field, 2}, + {"IfMsghdr.Pad_cgo_0", Field, 0}, + {"IfMsghdr.Pad_cgo_1", Field, 2}, + {"IfMsghdr.Tableid", Field, 2}, + {"IfMsghdr.Type", Field, 0}, + {"IfMsghdr.Version", Field, 0}, + {"IfMsghdr.Xflags", Field, 2}, + {"IfaMsghdr", Type, 0}, + {"IfaMsghdr.Addrs", Field, 0}, + {"IfaMsghdr.Flags", Field, 0}, + {"IfaMsghdr.Hdrlen", Field, 2}, + {"IfaMsghdr.Index", Field, 0}, + {"IfaMsghdr.Metric", Field, 0}, + {"IfaMsghdr.Msglen", Field, 0}, + {"IfaMsghdr.Pad1", Field, 2}, + {"IfaMsghdr.Pad2", Field, 2}, + {"IfaMsghdr.Pad_cgo_0", Field, 0}, + {"IfaMsghdr.Tableid", Field, 2}, + {"IfaMsghdr.Type", Field, 0}, + {"IfaMsghdr.Version", Field, 0}, + {"IfmaMsghdr", Type, 0}, + {"IfmaMsghdr.Addrs", Field, 0}, + {"IfmaMsghdr.Flags", Field, 0}, + {"IfmaMsghdr.Index", Field, 0}, + {"IfmaMsghdr.Msglen", Field, 0}, + {"IfmaMsghdr.Pad_cgo_0", Field, 0}, + {"IfmaMsghdr.Type", Field, 0}, + {"IfmaMsghdr.Version", Field, 0}, + {"IfmaMsghdr2", Type, 0}, + {"IfmaMsghdr2.Addrs", Field, 0}, + {"IfmaMsghdr2.Flags", Field, 0}, + {"IfmaMsghdr2.Index", Field, 0}, + {"IfmaMsghdr2.Msglen", Field, 0}, + {"IfmaMsghdr2.Pad_cgo_0", Field, 0}, + {"IfmaMsghdr2.Refcount", Field, 0}, + {"IfmaMsghdr2.Type", Field, 0}, + {"IfmaMsghdr2.Version", Field, 0}, + {"ImplementsGetwd", Const, 0}, + {"Inet4Pktinfo", Type, 0}, + {"Inet4Pktinfo.Addr", Field, 0}, + {"Inet4Pktinfo.Ifindex", Field, 0}, + {"Inet4Pktinfo.Spec_dst", Field, 0}, + {"Inet6Pktinfo", Type, 0}, + {"Inet6Pktinfo.Addr", Field, 0}, + {"Inet6Pktinfo.Ifindex", Field, 0}, + {"InotifyAddWatch", Func, 0}, + {"InotifyEvent", Type, 0}, + {"InotifyEvent.Cookie", Field, 0}, + {"InotifyEvent.Len", Field, 0}, + {"InotifyEvent.Mask", Field, 0}, + {"InotifyEvent.Name", Field, 0}, + {"InotifyEvent.Wd", Field, 0}, + {"InotifyInit", Func, 0}, + {"InotifyInit1", Func, 0}, + {"InotifyRmWatch", Func, 0}, + {"InterfaceAddrMessage", Type, 0}, + {"InterfaceAddrMessage.Data", Field, 0}, + {"InterfaceAddrMessage.Header", Field, 0}, + {"InterfaceAnnounceMessage", Type, 1}, + {"InterfaceAnnounceMessage.Header", Field, 1}, + {"InterfaceInfo", Type, 0}, + {"InterfaceInfo.Address", Field, 0}, + {"InterfaceInfo.BroadcastAddress", Field, 0}, + {"InterfaceInfo.Flags", Field, 0}, + {"InterfaceInfo.Netmask", Field, 0}, + {"InterfaceMessage", Type, 0}, + {"InterfaceMessage.Data", Field, 0}, + {"InterfaceMessage.Header", Field, 0}, + {"InterfaceMulticastAddrMessage", Type, 0}, + {"InterfaceMulticastAddrMessage.Data", Field, 0}, + {"InterfaceMulticastAddrMessage.Header", Field, 0}, + {"InvalidHandle", Const, 0}, + {"Ioperm", Func, 0}, + {"Iopl", Func, 0}, + {"Iovec", Type, 0}, + {"Iovec.Base", Field, 0}, + {"Iovec.Len", Field, 0}, + {"IpAdapterInfo", Type, 0}, + {"IpAdapterInfo.AdapterName", Field, 0}, + {"IpAdapterInfo.Address", Field, 0}, + {"IpAdapterInfo.AddressLength", Field, 0}, + {"IpAdapterInfo.ComboIndex", Field, 0}, + {"IpAdapterInfo.CurrentIpAddress", Field, 0}, + {"IpAdapterInfo.Description", Field, 0}, + {"IpAdapterInfo.DhcpEnabled", Field, 0}, + {"IpAdapterInfo.DhcpServer", Field, 0}, + {"IpAdapterInfo.GatewayList", Field, 0}, + {"IpAdapterInfo.HaveWins", Field, 0}, + {"IpAdapterInfo.Index", Field, 0}, + {"IpAdapterInfo.IpAddressList", Field, 0}, + {"IpAdapterInfo.LeaseExpires", Field, 0}, + {"IpAdapterInfo.LeaseObtained", Field, 0}, + {"IpAdapterInfo.Next", Field, 0}, + {"IpAdapterInfo.PrimaryWinsServer", Field, 0}, + {"IpAdapterInfo.SecondaryWinsServer", Field, 0}, + {"IpAdapterInfo.Type", Field, 0}, + {"IpAddrString", Type, 0}, + {"IpAddrString.Context", Field, 0}, + {"IpAddrString.IpAddress", Field, 0}, + {"IpAddrString.IpMask", Field, 0}, + {"IpAddrString.Next", Field, 0}, + {"IpAddressString", Type, 0}, + {"IpAddressString.String", Field, 0}, + {"IpMaskString", Type, 0}, + {"IpMaskString.String", Field, 2}, + {"Issetugid", Func, 0}, + {"KEY_ALL_ACCESS", Const, 0}, + {"KEY_CREATE_LINK", Const, 0}, + {"KEY_CREATE_SUB_KEY", Const, 0}, + {"KEY_ENUMERATE_SUB_KEYS", Const, 0}, + {"KEY_EXECUTE", Const, 0}, + {"KEY_NOTIFY", Const, 0}, + {"KEY_QUERY_VALUE", Const, 0}, + {"KEY_READ", Const, 0}, + {"KEY_SET_VALUE", Const, 0}, + {"KEY_WOW64_32KEY", Const, 0}, + {"KEY_WOW64_64KEY", Const, 0}, + {"KEY_WRITE", Const, 0}, + {"Kevent", Func, 0}, + {"Kevent_t", Type, 0}, + {"Kevent_t.Data", Field, 0}, + {"Kevent_t.Fflags", Field, 0}, + {"Kevent_t.Filter", Field, 0}, + {"Kevent_t.Flags", Field, 0}, + {"Kevent_t.Ident", Field, 0}, + {"Kevent_t.Pad_cgo_0", Field, 2}, + {"Kevent_t.Udata", Field, 0}, + {"Kill", Func, 0}, + {"Klogctl", Func, 0}, + {"Kqueue", Func, 0}, + {"LANG_ENGLISH", Const, 0}, + {"LAYERED_PROTOCOL", Const, 2}, + {"LCNT_OVERLOAD_FLUSH", Const, 1}, + {"LINUX_REBOOT_CMD_CAD_OFF", Const, 0}, + {"LINUX_REBOOT_CMD_CAD_ON", Const, 0}, + {"LINUX_REBOOT_CMD_HALT", Const, 0}, + {"LINUX_REBOOT_CMD_KEXEC", Const, 0}, + {"LINUX_REBOOT_CMD_POWER_OFF", Const, 0}, + {"LINUX_REBOOT_CMD_RESTART", Const, 0}, + {"LINUX_REBOOT_CMD_RESTART2", Const, 0}, + {"LINUX_REBOOT_CMD_SW_SUSPEND", Const, 0}, + {"LINUX_REBOOT_MAGIC1", Const, 0}, + {"LINUX_REBOOT_MAGIC2", Const, 0}, + {"LOCK_EX", Const, 0}, + {"LOCK_NB", Const, 0}, + {"LOCK_SH", Const, 0}, + {"LOCK_UN", Const, 0}, + {"LazyDLL", Type, 0}, + {"LazyDLL.Name", Field, 0}, + {"LazyProc", Type, 0}, + {"LazyProc.Name", Field, 0}, + {"Lchown", Func, 0}, + {"Linger", Type, 0}, + {"Linger.Linger", Field, 0}, + {"Linger.Onoff", Field, 0}, + {"Link", Func, 0}, + {"Listen", Func, 0}, + {"Listxattr", Func, 1}, + {"LoadCancelIoEx", Func, 1}, + {"LoadConnectEx", Func, 1}, + {"LoadCreateSymbolicLink", Func, 4}, + {"LoadDLL", Func, 0}, + {"LoadGetAddrInfo", Func, 1}, + {"LoadLibrary", Func, 0}, + {"LoadSetFileCompletionNotificationModes", Func, 2}, + {"LocalFree", Func, 0}, + {"Log2phys_t", Type, 0}, + {"Log2phys_t.Contigbytes", Field, 0}, + {"Log2phys_t.Devoffset", Field, 0}, + {"Log2phys_t.Flags", Field, 0}, + {"LookupAccountName", Func, 0}, + {"LookupAccountSid", Func, 0}, + {"LookupSID", Func, 0}, + {"LsfJump", Func, 0}, + {"LsfSocket", Func, 0}, + {"LsfStmt", Func, 0}, + {"Lstat", Func, 0}, + {"MADV_AUTOSYNC", Const, 1}, + {"MADV_CAN_REUSE", Const, 0}, + {"MADV_CORE", Const, 1}, + {"MADV_DOFORK", Const, 0}, + {"MADV_DONTFORK", Const, 0}, + {"MADV_DONTNEED", Const, 0}, + {"MADV_FREE", Const, 0}, + {"MADV_FREE_REUSABLE", Const, 0}, + {"MADV_FREE_REUSE", Const, 0}, + {"MADV_HUGEPAGE", Const, 0}, + {"MADV_HWPOISON", Const, 0}, + {"MADV_MERGEABLE", Const, 0}, + {"MADV_NOCORE", Const, 1}, + {"MADV_NOHUGEPAGE", Const, 0}, + {"MADV_NORMAL", Const, 0}, + {"MADV_NOSYNC", Const, 1}, + {"MADV_PROTECT", Const, 1}, + {"MADV_RANDOM", Const, 0}, + {"MADV_REMOVE", Const, 0}, + {"MADV_SEQUENTIAL", Const, 0}, + {"MADV_SPACEAVAIL", Const, 3}, + {"MADV_UNMERGEABLE", Const, 0}, + {"MADV_WILLNEED", Const, 0}, + {"MADV_ZERO_WIRED_PAGES", Const, 0}, + {"MAP_32BIT", Const, 0}, + {"MAP_ALIGNED_SUPER", Const, 3}, + {"MAP_ALIGNMENT_16MB", Const, 3}, + {"MAP_ALIGNMENT_1TB", Const, 3}, + {"MAP_ALIGNMENT_256TB", Const, 3}, + {"MAP_ALIGNMENT_4GB", Const, 3}, + {"MAP_ALIGNMENT_64KB", Const, 3}, + {"MAP_ALIGNMENT_64PB", Const, 3}, + {"MAP_ALIGNMENT_MASK", Const, 3}, + {"MAP_ALIGNMENT_SHIFT", Const, 3}, + {"MAP_ANON", Const, 0}, + {"MAP_ANONYMOUS", Const, 0}, + {"MAP_COPY", Const, 0}, + {"MAP_DENYWRITE", Const, 0}, + {"MAP_EXECUTABLE", Const, 0}, + {"MAP_FILE", Const, 0}, + {"MAP_FIXED", Const, 0}, + {"MAP_FLAGMASK", Const, 3}, + {"MAP_GROWSDOWN", Const, 0}, + {"MAP_HASSEMAPHORE", Const, 0}, + {"MAP_HUGETLB", Const, 0}, + {"MAP_INHERIT", Const, 3}, + {"MAP_INHERIT_COPY", Const, 3}, + {"MAP_INHERIT_DEFAULT", Const, 3}, + {"MAP_INHERIT_DONATE_COPY", Const, 3}, + {"MAP_INHERIT_NONE", Const, 3}, + {"MAP_INHERIT_SHARE", Const, 3}, + {"MAP_JIT", Const, 0}, + {"MAP_LOCKED", Const, 0}, + {"MAP_NOCACHE", Const, 0}, + {"MAP_NOCORE", Const, 1}, + {"MAP_NOEXTEND", Const, 0}, + {"MAP_NONBLOCK", Const, 0}, + {"MAP_NORESERVE", Const, 0}, + {"MAP_NOSYNC", Const, 1}, + {"MAP_POPULATE", Const, 0}, + {"MAP_PREFAULT_READ", Const, 1}, + {"MAP_PRIVATE", Const, 0}, + {"MAP_RENAME", Const, 0}, + {"MAP_RESERVED0080", Const, 0}, + {"MAP_RESERVED0100", Const, 1}, + {"MAP_SHARED", Const, 0}, + {"MAP_STACK", Const, 0}, + {"MAP_TRYFIXED", Const, 3}, + {"MAP_TYPE", Const, 0}, + {"MAP_WIRED", Const, 3}, + {"MAXIMUM_REPARSE_DATA_BUFFER_SIZE", Const, 4}, + {"MAXLEN_IFDESCR", Const, 0}, + {"MAXLEN_PHYSADDR", Const, 0}, + {"MAX_ADAPTER_ADDRESS_LENGTH", Const, 0}, + {"MAX_ADAPTER_DESCRIPTION_LENGTH", Const, 0}, + {"MAX_ADAPTER_NAME_LENGTH", Const, 0}, + {"MAX_COMPUTERNAME_LENGTH", Const, 0}, + {"MAX_INTERFACE_NAME_LEN", Const, 0}, + {"MAX_LONG_PATH", Const, 0}, + {"MAX_PATH", Const, 0}, + {"MAX_PROTOCOL_CHAIN", Const, 2}, + {"MCL_CURRENT", Const, 0}, + {"MCL_FUTURE", Const, 0}, + {"MNT_DETACH", Const, 0}, + {"MNT_EXPIRE", Const, 0}, + {"MNT_FORCE", Const, 0}, + {"MSG_BCAST", Const, 1}, + {"MSG_CMSG_CLOEXEC", Const, 0}, + {"MSG_COMPAT", Const, 0}, + {"MSG_CONFIRM", Const, 0}, + {"MSG_CONTROLMBUF", Const, 1}, + {"MSG_CTRUNC", Const, 0}, + {"MSG_DONTROUTE", Const, 0}, + {"MSG_DONTWAIT", Const, 0}, + {"MSG_EOF", Const, 0}, + {"MSG_EOR", Const, 0}, + {"MSG_ERRQUEUE", Const, 0}, + {"MSG_FASTOPEN", Const, 1}, + {"MSG_FIN", Const, 0}, + {"MSG_FLUSH", Const, 0}, + {"MSG_HAVEMORE", Const, 0}, + {"MSG_HOLD", Const, 0}, + {"MSG_IOVUSRSPACE", Const, 1}, + {"MSG_LENUSRSPACE", Const, 1}, + {"MSG_MCAST", Const, 1}, + {"MSG_MORE", Const, 0}, + {"MSG_NAMEMBUF", Const, 1}, + {"MSG_NBIO", Const, 0}, + {"MSG_NEEDSA", Const, 0}, + {"MSG_NOSIGNAL", Const, 0}, + {"MSG_NOTIFICATION", Const, 0}, + {"MSG_OOB", Const, 0}, + {"MSG_PEEK", Const, 0}, + {"MSG_PROXY", Const, 0}, + {"MSG_RCVMORE", Const, 0}, + {"MSG_RST", Const, 0}, + {"MSG_SEND", Const, 0}, + {"MSG_SYN", Const, 0}, + {"MSG_TRUNC", Const, 0}, + {"MSG_TRYHARD", Const, 0}, + {"MSG_USERFLAGS", Const, 1}, + {"MSG_WAITALL", Const, 0}, + {"MSG_WAITFORONE", Const, 0}, + {"MSG_WAITSTREAM", Const, 0}, + {"MS_ACTIVE", Const, 0}, + {"MS_ASYNC", Const, 0}, + {"MS_BIND", Const, 0}, + {"MS_DEACTIVATE", Const, 0}, + {"MS_DIRSYNC", Const, 0}, + {"MS_INVALIDATE", Const, 0}, + {"MS_I_VERSION", Const, 0}, + {"MS_KERNMOUNT", Const, 0}, + {"MS_KILLPAGES", Const, 0}, + {"MS_MANDLOCK", Const, 0}, + {"MS_MGC_MSK", Const, 0}, + {"MS_MGC_VAL", Const, 0}, + {"MS_MOVE", Const, 0}, + {"MS_NOATIME", Const, 0}, + {"MS_NODEV", Const, 0}, + {"MS_NODIRATIME", Const, 0}, + {"MS_NOEXEC", Const, 0}, + {"MS_NOSUID", Const, 0}, + {"MS_NOUSER", Const, 0}, + {"MS_POSIXACL", Const, 0}, + {"MS_PRIVATE", Const, 0}, + {"MS_RDONLY", Const, 0}, + {"MS_REC", Const, 0}, + {"MS_RELATIME", Const, 0}, + {"MS_REMOUNT", Const, 0}, + {"MS_RMT_MASK", Const, 0}, + {"MS_SHARED", Const, 0}, + {"MS_SILENT", Const, 0}, + {"MS_SLAVE", Const, 0}, + {"MS_STRICTATIME", Const, 0}, + {"MS_SYNC", Const, 0}, + {"MS_SYNCHRONOUS", Const, 0}, + {"MS_UNBINDABLE", Const, 0}, + {"Madvise", Func, 0}, + {"MapViewOfFile", Func, 0}, + {"MaxTokenInfoClass", Const, 0}, + {"Mclpool", Type, 2}, + {"Mclpool.Alive", Field, 2}, + {"Mclpool.Cwm", Field, 2}, + {"Mclpool.Grown", Field, 2}, + {"Mclpool.Hwm", Field, 2}, + {"Mclpool.Lwm", Field, 2}, + {"MibIfRow", Type, 0}, + {"MibIfRow.AdminStatus", Field, 0}, + {"MibIfRow.Descr", Field, 0}, + {"MibIfRow.DescrLen", Field, 0}, + {"MibIfRow.InDiscards", Field, 0}, + {"MibIfRow.InErrors", Field, 0}, + {"MibIfRow.InNUcastPkts", Field, 0}, + {"MibIfRow.InOctets", Field, 0}, + {"MibIfRow.InUcastPkts", Field, 0}, + {"MibIfRow.InUnknownProtos", Field, 0}, + {"MibIfRow.Index", Field, 0}, + {"MibIfRow.LastChange", Field, 0}, + {"MibIfRow.Mtu", Field, 0}, + {"MibIfRow.Name", Field, 0}, + {"MibIfRow.OperStatus", Field, 0}, + {"MibIfRow.OutDiscards", Field, 0}, + {"MibIfRow.OutErrors", Field, 0}, + {"MibIfRow.OutNUcastPkts", Field, 0}, + {"MibIfRow.OutOctets", Field, 0}, + {"MibIfRow.OutQLen", Field, 0}, + {"MibIfRow.OutUcastPkts", Field, 0}, + {"MibIfRow.PhysAddr", Field, 0}, + {"MibIfRow.PhysAddrLen", Field, 0}, + {"MibIfRow.Speed", Field, 0}, + {"MibIfRow.Type", Field, 0}, + {"Mkdir", Func, 0}, + {"Mkdirat", Func, 0}, + {"Mkfifo", Func, 0}, + {"Mknod", Func, 0}, + {"Mknodat", Func, 0}, + {"Mlock", Func, 0}, + {"Mlockall", Func, 0}, + {"Mmap", Func, 0}, + {"Mount", Func, 0}, + {"MoveFile", Func, 0}, + {"Mprotect", Func, 0}, + {"Msghdr", Type, 0}, + {"Msghdr.Control", Field, 0}, + {"Msghdr.Controllen", Field, 0}, + {"Msghdr.Flags", Field, 0}, + {"Msghdr.Iov", Field, 0}, + {"Msghdr.Iovlen", Field, 0}, + {"Msghdr.Name", Field, 0}, + {"Msghdr.Namelen", Field, 0}, + {"Msghdr.Pad_cgo_0", Field, 0}, + {"Msghdr.Pad_cgo_1", Field, 0}, + {"Munlock", Func, 0}, + {"Munlockall", Func, 0}, + {"Munmap", Func, 0}, + {"MustLoadDLL", Func, 0}, + {"NAME_MAX", Const, 0}, + {"NETLINK_ADD_MEMBERSHIP", Const, 0}, + {"NETLINK_AUDIT", Const, 0}, + {"NETLINK_BROADCAST_ERROR", Const, 0}, + {"NETLINK_CONNECTOR", Const, 0}, + {"NETLINK_DNRTMSG", Const, 0}, + {"NETLINK_DROP_MEMBERSHIP", Const, 0}, + {"NETLINK_ECRYPTFS", Const, 0}, + {"NETLINK_FIB_LOOKUP", Const, 0}, + {"NETLINK_FIREWALL", Const, 0}, + {"NETLINK_GENERIC", Const, 0}, + {"NETLINK_INET_DIAG", Const, 0}, + {"NETLINK_IP6_FW", Const, 0}, + {"NETLINK_ISCSI", Const, 0}, + {"NETLINK_KOBJECT_UEVENT", Const, 0}, + {"NETLINK_NETFILTER", Const, 0}, + {"NETLINK_NFLOG", Const, 0}, + {"NETLINK_NO_ENOBUFS", Const, 0}, + {"NETLINK_PKTINFO", Const, 0}, + {"NETLINK_RDMA", Const, 0}, + {"NETLINK_ROUTE", Const, 0}, + {"NETLINK_SCSITRANSPORT", Const, 0}, + {"NETLINK_SELINUX", Const, 0}, + {"NETLINK_UNUSED", Const, 0}, + {"NETLINK_USERSOCK", Const, 0}, + {"NETLINK_XFRM", Const, 0}, + {"NET_RT_DUMP", Const, 0}, + {"NET_RT_DUMP2", Const, 0}, + {"NET_RT_FLAGS", Const, 0}, + {"NET_RT_IFLIST", Const, 0}, + {"NET_RT_IFLIST2", Const, 0}, + {"NET_RT_IFLISTL", Const, 1}, + {"NET_RT_IFMALIST", Const, 0}, + {"NET_RT_MAXID", Const, 0}, + {"NET_RT_OIFLIST", Const, 1}, + {"NET_RT_OOIFLIST", Const, 1}, + {"NET_RT_STAT", Const, 0}, + {"NET_RT_STATS", Const, 1}, + {"NET_RT_TABLE", Const, 1}, + {"NET_RT_TRASH", Const, 0}, + {"NLA_ALIGNTO", Const, 0}, + {"NLA_F_NESTED", Const, 0}, + {"NLA_F_NET_BYTEORDER", Const, 0}, + {"NLA_HDRLEN", Const, 0}, + {"NLMSG_ALIGNTO", Const, 0}, + {"NLMSG_DONE", Const, 0}, + {"NLMSG_ERROR", Const, 0}, + {"NLMSG_HDRLEN", Const, 0}, + {"NLMSG_MIN_TYPE", Const, 0}, + {"NLMSG_NOOP", Const, 0}, + {"NLMSG_OVERRUN", Const, 0}, + {"NLM_F_ACK", Const, 0}, + {"NLM_F_APPEND", Const, 0}, + {"NLM_F_ATOMIC", Const, 0}, + {"NLM_F_CREATE", Const, 0}, + {"NLM_F_DUMP", Const, 0}, + {"NLM_F_ECHO", Const, 0}, + {"NLM_F_EXCL", Const, 0}, + {"NLM_F_MATCH", Const, 0}, + {"NLM_F_MULTI", Const, 0}, + {"NLM_F_REPLACE", Const, 0}, + {"NLM_F_REQUEST", Const, 0}, + {"NLM_F_ROOT", Const, 0}, + {"NOFLSH", Const, 0}, + {"NOTE_ABSOLUTE", Const, 0}, + {"NOTE_ATTRIB", Const, 0}, + {"NOTE_BACKGROUND", Const, 16}, + {"NOTE_CHILD", Const, 0}, + {"NOTE_CRITICAL", Const, 16}, + {"NOTE_DELETE", Const, 0}, + {"NOTE_EOF", Const, 1}, + {"NOTE_EXEC", Const, 0}, + {"NOTE_EXIT", Const, 0}, + {"NOTE_EXITSTATUS", Const, 0}, + {"NOTE_EXIT_CSERROR", Const, 16}, + {"NOTE_EXIT_DECRYPTFAIL", Const, 16}, + {"NOTE_EXIT_DETAIL", Const, 16}, + {"NOTE_EXIT_DETAIL_MASK", Const, 16}, + {"NOTE_EXIT_MEMORY", Const, 16}, + {"NOTE_EXIT_REPARENTED", Const, 16}, + {"NOTE_EXTEND", Const, 0}, + {"NOTE_FFAND", Const, 0}, + {"NOTE_FFCOPY", Const, 0}, + {"NOTE_FFCTRLMASK", Const, 0}, + {"NOTE_FFLAGSMASK", Const, 0}, + {"NOTE_FFNOP", Const, 0}, + {"NOTE_FFOR", Const, 0}, + {"NOTE_FORK", Const, 0}, + {"NOTE_LEEWAY", Const, 16}, + {"NOTE_LINK", Const, 0}, + {"NOTE_LOWAT", Const, 0}, + {"NOTE_NONE", Const, 0}, + {"NOTE_NSECONDS", Const, 0}, + {"NOTE_PCTRLMASK", Const, 0}, + {"NOTE_PDATAMASK", Const, 0}, + {"NOTE_REAP", Const, 0}, + {"NOTE_RENAME", Const, 0}, + {"NOTE_RESOURCEEND", Const, 0}, + {"NOTE_REVOKE", Const, 0}, + {"NOTE_SECONDS", Const, 0}, + {"NOTE_SIGNAL", Const, 0}, + {"NOTE_TRACK", Const, 0}, + {"NOTE_TRACKERR", Const, 0}, + {"NOTE_TRIGGER", Const, 0}, + {"NOTE_TRUNCATE", Const, 1}, + {"NOTE_USECONDS", Const, 0}, + {"NOTE_VM_ERROR", Const, 0}, + {"NOTE_VM_PRESSURE", Const, 0}, + {"NOTE_VM_PRESSURE_SUDDEN_TERMINATE", Const, 0}, + {"NOTE_VM_PRESSURE_TERMINATE", Const, 0}, + {"NOTE_WRITE", Const, 0}, + {"NameCanonical", Const, 0}, + {"NameCanonicalEx", Const, 0}, + {"NameDisplay", Const, 0}, + {"NameDnsDomain", Const, 0}, + {"NameFullyQualifiedDN", Const, 0}, + {"NameSamCompatible", Const, 0}, + {"NameServicePrincipal", Const, 0}, + {"NameUniqueId", Const, 0}, + {"NameUnknown", Const, 0}, + {"NameUserPrincipal", Const, 0}, + {"Nanosleep", Func, 0}, + {"NetApiBufferFree", Func, 0}, + {"NetGetJoinInformation", Func, 2}, + {"NetSetupDomainName", Const, 2}, + {"NetSetupUnjoined", Const, 2}, + {"NetSetupUnknownStatus", Const, 2}, + {"NetSetupWorkgroupName", Const, 2}, + {"NetUserGetInfo", Func, 0}, + {"NetlinkMessage", Type, 0}, + {"NetlinkMessage.Data", Field, 0}, + {"NetlinkMessage.Header", Field, 0}, + {"NetlinkRIB", Func, 0}, + {"NetlinkRouteAttr", Type, 0}, + {"NetlinkRouteAttr.Attr", Field, 0}, + {"NetlinkRouteAttr.Value", Field, 0}, + {"NetlinkRouteRequest", Type, 0}, + {"NetlinkRouteRequest.Data", Field, 0}, + {"NetlinkRouteRequest.Header", Field, 0}, + {"NewCallback", Func, 0}, + {"NewCallbackCDecl", Func, 3}, + {"NewLazyDLL", Func, 0}, + {"NlAttr", Type, 0}, + {"NlAttr.Len", Field, 0}, + {"NlAttr.Type", Field, 0}, + {"NlMsgerr", Type, 0}, + {"NlMsgerr.Error", Field, 0}, + {"NlMsgerr.Msg", Field, 0}, + {"NlMsghdr", Type, 0}, + {"NlMsghdr.Flags", Field, 0}, + {"NlMsghdr.Len", Field, 0}, + {"NlMsghdr.Pid", Field, 0}, + {"NlMsghdr.Seq", Field, 0}, + {"NlMsghdr.Type", Field, 0}, + {"NsecToFiletime", Func, 0}, + {"NsecToTimespec", Func, 0}, + {"NsecToTimeval", Func, 0}, + {"Ntohs", Func, 0}, + {"OCRNL", Const, 0}, + {"OFDEL", Const, 0}, + {"OFILL", Const, 0}, + {"OFIOGETBMAP", Const, 1}, + {"OID_PKIX_KP_SERVER_AUTH", Var, 0}, + {"OID_SERVER_GATED_CRYPTO", Var, 0}, + {"OID_SGC_NETSCAPE", Var, 0}, + {"OLCUC", Const, 0}, + {"ONLCR", Const, 0}, + {"ONLRET", Const, 0}, + {"ONOCR", Const, 0}, + {"ONOEOT", Const, 1}, + {"OPEN_ALWAYS", Const, 0}, + {"OPEN_EXISTING", Const, 0}, + {"OPOST", Const, 0}, + {"O_ACCMODE", Const, 0}, + {"O_ALERT", Const, 0}, + {"O_ALT_IO", Const, 1}, + {"O_APPEND", Const, 0}, + {"O_ASYNC", Const, 0}, + {"O_CLOEXEC", Const, 0}, + {"O_CREAT", Const, 0}, + {"O_DIRECT", Const, 0}, + {"O_DIRECTORY", Const, 0}, + {"O_DP_GETRAWENCRYPTED", Const, 16}, + {"O_DSYNC", Const, 0}, + {"O_EVTONLY", Const, 0}, + {"O_EXCL", Const, 0}, + {"O_EXEC", Const, 0}, + {"O_EXLOCK", Const, 0}, + {"O_FSYNC", Const, 0}, + {"O_LARGEFILE", Const, 0}, + {"O_NDELAY", Const, 0}, + {"O_NOATIME", Const, 0}, + {"O_NOCTTY", Const, 0}, + {"O_NOFOLLOW", Const, 0}, + {"O_NONBLOCK", Const, 0}, + {"O_NOSIGPIPE", Const, 1}, + {"O_POPUP", Const, 0}, + {"O_RDONLY", Const, 0}, + {"O_RDWR", Const, 0}, + {"O_RSYNC", Const, 0}, + {"O_SHLOCK", Const, 0}, + {"O_SYMLINK", Const, 0}, + {"O_SYNC", Const, 0}, + {"O_TRUNC", Const, 0}, + {"O_TTY_INIT", Const, 0}, + {"O_WRONLY", Const, 0}, + {"Open", Func, 0}, + {"OpenCurrentProcessToken", Func, 0}, + {"OpenProcess", Func, 0}, + {"OpenProcessToken", Func, 0}, + {"Openat", Func, 0}, + {"Overlapped", Type, 0}, + {"Overlapped.HEvent", Field, 0}, + {"Overlapped.Internal", Field, 0}, + {"Overlapped.InternalHigh", Field, 0}, + {"Overlapped.Offset", Field, 0}, + {"Overlapped.OffsetHigh", Field, 0}, + {"PACKET_ADD_MEMBERSHIP", Const, 0}, + {"PACKET_BROADCAST", Const, 0}, + {"PACKET_DROP_MEMBERSHIP", Const, 0}, + {"PACKET_FASTROUTE", Const, 0}, + {"PACKET_HOST", Const, 0}, + {"PACKET_LOOPBACK", Const, 0}, + {"PACKET_MR_ALLMULTI", Const, 0}, + {"PACKET_MR_MULTICAST", Const, 0}, + {"PACKET_MR_PROMISC", Const, 0}, + {"PACKET_MULTICAST", Const, 0}, + {"PACKET_OTHERHOST", Const, 0}, + {"PACKET_OUTGOING", Const, 0}, + {"PACKET_RECV_OUTPUT", Const, 0}, + {"PACKET_RX_RING", Const, 0}, + {"PACKET_STATISTICS", Const, 0}, + {"PAGE_EXECUTE_READ", Const, 0}, + {"PAGE_EXECUTE_READWRITE", Const, 0}, + {"PAGE_EXECUTE_WRITECOPY", Const, 0}, + {"PAGE_READONLY", Const, 0}, + {"PAGE_READWRITE", Const, 0}, + {"PAGE_WRITECOPY", Const, 0}, + {"PARENB", Const, 0}, + {"PARMRK", Const, 0}, + {"PARODD", Const, 0}, + {"PENDIN", Const, 0}, + {"PFL_HIDDEN", Const, 2}, + {"PFL_MATCHES_PROTOCOL_ZERO", Const, 2}, + {"PFL_MULTIPLE_PROTO_ENTRIES", Const, 2}, + {"PFL_NETWORKDIRECT_PROVIDER", Const, 2}, + {"PFL_RECOMMENDED_PROTO_ENTRY", Const, 2}, + {"PF_FLUSH", Const, 1}, + {"PKCS_7_ASN_ENCODING", Const, 0}, + {"PMC5_PIPELINE_FLUSH", Const, 1}, + {"PRIO_PGRP", Const, 2}, + {"PRIO_PROCESS", Const, 2}, + {"PRIO_USER", Const, 2}, + {"PRI_IOFLUSH", Const, 1}, + {"PROCESS_QUERY_INFORMATION", Const, 0}, + {"PROCESS_TERMINATE", Const, 2}, + {"PROT_EXEC", Const, 0}, + {"PROT_GROWSDOWN", Const, 0}, + {"PROT_GROWSUP", Const, 0}, + {"PROT_NONE", Const, 0}, + {"PROT_READ", Const, 0}, + {"PROT_WRITE", Const, 0}, + {"PROV_DH_SCHANNEL", Const, 0}, + {"PROV_DSS", Const, 0}, + {"PROV_DSS_DH", Const, 0}, + {"PROV_EC_ECDSA_FULL", Const, 0}, + {"PROV_EC_ECDSA_SIG", Const, 0}, + {"PROV_EC_ECNRA_FULL", Const, 0}, + {"PROV_EC_ECNRA_SIG", Const, 0}, + {"PROV_FORTEZZA", Const, 0}, + {"PROV_INTEL_SEC", Const, 0}, + {"PROV_MS_EXCHANGE", Const, 0}, + {"PROV_REPLACE_OWF", Const, 0}, + {"PROV_RNG", Const, 0}, + {"PROV_RSA_AES", Const, 0}, + {"PROV_RSA_FULL", Const, 0}, + {"PROV_RSA_SCHANNEL", Const, 0}, + {"PROV_RSA_SIG", Const, 0}, + {"PROV_SPYRUS_LYNKS", Const, 0}, + {"PROV_SSL", Const, 0}, + {"PR_CAPBSET_DROP", Const, 0}, + {"PR_CAPBSET_READ", Const, 0}, + {"PR_CLEAR_SECCOMP_FILTER", Const, 0}, + {"PR_ENDIAN_BIG", Const, 0}, + {"PR_ENDIAN_LITTLE", Const, 0}, + {"PR_ENDIAN_PPC_LITTLE", Const, 0}, + {"PR_FPEMU_NOPRINT", Const, 0}, + {"PR_FPEMU_SIGFPE", Const, 0}, + {"PR_FP_EXC_ASYNC", Const, 0}, + {"PR_FP_EXC_DISABLED", Const, 0}, + {"PR_FP_EXC_DIV", Const, 0}, + {"PR_FP_EXC_INV", Const, 0}, + {"PR_FP_EXC_NONRECOV", Const, 0}, + {"PR_FP_EXC_OVF", Const, 0}, + {"PR_FP_EXC_PRECISE", Const, 0}, + {"PR_FP_EXC_RES", Const, 0}, + {"PR_FP_EXC_SW_ENABLE", Const, 0}, + {"PR_FP_EXC_UND", Const, 0}, + {"PR_GET_DUMPABLE", Const, 0}, + {"PR_GET_ENDIAN", Const, 0}, + {"PR_GET_FPEMU", Const, 0}, + {"PR_GET_FPEXC", Const, 0}, + {"PR_GET_KEEPCAPS", Const, 0}, + {"PR_GET_NAME", Const, 0}, + {"PR_GET_PDEATHSIG", Const, 0}, + {"PR_GET_SECCOMP", Const, 0}, + {"PR_GET_SECCOMP_FILTER", Const, 0}, + {"PR_GET_SECUREBITS", Const, 0}, + {"PR_GET_TIMERSLACK", Const, 0}, + {"PR_GET_TIMING", Const, 0}, + {"PR_GET_TSC", Const, 0}, + {"PR_GET_UNALIGN", Const, 0}, + {"PR_MCE_KILL", Const, 0}, + {"PR_MCE_KILL_CLEAR", Const, 0}, + {"PR_MCE_KILL_DEFAULT", Const, 0}, + {"PR_MCE_KILL_EARLY", Const, 0}, + {"PR_MCE_KILL_GET", Const, 0}, + {"PR_MCE_KILL_LATE", Const, 0}, + {"PR_MCE_KILL_SET", Const, 0}, + {"PR_SECCOMP_FILTER_EVENT", Const, 0}, + {"PR_SECCOMP_FILTER_SYSCALL", Const, 0}, + {"PR_SET_DUMPABLE", Const, 0}, + {"PR_SET_ENDIAN", Const, 0}, + {"PR_SET_FPEMU", Const, 0}, + {"PR_SET_FPEXC", Const, 0}, + {"PR_SET_KEEPCAPS", Const, 0}, + {"PR_SET_NAME", Const, 0}, + {"PR_SET_PDEATHSIG", Const, 0}, + {"PR_SET_PTRACER", Const, 0}, + {"PR_SET_SECCOMP", Const, 0}, + {"PR_SET_SECCOMP_FILTER", Const, 0}, + {"PR_SET_SECUREBITS", Const, 0}, + {"PR_SET_TIMERSLACK", Const, 0}, + {"PR_SET_TIMING", Const, 0}, + {"PR_SET_TSC", Const, 0}, + {"PR_SET_UNALIGN", Const, 0}, + {"PR_TASK_PERF_EVENTS_DISABLE", Const, 0}, + {"PR_TASK_PERF_EVENTS_ENABLE", Const, 0}, + {"PR_TIMING_STATISTICAL", Const, 0}, + {"PR_TIMING_TIMESTAMP", Const, 0}, + {"PR_TSC_ENABLE", Const, 0}, + {"PR_TSC_SIGSEGV", Const, 0}, + {"PR_UNALIGN_NOPRINT", Const, 0}, + {"PR_UNALIGN_SIGBUS", Const, 0}, + {"PTRACE_ARCH_PRCTL", Const, 0}, + {"PTRACE_ATTACH", Const, 0}, + {"PTRACE_CONT", Const, 0}, + {"PTRACE_DETACH", Const, 0}, + {"PTRACE_EVENT_CLONE", Const, 0}, + {"PTRACE_EVENT_EXEC", Const, 0}, + {"PTRACE_EVENT_EXIT", Const, 0}, + {"PTRACE_EVENT_FORK", Const, 0}, + {"PTRACE_EVENT_VFORK", Const, 0}, + {"PTRACE_EVENT_VFORK_DONE", Const, 0}, + {"PTRACE_GETCRUNCHREGS", Const, 0}, + {"PTRACE_GETEVENTMSG", Const, 0}, + {"PTRACE_GETFPREGS", Const, 0}, + {"PTRACE_GETFPXREGS", Const, 0}, + {"PTRACE_GETHBPREGS", Const, 0}, + {"PTRACE_GETREGS", Const, 0}, + {"PTRACE_GETREGSET", Const, 0}, + {"PTRACE_GETSIGINFO", Const, 0}, + {"PTRACE_GETVFPREGS", Const, 0}, + {"PTRACE_GETWMMXREGS", Const, 0}, + {"PTRACE_GET_THREAD_AREA", Const, 0}, + {"PTRACE_KILL", Const, 0}, + {"PTRACE_OLDSETOPTIONS", Const, 0}, + {"PTRACE_O_MASK", Const, 0}, + {"PTRACE_O_TRACECLONE", Const, 0}, + {"PTRACE_O_TRACEEXEC", Const, 0}, + {"PTRACE_O_TRACEEXIT", Const, 0}, + {"PTRACE_O_TRACEFORK", Const, 0}, + {"PTRACE_O_TRACESYSGOOD", Const, 0}, + {"PTRACE_O_TRACEVFORK", Const, 0}, + {"PTRACE_O_TRACEVFORKDONE", Const, 0}, + {"PTRACE_PEEKDATA", Const, 0}, + {"PTRACE_PEEKTEXT", Const, 0}, + {"PTRACE_PEEKUSR", Const, 0}, + {"PTRACE_POKEDATA", Const, 0}, + {"PTRACE_POKETEXT", Const, 0}, + {"PTRACE_POKEUSR", Const, 0}, + {"PTRACE_SETCRUNCHREGS", Const, 0}, + {"PTRACE_SETFPREGS", Const, 0}, + {"PTRACE_SETFPXREGS", Const, 0}, + {"PTRACE_SETHBPREGS", Const, 0}, + {"PTRACE_SETOPTIONS", Const, 0}, + {"PTRACE_SETREGS", Const, 0}, + {"PTRACE_SETREGSET", Const, 0}, + {"PTRACE_SETSIGINFO", Const, 0}, + {"PTRACE_SETVFPREGS", Const, 0}, + {"PTRACE_SETWMMXREGS", Const, 0}, + {"PTRACE_SET_SYSCALL", Const, 0}, + {"PTRACE_SET_THREAD_AREA", Const, 0}, + {"PTRACE_SINGLEBLOCK", Const, 0}, + {"PTRACE_SINGLESTEP", Const, 0}, + {"PTRACE_SYSCALL", Const, 0}, + {"PTRACE_SYSEMU", Const, 0}, + {"PTRACE_SYSEMU_SINGLESTEP", Const, 0}, + {"PTRACE_TRACEME", Const, 0}, + {"PT_ATTACH", Const, 0}, + {"PT_ATTACHEXC", Const, 0}, + {"PT_CONTINUE", Const, 0}, + {"PT_DATA_ADDR", Const, 0}, + {"PT_DENY_ATTACH", Const, 0}, + {"PT_DETACH", Const, 0}, + {"PT_FIRSTMACH", Const, 0}, + {"PT_FORCEQUOTA", Const, 0}, + {"PT_KILL", Const, 0}, + {"PT_MASK", Const, 1}, + {"PT_READ_D", Const, 0}, + {"PT_READ_I", Const, 0}, + {"PT_READ_U", Const, 0}, + {"PT_SIGEXC", Const, 0}, + {"PT_STEP", Const, 0}, + {"PT_TEXT_ADDR", Const, 0}, + {"PT_TEXT_END_ADDR", Const, 0}, + {"PT_THUPDATE", Const, 0}, + {"PT_TRACE_ME", Const, 0}, + {"PT_WRITE_D", Const, 0}, + {"PT_WRITE_I", Const, 0}, + {"PT_WRITE_U", Const, 0}, + {"ParseDirent", Func, 0}, + {"ParseNetlinkMessage", Func, 0}, + {"ParseNetlinkRouteAttr", Func, 0}, + {"ParseRoutingMessage", Func, 0}, + {"ParseRoutingSockaddr", Func, 0}, + {"ParseSocketControlMessage", Func, 0}, + {"ParseUnixCredentials", Func, 0}, + {"ParseUnixRights", Func, 0}, + {"PathMax", Const, 0}, + {"Pathconf", Func, 0}, + {"Pause", Func, 0}, + {"Pipe", Func, 0}, + {"Pipe2", Func, 1}, + {"PivotRoot", Func, 0}, + {"Pointer", Type, 11}, + {"PostQueuedCompletionStatus", Func, 0}, + {"Pread", Func, 0}, + {"Proc", Type, 0}, + {"Proc.Dll", Field, 0}, + {"Proc.Name", Field, 0}, + {"ProcAttr", Type, 0}, + {"ProcAttr.Dir", Field, 0}, + {"ProcAttr.Env", Field, 0}, + {"ProcAttr.Files", Field, 0}, + {"ProcAttr.Sys", Field, 0}, + {"Process32First", Func, 4}, + {"Process32Next", Func, 4}, + {"ProcessEntry32", Type, 4}, + {"ProcessEntry32.DefaultHeapID", Field, 4}, + {"ProcessEntry32.ExeFile", Field, 4}, + {"ProcessEntry32.Flags", Field, 4}, + {"ProcessEntry32.ModuleID", Field, 4}, + {"ProcessEntry32.ParentProcessID", Field, 4}, + {"ProcessEntry32.PriClassBase", Field, 4}, + {"ProcessEntry32.ProcessID", Field, 4}, + {"ProcessEntry32.Size", Field, 4}, + {"ProcessEntry32.Threads", Field, 4}, + {"ProcessEntry32.Usage", Field, 4}, + {"ProcessInformation", Type, 0}, + {"ProcessInformation.Process", Field, 0}, + {"ProcessInformation.ProcessId", Field, 0}, + {"ProcessInformation.Thread", Field, 0}, + {"ProcessInformation.ThreadId", Field, 0}, + {"Protoent", Type, 0}, + {"Protoent.Aliases", Field, 0}, + {"Protoent.Name", Field, 0}, + {"Protoent.Proto", Field, 0}, + {"PtraceAttach", Func, 0}, + {"PtraceCont", Func, 0}, + {"PtraceDetach", Func, 0}, + {"PtraceGetEventMsg", Func, 0}, + {"PtraceGetRegs", Func, 0}, + {"PtracePeekData", Func, 0}, + {"PtracePeekText", Func, 0}, + {"PtracePokeData", Func, 0}, + {"PtracePokeText", Func, 0}, + {"PtraceRegs", Type, 0}, + {"PtraceRegs.Cs", Field, 0}, + {"PtraceRegs.Ds", Field, 0}, + {"PtraceRegs.Eax", Field, 0}, + {"PtraceRegs.Ebp", Field, 0}, + {"PtraceRegs.Ebx", Field, 0}, + {"PtraceRegs.Ecx", Field, 0}, + {"PtraceRegs.Edi", Field, 0}, + {"PtraceRegs.Edx", Field, 0}, + {"PtraceRegs.Eflags", Field, 0}, + {"PtraceRegs.Eip", Field, 0}, + {"PtraceRegs.Es", Field, 0}, + {"PtraceRegs.Esi", Field, 0}, + {"PtraceRegs.Esp", Field, 0}, + {"PtraceRegs.Fs", Field, 0}, + {"PtraceRegs.Fs_base", Field, 0}, + {"PtraceRegs.Gs", Field, 0}, + {"PtraceRegs.Gs_base", Field, 0}, + {"PtraceRegs.Orig_eax", Field, 0}, + {"PtraceRegs.Orig_rax", Field, 0}, + {"PtraceRegs.R10", Field, 0}, + {"PtraceRegs.R11", Field, 0}, + {"PtraceRegs.R12", Field, 0}, + {"PtraceRegs.R13", Field, 0}, + {"PtraceRegs.R14", Field, 0}, + {"PtraceRegs.R15", Field, 0}, + {"PtraceRegs.R8", Field, 0}, + {"PtraceRegs.R9", Field, 0}, + {"PtraceRegs.Rax", Field, 0}, + {"PtraceRegs.Rbp", Field, 0}, + {"PtraceRegs.Rbx", Field, 0}, + {"PtraceRegs.Rcx", Field, 0}, + {"PtraceRegs.Rdi", Field, 0}, + {"PtraceRegs.Rdx", Field, 0}, + {"PtraceRegs.Rip", Field, 0}, + {"PtraceRegs.Rsi", Field, 0}, + {"PtraceRegs.Rsp", Field, 0}, + {"PtraceRegs.Ss", Field, 0}, + {"PtraceRegs.Uregs", Field, 0}, + {"PtraceRegs.Xcs", Field, 0}, + {"PtraceRegs.Xds", Field, 0}, + {"PtraceRegs.Xes", Field, 0}, + {"PtraceRegs.Xfs", Field, 0}, + {"PtraceRegs.Xgs", Field, 0}, + {"PtraceRegs.Xss", Field, 0}, + {"PtraceSetOptions", Func, 0}, + {"PtraceSetRegs", Func, 0}, + {"PtraceSingleStep", Func, 0}, + {"PtraceSyscall", Func, 1}, + {"Pwrite", Func, 0}, + {"REG_BINARY", Const, 0}, + {"REG_DWORD", Const, 0}, + {"REG_DWORD_BIG_ENDIAN", Const, 0}, + {"REG_DWORD_LITTLE_ENDIAN", Const, 0}, + {"REG_EXPAND_SZ", Const, 0}, + {"REG_FULL_RESOURCE_DESCRIPTOR", Const, 0}, + {"REG_LINK", Const, 0}, + {"REG_MULTI_SZ", Const, 0}, + {"REG_NONE", Const, 0}, + {"REG_QWORD", Const, 0}, + {"REG_QWORD_LITTLE_ENDIAN", Const, 0}, + {"REG_RESOURCE_LIST", Const, 0}, + {"REG_RESOURCE_REQUIREMENTS_LIST", Const, 0}, + {"REG_SZ", Const, 0}, + {"RLIMIT_AS", Const, 0}, + {"RLIMIT_CORE", Const, 0}, + {"RLIMIT_CPU", Const, 0}, + {"RLIMIT_CPU_USAGE_MONITOR", Const, 16}, + {"RLIMIT_DATA", Const, 0}, + {"RLIMIT_FSIZE", Const, 0}, + {"RLIMIT_NOFILE", Const, 0}, + {"RLIMIT_STACK", Const, 0}, + {"RLIM_INFINITY", Const, 0}, + {"RTAX_ADVMSS", Const, 0}, + {"RTAX_AUTHOR", Const, 0}, + {"RTAX_BRD", Const, 0}, + {"RTAX_CWND", Const, 0}, + {"RTAX_DST", Const, 0}, + {"RTAX_FEATURES", Const, 0}, + {"RTAX_FEATURE_ALLFRAG", Const, 0}, + {"RTAX_FEATURE_ECN", Const, 0}, + {"RTAX_FEATURE_SACK", Const, 0}, + {"RTAX_FEATURE_TIMESTAMP", Const, 0}, + {"RTAX_GATEWAY", Const, 0}, + {"RTAX_GENMASK", Const, 0}, + {"RTAX_HOPLIMIT", Const, 0}, + {"RTAX_IFA", Const, 0}, + {"RTAX_IFP", Const, 0}, + {"RTAX_INITCWND", Const, 0}, + {"RTAX_INITRWND", Const, 0}, + {"RTAX_LABEL", Const, 1}, + {"RTAX_LOCK", Const, 0}, + {"RTAX_MAX", Const, 0}, + {"RTAX_MTU", Const, 0}, + {"RTAX_NETMASK", Const, 0}, + {"RTAX_REORDERING", Const, 0}, + {"RTAX_RTO_MIN", Const, 0}, + {"RTAX_RTT", Const, 0}, + {"RTAX_RTTVAR", Const, 0}, + {"RTAX_SRC", Const, 1}, + {"RTAX_SRCMASK", Const, 1}, + {"RTAX_SSTHRESH", Const, 0}, + {"RTAX_TAG", Const, 1}, + {"RTAX_UNSPEC", Const, 0}, + {"RTAX_WINDOW", Const, 0}, + {"RTA_ALIGNTO", Const, 0}, + {"RTA_AUTHOR", Const, 0}, + {"RTA_BRD", Const, 0}, + {"RTA_CACHEINFO", Const, 0}, + {"RTA_DST", Const, 0}, + {"RTA_FLOW", Const, 0}, + {"RTA_GATEWAY", Const, 0}, + {"RTA_GENMASK", Const, 0}, + {"RTA_IFA", Const, 0}, + {"RTA_IFP", Const, 0}, + {"RTA_IIF", Const, 0}, + {"RTA_LABEL", Const, 1}, + {"RTA_MAX", Const, 0}, + {"RTA_METRICS", Const, 0}, + {"RTA_MULTIPATH", Const, 0}, + {"RTA_NETMASK", Const, 0}, + {"RTA_OIF", Const, 0}, + {"RTA_PREFSRC", Const, 0}, + {"RTA_PRIORITY", Const, 0}, + {"RTA_SRC", Const, 0}, + {"RTA_SRCMASK", Const, 1}, + {"RTA_TABLE", Const, 0}, + {"RTA_TAG", Const, 1}, + {"RTA_UNSPEC", Const, 0}, + {"RTCF_DIRECTSRC", Const, 0}, + {"RTCF_DOREDIRECT", Const, 0}, + {"RTCF_LOG", Const, 0}, + {"RTCF_MASQ", Const, 0}, + {"RTCF_NAT", Const, 0}, + {"RTCF_VALVE", Const, 0}, + {"RTF_ADDRCLASSMASK", Const, 0}, + {"RTF_ADDRCONF", Const, 0}, + {"RTF_ALLONLINK", Const, 0}, + {"RTF_ANNOUNCE", Const, 1}, + {"RTF_BLACKHOLE", Const, 0}, + {"RTF_BROADCAST", Const, 0}, + {"RTF_CACHE", Const, 0}, + {"RTF_CLONED", Const, 1}, + {"RTF_CLONING", Const, 0}, + {"RTF_CONDEMNED", Const, 0}, + {"RTF_DEFAULT", Const, 0}, + {"RTF_DELCLONE", Const, 0}, + {"RTF_DONE", Const, 0}, + {"RTF_DYNAMIC", Const, 0}, + {"RTF_FLOW", Const, 0}, + {"RTF_FMASK", Const, 0}, + {"RTF_GATEWAY", Const, 0}, + {"RTF_GWFLAG_COMPAT", Const, 3}, + {"RTF_HOST", Const, 0}, + {"RTF_IFREF", Const, 0}, + {"RTF_IFSCOPE", Const, 0}, + {"RTF_INTERFACE", Const, 0}, + {"RTF_IRTT", Const, 0}, + {"RTF_LINKRT", Const, 0}, + {"RTF_LLDATA", Const, 0}, + {"RTF_LLINFO", Const, 0}, + {"RTF_LOCAL", Const, 0}, + {"RTF_MASK", Const, 1}, + {"RTF_MODIFIED", Const, 0}, + {"RTF_MPATH", Const, 1}, + {"RTF_MPLS", Const, 1}, + {"RTF_MSS", Const, 0}, + {"RTF_MTU", Const, 0}, + {"RTF_MULTICAST", Const, 0}, + {"RTF_NAT", Const, 0}, + {"RTF_NOFORWARD", Const, 0}, + {"RTF_NONEXTHOP", Const, 0}, + {"RTF_NOPMTUDISC", Const, 0}, + {"RTF_PERMANENT_ARP", Const, 1}, + {"RTF_PINNED", Const, 0}, + {"RTF_POLICY", Const, 0}, + {"RTF_PRCLONING", Const, 0}, + {"RTF_PROTO1", Const, 0}, + {"RTF_PROTO2", Const, 0}, + {"RTF_PROTO3", Const, 0}, + {"RTF_PROXY", Const, 16}, + {"RTF_REINSTATE", Const, 0}, + {"RTF_REJECT", Const, 0}, + {"RTF_RNH_LOCKED", Const, 0}, + {"RTF_ROUTER", Const, 16}, + {"RTF_SOURCE", Const, 1}, + {"RTF_SRC", Const, 1}, + {"RTF_STATIC", Const, 0}, + {"RTF_STICKY", Const, 0}, + {"RTF_THROW", Const, 0}, + {"RTF_TUNNEL", Const, 1}, + {"RTF_UP", Const, 0}, + {"RTF_USETRAILERS", Const, 1}, + {"RTF_WASCLONED", Const, 0}, + {"RTF_WINDOW", Const, 0}, + {"RTF_XRESOLVE", Const, 0}, + {"RTM_ADD", Const, 0}, + {"RTM_BASE", Const, 0}, + {"RTM_CHANGE", Const, 0}, + {"RTM_CHGADDR", Const, 1}, + {"RTM_DELACTION", Const, 0}, + {"RTM_DELADDR", Const, 0}, + {"RTM_DELADDRLABEL", Const, 0}, + {"RTM_DELETE", Const, 0}, + {"RTM_DELLINK", Const, 0}, + {"RTM_DELMADDR", Const, 0}, + {"RTM_DELNEIGH", Const, 0}, + {"RTM_DELQDISC", Const, 0}, + {"RTM_DELROUTE", Const, 0}, + {"RTM_DELRULE", Const, 0}, + {"RTM_DELTCLASS", Const, 0}, + {"RTM_DELTFILTER", Const, 0}, + {"RTM_DESYNC", Const, 1}, + {"RTM_F_CLONED", Const, 0}, + {"RTM_F_EQUALIZE", Const, 0}, + {"RTM_F_NOTIFY", Const, 0}, + {"RTM_F_PREFIX", Const, 0}, + {"RTM_GET", Const, 0}, + {"RTM_GET2", Const, 0}, + {"RTM_GETACTION", Const, 0}, + {"RTM_GETADDR", Const, 0}, + {"RTM_GETADDRLABEL", Const, 0}, + {"RTM_GETANYCAST", Const, 0}, + {"RTM_GETDCB", Const, 0}, + {"RTM_GETLINK", Const, 0}, + {"RTM_GETMULTICAST", Const, 0}, + {"RTM_GETNEIGH", Const, 0}, + {"RTM_GETNEIGHTBL", Const, 0}, + {"RTM_GETQDISC", Const, 0}, + {"RTM_GETROUTE", Const, 0}, + {"RTM_GETRULE", Const, 0}, + {"RTM_GETTCLASS", Const, 0}, + {"RTM_GETTFILTER", Const, 0}, + {"RTM_IEEE80211", Const, 0}, + {"RTM_IFANNOUNCE", Const, 0}, + {"RTM_IFINFO", Const, 0}, + {"RTM_IFINFO2", Const, 0}, + {"RTM_LLINFO_UPD", Const, 1}, + {"RTM_LOCK", Const, 0}, + {"RTM_LOSING", Const, 0}, + {"RTM_MAX", Const, 0}, + {"RTM_MAXSIZE", Const, 1}, + {"RTM_MISS", Const, 0}, + {"RTM_NEWACTION", Const, 0}, + {"RTM_NEWADDR", Const, 0}, + {"RTM_NEWADDRLABEL", Const, 0}, + {"RTM_NEWLINK", Const, 0}, + {"RTM_NEWMADDR", Const, 0}, + {"RTM_NEWMADDR2", Const, 0}, + {"RTM_NEWNDUSEROPT", Const, 0}, + {"RTM_NEWNEIGH", Const, 0}, + {"RTM_NEWNEIGHTBL", Const, 0}, + {"RTM_NEWPREFIX", Const, 0}, + {"RTM_NEWQDISC", Const, 0}, + {"RTM_NEWROUTE", Const, 0}, + {"RTM_NEWRULE", Const, 0}, + {"RTM_NEWTCLASS", Const, 0}, + {"RTM_NEWTFILTER", Const, 0}, + {"RTM_NR_FAMILIES", Const, 0}, + {"RTM_NR_MSGTYPES", Const, 0}, + {"RTM_OIFINFO", Const, 1}, + {"RTM_OLDADD", Const, 0}, + {"RTM_OLDDEL", Const, 0}, + {"RTM_OOIFINFO", Const, 1}, + {"RTM_REDIRECT", Const, 0}, + {"RTM_RESOLVE", Const, 0}, + {"RTM_RTTUNIT", Const, 0}, + {"RTM_SETDCB", Const, 0}, + {"RTM_SETGATE", Const, 1}, + {"RTM_SETLINK", Const, 0}, + {"RTM_SETNEIGHTBL", Const, 0}, + {"RTM_VERSION", Const, 0}, + {"RTNH_ALIGNTO", Const, 0}, + {"RTNH_F_DEAD", Const, 0}, + {"RTNH_F_ONLINK", Const, 0}, + {"RTNH_F_PERVASIVE", Const, 0}, + {"RTNLGRP_IPV4_IFADDR", Const, 1}, + {"RTNLGRP_IPV4_MROUTE", Const, 1}, + {"RTNLGRP_IPV4_ROUTE", Const, 1}, + {"RTNLGRP_IPV4_RULE", Const, 1}, + {"RTNLGRP_IPV6_IFADDR", Const, 1}, + {"RTNLGRP_IPV6_IFINFO", Const, 1}, + {"RTNLGRP_IPV6_MROUTE", Const, 1}, + {"RTNLGRP_IPV6_PREFIX", Const, 1}, + {"RTNLGRP_IPV6_ROUTE", Const, 1}, + {"RTNLGRP_IPV6_RULE", Const, 1}, + {"RTNLGRP_LINK", Const, 1}, + {"RTNLGRP_ND_USEROPT", Const, 1}, + {"RTNLGRP_NEIGH", Const, 1}, + {"RTNLGRP_NONE", Const, 1}, + {"RTNLGRP_NOTIFY", Const, 1}, + {"RTNLGRP_TC", Const, 1}, + {"RTN_ANYCAST", Const, 0}, + {"RTN_BLACKHOLE", Const, 0}, + {"RTN_BROADCAST", Const, 0}, + {"RTN_LOCAL", Const, 0}, + {"RTN_MAX", Const, 0}, + {"RTN_MULTICAST", Const, 0}, + {"RTN_NAT", Const, 0}, + {"RTN_PROHIBIT", Const, 0}, + {"RTN_THROW", Const, 0}, + {"RTN_UNICAST", Const, 0}, + {"RTN_UNREACHABLE", Const, 0}, + {"RTN_UNSPEC", Const, 0}, + {"RTN_XRESOLVE", Const, 0}, + {"RTPROT_BIRD", Const, 0}, + {"RTPROT_BOOT", Const, 0}, + {"RTPROT_DHCP", Const, 0}, + {"RTPROT_DNROUTED", Const, 0}, + {"RTPROT_GATED", Const, 0}, + {"RTPROT_KERNEL", Const, 0}, + {"RTPROT_MRT", Const, 0}, + {"RTPROT_NTK", Const, 0}, + {"RTPROT_RA", Const, 0}, + {"RTPROT_REDIRECT", Const, 0}, + {"RTPROT_STATIC", Const, 0}, + {"RTPROT_UNSPEC", Const, 0}, + {"RTPROT_XORP", Const, 0}, + {"RTPROT_ZEBRA", Const, 0}, + {"RTV_EXPIRE", Const, 0}, + {"RTV_HOPCOUNT", Const, 0}, + {"RTV_MTU", Const, 0}, + {"RTV_RPIPE", Const, 0}, + {"RTV_RTT", Const, 0}, + {"RTV_RTTVAR", Const, 0}, + {"RTV_SPIPE", Const, 0}, + {"RTV_SSTHRESH", Const, 0}, + {"RTV_WEIGHT", Const, 0}, + {"RT_CACHING_CONTEXT", Const, 1}, + {"RT_CLASS_DEFAULT", Const, 0}, + {"RT_CLASS_LOCAL", Const, 0}, + {"RT_CLASS_MAIN", Const, 0}, + {"RT_CLASS_MAX", Const, 0}, + {"RT_CLASS_UNSPEC", Const, 0}, + {"RT_DEFAULT_FIB", Const, 1}, + {"RT_NORTREF", Const, 1}, + {"RT_SCOPE_HOST", Const, 0}, + {"RT_SCOPE_LINK", Const, 0}, + {"RT_SCOPE_NOWHERE", Const, 0}, + {"RT_SCOPE_SITE", Const, 0}, + {"RT_SCOPE_UNIVERSE", Const, 0}, + {"RT_TABLEID_MAX", Const, 1}, + {"RT_TABLE_COMPAT", Const, 0}, + {"RT_TABLE_DEFAULT", Const, 0}, + {"RT_TABLE_LOCAL", Const, 0}, + {"RT_TABLE_MAIN", Const, 0}, + {"RT_TABLE_MAX", Const, 0}, + {"RT_TABLE_UNSPEC", Const, 0}, + {"RUSAGE_CHILDREN", Const, 0}, + {"RUSAGE_SELF", Const, 0}, + {"RUSAGE_THREAD", Const, 0}, + {"Radvisory_t", Type, 0}, + {"Radvisory_t.Count", Field, 0}, + {"Radvisory_t.Offset", Field, 0}, + {"Radvisory_t.Pad_cgo_0", Field, 0}, + {"RawConn", Type, 9}, + {"RawSockaddr", Type, 0}, + {"RawSockaddr.Data", Field, 0}, + {"RawSockaddr.Family", Field, 0}, + {"RawSockaddr.Len", Field, 0}, + {"RawSockaddrAny", Type, 0}, + {"RawSockaddrAny.Addr", Field, 0}, + {"RawSockaddrAny.Pad", Field, 0}, + {"RawSockaddrDatalink", Type, 0}, + {"RawSockaddrDatalink.Alen", Field, 0}, + {"RawSockaddrDatalink.Data", Field, 0}, + {"RawSockaddrDatalink.Family", Field, 0}, + {"RawSockaddrDatalink.Index", Field, 0}, + {"RawSockaddrDatalink.Len", Field, 0}, + {"RawSockaddrDatalink.Nlen", Field, 0}, + {"RawSockaddrDatalink.Pad_cgo_0", Field, 2}, + {"RawSockaddrDatalink.Slen", Field, 0}, + {"RawSockaddrDatalink.Type", Field, 0}, + {"RawSockaddrInet4", Type, 0}, + {"RawSockaddrInet4.Addr", Field, 0}, + {"RawSockaddrInet4.Family", Field, 0}, + {"RawSockaddrInet4.Len", Field, 0}, + {"RawSockaddrInet4.Port", Field, 0}, + {"RawSockaddrInet4.Zero", Field, 0}, + {"RawSockaddrInet6", Type, 0}, + {"RawSockaddrInet6.Addr", Field, 0}, + {"RawSockaddrInet6.Family", Field, 0}, + {"RawSockaddrInet6.Flowinfo", Field, 0}, + {"RawSockaddrInet6.Len", Field, 0}, + {"RawSockaddrInet6.Port", Field, 0}, + {"RawSockaddrInet6.Scope_id", Field, 0}, + {"RawSockaddrLinklayer", Type, 0}, + {"RawSockaddrLinklayer.Addr", Field, 0}, + {"RawSockaddrLinklayer.Family", Field, 0}, + {"RawSockaddrLinklayer.Halen", Field, 0}, + {"RawSockaddrLinklayer.Hatype", Field, 0}, + {"RawSockaddrLinklayer.Ifindex", Field, 0}, + {"RawSockaddrLinklayer.Pkttype", Field, 0}, + {"RawSockaddrLinklayer.Protocol", Field, 0}, + {"RawSockaddrNetlink", Type, 0}, + {"RawSockaddrNetlink.Family", Field, 0}, + {"RawSockaddrNetlink.Groups", Field, 0}, + {"RawSockaddrNetlink.Pad", Field, 0}, + {"RawSockaddrNetlink.Pid", Field, 0}, + {"RawSockaddrUnix", Type, 0}, + {"RawSockaddrUnix.Family", Field, 0}, + {"RawSockaddrUnix.Len", Field, 0}, + {"RawSockaddrUnix.Pad_cgo_0", Field, 2}, + {"RawSockaddrUnix.Path", Field, 0}, + {"RawSyscall", Func, 0}, + {"RawSyscall6", Func, 0}, + {"Read", Func, 0}, + {"ReadConsole", Func, 1}, + {"ReadDirectoryChanges", Func, 0}, + {"ReadDirent", Func, 0}, + {"ReadFile", Func, 0}, + {"Readlink", Func, 0}, + {"Reboot", Func, 0}, + {"Recvfrom", Func, 0}, + {"Recvmsg", Func, 0}, + {"RegCloseKey", Func, 0}, + {"RegEnumKeyEx", Func, 0}, + {"RegOpenKeyEx", Func, 0}, + {"RegQueryInfoKey", Func, 0}, + {"RegQueryValueEx", Func, 0}, + {"RemoveDirectory", Func, 0}, + {"Removexattr", Func, 1}, + {"Rename", Func, 0}, + {"Renameat", Func, 0}, + {"Revoke", Func, 0}, + {"Rlimit", Type, 0}, + {"Rlimit.Cur", Field, 0}, + {"Rlimit.Max", Field, 0}, + {"Rmdir", Func, 0}, + {"RouteMessage", Type, 0}, + {"RouteMessage.Data", Field, 0}, + {"RouteMessage.Header", Field, 0}, + {"RouteRIB", Func, 0}, + {"RoutingMessage", Type, 0}, + {"RtAttr", Type, 0}, + {"RtAttr.Len", Field, 0}, + {"RtAttr.Type", Field, 0}, + {"RtGenmsg", Type, 0}, + {"RtGenmsg.Family", Field, 0}, + {"RtMetrics", Type, 0}, + {"RtMetrics.Expire", Field, 0}, + {"RtMetrics.Filler", Field, 0}, + {"RtMetrics.Hopcount", Field, 0}, + {"RtMetrics.Locks", Field, 0}, + {"RtMetrics.Mtu", Field, 0}, + {"RtMetrics.Pad", Field, 3}, + {"RtMetrics.Pksent", Field, 0}, + {"RtMetrics.Recvpipe", Field, 0}, + {"RtMetrics.Refcnt", Field, 2}, + {"RtMetrics.Rtt", Field, 0}, + {"RtMetrics.Rttvar", Field, 0}, + {"RtMetrics.Sendpipe", Field, 0}, + {"RtMetrics.Ssthresh", Field, 0}, + {"RtMetrics.Weight", Field, 0}, + {"RtMsg", Type, 0}, + {"RtMsg.Dst_len", Field, 0}, + {"RtMsg.Family", Field, 0}, + {"RtMsg.Flags", Field, 0}, + {"RtMsg.Protocol", Field, 0}, + {"RtMsg.Scope", Field, 0}, + {"RtMsg.Src_len", Field, 0}, + {"RtMsg.Table", Field, 0}, + {"RtMsg.Tos", Field, 0}, + {"RtMsg.Type", Field, 0}, + {"RtMsghdr", Type, 0}, + {"RtMsghdr.Addrs", Field, 0}, + {"RtMsghdr.Errno", Field, 0}, + {"RtMsghdr.Flags", Field, 0}, + {"RtMsghdr.Fmask", Field, 0}, + {"RtMsghdr.Hdrlen", Field, 2}, + {"RtMsghdr.Index", Field, 0}, + {"RtMsghdr.Inits", Field, 0}, + {"RtMsghdr.Mpls", Field, 2}, + {"RtMsghdr.Msglen", Field, 0}, + {"RtMsghdr.Pad_cgo_0", Field, 0}, + {"RtMsghdr.Pad_cgo_1", Field, 2}, + {"RtMsghdr.Pid", Field, 0}, + {"RtMsghdr.Priority", Field, 2}, + {"RtMsghdr.Rmx", Field, 0}, + {"RtMsghdr.Seq", Field, 0}, + {"RtMsghdr.Tableid", Field, 2}, + {"RtMsghdr.Type", Field, 0}, + {"RtMsghdr.Use", Field, 0}, + {"RtMsghdr.Version", Field, 0}, + {"RtNexthop", Type, 0}, + {"RtNexthop.Flags", Field, 0}, + {"RtNexthop.Hops", Field, 0}, + {"RtNexthop.Ifindex", Field, 0}, + {"RtNexthop.Len", Field, 0}, + {"Rusage", Type, 0}, + {"Rusage.CreationTime", Field, 0}, + {"Rusage.ExitTime", Field, 0}, + {"Rusage.Idrss", Field, 0}, + {"Rusage.Inblock", Field, 0}, + {"Rusage.Isrss", Field, 0}, + {"Rusage.Ixrss", Field, 0}, + {"Rusage.KernelTime", Field, 0}, + {"Rusage.Majflt", Field, 0}, + {"Rusage.Maxrss", Field, 0}, + {"Rusage.Minflt", Field, 0}, + {"Rusage.Msgrcv", Field, 0}, + {"Rusage.Msgsnd", Field, 0}, + {"Rusage.Nivcsw", Field, 0}, + {"Rusage.Nsignals", Field, 0}, + {"Rusage.Nswap", Field, 0}, + {"Rusage.Nvcsw", Field, 0}, + {"Rusage.Oublock", Field, 0}, + {"Rusage.Stime", Field, 0}, + {"Rusage.UserTime", Field, 0}, + {"Rusage.Utime", Field, 0}, + {"SCM_BINTIME", Const, 0}, + {"SCM_CREDENTIALS", Const, 0}, + {"SCM_CREDS", Const, 0}, + {"SCM_RIGHTS", Const, 0}, + {"SCM_TIMESTAMP", Const, 0}, + {"SCM_TIMESTAMPING", Const, 0}, + {"SCM_TIMESTAMPNS", Const, 0}, + {"SCM_TIMESTAMP_MONOTONIC", Const, 0}, + {"SHUT_RD", Const, 0}, + {"SHUT_RDWR", Const, 0}, + {"SHUT_WR", Const, 0}, + {"SID", Type, 0}, + {"SIDAndAttributes", Type, 0}, + {"SIDAndAttributes.Attributes", Field, 0}, + {"SIDAndAttributes.Sid", Field, 0}, + {"SIGABRT", Const, 0}, + {"SIGALRM", Const, 0}, + {"SIGBUS", Const, 0}, + {"SIGCHLD", Const, 0}, + {"SIGCLD", Const, 0}, + {"SIGCONT", Const, 0}, + {"SIGEMT", Const, 0}, + {"SIGFPE", Const, 0}, + {"SIGHUP", Const, 0}, + {"SIGILL", Const, 0}, + {"SIGINFO", Const, 0}, + {"SIGINT", Const, 0}, + {"SIGIO", Const, 0}, + {"SIGIOT", Const, 0}, + {"SIGKILL", Const, 0}, + {"SIGLIBRT", Const, 1}, + {"SIGLWP", Const, 0}, + {"SIGPIPE", Const, 0}, + {"SIGPOLL", Const, 0}, + {"SIGPROF", Const, 0}, + {"SIGPWR", Const, 0}, + {"SIGQUIT", Const, 0}, + {"SIGSEGV", Const, 0}, + {"SIGSTKFLT", Const, 0}, + {"SIGSTOP", Const, 0}, + {"SIGSYS", Const, 0}, + {"SIGTERM", Const, 0}, + {"SIGTHR", Const, 0}, + {"SIGTRAP", Const, 0}, + {"SIGTSTP", Const, 0}, + {"SIGTTIN", Const, 0}, + {"SIGTTOU", Const, 0}, + {"SIGUNUSED", Const, 0}, + {"SIGURG", Const, 0}, + {"SIGUSR1", Const, 0}, + {"SIGUSR2", Const, 0}, + {"SIGVTALRM", Const, 0}, + {"SIGWINCH", Const, 0}, + {"SIGXCPU", Const, 0}, + {"SIGXFSZ", Const, 0}, + {"SIOCADDDLCI", Const, 0}, + {"SIOCADDMULTI", Const, 0}, + {"SIOCADDRT", Const, 0}, + {"SIOCAIFADDR", Const, 0}, + {"SIOCAIFGROUP", Const, 0}, + {"SIOCALIFADDR", Const, 0}, + {"SIOCARPIPLL", Const, 0}, + {"SIOCATMARK", Const, 0}, + {"SIOCAUTOADDR", Const, 0}, + {"SIOCAUTONETMASK", Const, 0}, + {"SIOCBRDGADD", Const, 1}, + {"SIOCBRDGADDS", Const, 1}, + {"SIOCBRDGARL", Const, 1}, + {"SIOCBRDGDADDR", Const, 1}, + {"SIOCBRDGDEL", Const, 1}, + {"SIOCBRDGDELS", Const, 1}, + {"SIOCBRDGFLUSH", Const, 1}, + {"SIOCBRDGFRL", Const, 1}, + {"SIOCBRDGGCACHE", Const, 1}, + {"SIOCBRDGGFD", Const, 1}, + {"SIOCBRDGGHT", Const, 1}, + {"SIOCBRDGGIFFLGS", Const, 1}, + {"SIOCBRDGGMA", Const, 1}, + {"SIOCBRDGGPARAM", Const, 1}, + {"SIOCBRDGGPRI", Const, 1}, + {"SIOCBRDGGRL", Const, 1}, + {"SIOCBRDGGSIFS", Const, 1}, + {"SIOCBRDGGTO", Const, 1}, + {"SIOCBRDGIFS", Const, 1}, + {"SIOCBRDGRTS", Const, 1}, + {"SIOCBRDGSADDR", Const, 1}, + {"SIOCBRDGSCACHE", Const, 1}, + {"SIOCBRDGSFD", Const, 1}, + {"SIOCBRDGSHT", Const, 1}, + {"SIOCBRDGSIFCOST", Const, 1}, + {"SIOCBRDGSIFFLGS", Const, 1}, + {"SIOCBRDGSIFPRIO", Const, 1}, + {"SIOCBRDGSMA", Const, 1}, + {"SIOCBRDGSPRI", Const, 1}, + {"SIOCBRDGSPROTO", Const, 1}, + {"SIOCBRDGSTO", Const, 1}, + {"SIOCBRDGSTXHC", Const, 1}, + {"SIOCDARP", Const, 0}, + {"SIOCDELDLCI", Const, 0}, + {"SIOCDELMULTI", Const, 0}, + {"SIOCDELRT", Const, 0}, + {"SIOCDEVPRIVATE", Const, 0}, + {"SIOCDIFADDR", Const, 0}, + {"SIOCDIFGROUP", Const, 0}, + {"SIOCDIFPHYADDR", Const, 0}, + {"SIOCDLIFADDR", Const, 0}, + {"SIOCDRARP", Const, 0}, + {"SIOCGARP", Const, 0}, + {"SIOCGDRVSPEC", Const, 0}, + {"SIOCGETKALIVE", Const, 1}, + {"SIOCGETLABEL", Const, 1}, + {"SIOCGETPFLOW", Const, 1}, + {"SIOCGETPFSYNC", Const, 1}, + {"SIOCGETSGCNT", Const, 0}, + {"SIOCGETVIFCNT", Const, 0}, + {"SIOCGETVLAN", Const, 0}, + {"SIOCGHIWAT", Const, 0}, + {"SIOCGIFADDR", Const, 0}, + {"SIOCGIFADDRPREF", Const, 1}, + {"SIOCGIFALIAS", Const, 1}, + {"SIOCGIFALTMTU", Const, 0}, + {"SIOCGIFASYNCMAP", Const, 0}, + {"SIOCGIFBOND", Const, 0}, + {"SIOCGIFBR", Const, 0}, + {"SIOCGIFBRDADDR", Const, 0}, + {"SIOCGIFCAP", Const, 0}, + {"SIOCGIFCONF", Const, 0}, + {"SIOCGIFCOUNT", Const, 0}, + {"SIOCGIFDATA", Const, 1}, + {"SIOCGIFDESCR", Const, 0}, + {"SIOCGIFDEVMTU", Const, 0}, + {"SIOCGIFDLT", Const, 1}, + {"SIOCGIFDSTADDR", Const, 0}, + {"SIOCGIFENCAP", Const, 0}, + {"SIOCGIFFIB", Const, 1}, + {"SIOCGIFFLAGS", Const, 0}, + {"SIOCGIFGATTR", Const, 1}, + {"SIOCGIFGENERIC", Const, 0}, + {"SIOCGIFGMEMB", Const, 0}, + {"SIOCGIFGROUP", Const, 0}, + {"SIOCGIFHARDMTU", Const, 3}, + {"SIOCGIFHWADDR", Const, 0}, + {"SIOCGIFINDEX", Const, 0}, + {"SIOCGIFKPI", Const, 0}, + {"SIOCGIFMAC", Const, 0}, + {"SIOCGIFMAP", Const, 0}, + {"SIOCGIFMEDIA", Const, 0}, + {"SIOCGIFMEM", Const, 0}, + {"SIOCGIFMETRIC", Const, 0}, + {"SIOCGIFMTU", Const, 0}, + {"SIOCGIFNAME", Const, 0}, + {"SIOCGIFNETMASK", Const, 0}, + {"SIOCGIFPDSTADDR", Const, 0}, + {"SIOCGIFPFLAGS", Const, 0}, + {"SIOCGIFPHYS", Const, 0}, + {"SIOCGIFPRIORITY", Const, 1}, + {"SIOCGIFPSRCADDR", Const, 0}, + {"SIOCGIFRDOMAIN", Const, 1}, + {"SIOCGIFRTLABEL", Const, 1}, + {"SIOCGIFSLAVE", Const, 0}, + {"SIOCGIFSTATUS", Const, 0}, + {"SIOCGIFTIMESLOT", Const, 1}, + {"SIOCGIFTXQLEN", Const, 0}, + {"SIOCGIFVLAN", Const, 0}, + {"SIOCGIFWAKEFLAGS", Const, 0}, + {"SIOCGIFXFLAGS", Const, 1}, + {"SIOCGLIFADDR", Const, 0}, + {"SIOCGLIFPHYADDR", Const, 0}, + {"SIOCGLIFPHYRTABLE", Const, 1}, + {"SIOCGLIFPHYTTL", Const, 3}, + {"SIOCGLINKSTR", Const, 1}, + {"SIOCGLOWAT", Const, 0}, + {"SIOCGPGRP", Const, 0}, + {"SIOCGPRIVATE_0", Const, 0}, + {"SIOCGPRIVATE_1", Const, 0}, + {"SIOCGRARP", Const, 0}, + {"SIOCGSPPPPARAMS", Const, 3}, + {"SIOCGSTAMP", Const, 0}, + {"SIOCGSTAMPNS", Const, 0}, + {"SIOCGVH", Const, 1}, + {"SIOCGVNETID", Const, 3}, + {"SIOCIFCREATE", Const, 0}, + {"SIOCIFCREATE2", Const, 0}, + {"SIOCIFDESTROY", Const, 0}, + {"SIOCIFGCLONERS", Const, 0}, + {"SIOCINITIFADDR", Const, 1}, + {"SIOCPROTOPRIVATE", Const, 0}, + {"SIOCRSLVMULTI", Const, 0}, + {"SIOCRTMSG", Const, 0}, + {"SIOCSARP", Const, 0}, + {"SIOCSDRVSPEC", Const, 0}, + {"SIOCSETKALIVE", Const, 1}, + {"SIOCSETLABEL", Const, 1}, + {"SIOCSETPFLOW", Const, 1}, + {"SIOCSETPFSYNC", Const, 1}, + {"SIOCSETVLAN", Const, 0}, + {"SIOCSHIWAT", Const, 0}, + {"SIOCSIFADDR", Const, 0}, + {"SIOCSIFADDRPREF", Const, 1}, + {"SIOCSIFALTMTU", Const, 0}, + {"SIOCSIFASYNCMAP", Const, 0}, + {"SIOCSIFBOND", Const, 0}, + {"SIOCSIFBR", Const, 0}, + {"SIOCSIFBRDADDR", Const, 0}, + {"SIOCSIFCAP", Const, 0}, + {"SIOCSIFDESCR", Const, 0}, + {"SIOCSIFDSTADDR", Const, 0}, + {"SIOCSIFENCAP", Const, 0}, + {"SIOCSIFFIB", Const, 1}, + {"SIOCSIFFLAGS", Const, 0}, + {"SIOCSIFGATTR", Const, 1}, + {"SIOCSIFGENERIC", Const, 0}, + {"SIOCSIFHWADDR", Const, 0}, + {"SIOCSIFHWBROADCAST", Const, 0}, + {"SIOCSIFKPI", Const, 0}, + {"SIOCSIFLINK", Const, 0}, + {"SIOCSIFLLADDR", Const, 0}, + {"SIOCSIFMAC", Const, 0}, + {"SIOCSIFMAP", Const, 0}, + {"SIOCSIFMEDIA", Const, 0}, + {"SIOCSIFMEM", Const, 0}, + {"SIOCSIFMETRIC", Const, 0}, + {"SIOCSIFMTU", Const, 0}, + {"SIOCSIFNAME", Const, 0}, + {"SIOCSIFNETMASK", Const, 0}, + {"SIOCSIFPFLAGS", Const, 0}, + {"SIOCSIFPHYADDR", Const, 0}, + {"SIOCSIFPHYS", Const, 0}, + {"SIOCSIFPRIORITY", Const, 1}, + {"SIOCSIFRDOMAIN", Const, 1}, + {"SIOCSIFRTLABEL", Const, 1}, + {"SIOCSIFRVNET", Const, 0}, + {"SIOCSIFSLAVE", Const, 0}, + {"SIOCSIFTIMESLOT", Const, 1}, + {"SIOCSIFTXQLEN", Const, 0}, + {"SIOCSIFVLAN", Const, 0}, + {"SIOCSIFVNET", Const, 0}, + {"SIOCSIFXFLAGS", Const, 1}, + {"SIOCSLIFPHYADDR", Const, 0}, + {"SIOCSLIFPHYRTABLE", Const, 1}, + {"SIOCSLIFPHYTTL", Const, 3}, + {"SIOCSLINKSTR", Const, 1}, + {"SIOCSLOWAT", Const, 0}, + {"SIOCSPGRP", Const, 0}, + {"SIOCSRARP", Const, 0}, + {"SIOCSSPPPPARAMS", Const, 3}, + {"SIOCSVH", Const, 1}, + {"SIOCSVNETID", Const, 3}, + {"SIOCZIFDATA", Const, 1}, + {"SIO_GET_EXTENSION_FUNCTION_POINTER", Const, 1}, + {"SIO_GET_INTERFACE_LIST", Const, 0}, + {"SIO_KEEPALIVE_VALS", Const, 3}, + {"SIO_UDP_CONNRESET", Const, 4}, + {"SOCK_CLOEXEC", Const, 0}, + {"SOCK_DCCP", Const, 0}, + {"SOCK_DGRAM", Const, 0}, + {"SOCK_FLAGS_MASK", Const, 1}, + {"SOCK_MAXADDRLEN", Const, 0}, + {"SOCK_NONBLOCK", Const, 0}, + {"SOCK_NOSIGPIPE", Const, 1}, + {"SOCK_PACKET", Const, 0}, + {"SOCK_RAW", Const, 0}, + {"SOCK_RDM", Const, 0}, + {"SOCK_SEQPACKET", Const, 0}, + {"SOCK_STREAM", Const, 0}, + {"SOL_AAL", Const, 0}, + {"SOL_ATM", Const, 0}, + {"SOL_DECNET", Const, 0}, + {"SOL_ICMPV6", Const, 0}, + {"SOL_IP", Const, 0}, + {"SOL_IPV6", Const, 0}, + {"SOL_IRDA", Const, 0}, + {"SOL_PACKET", Const, 0}, + {"SOL_RAW", Const, 0}, + {"SOL_SOCKET", Const, 0}, + {"SOL_TCP", Const, 0}, + {"SOL_X25", Const, 0}, + {"SOMAXCONN", Const, 0}, + {"SO_ACCEPTCONN", Const, 0}, + {"SO_ACCEPTFILTER", Const, 0}, + {"SO_ATTACH_FILTER", Const, 0}, + {"SO_BINDANY", Const, 1}, + {"SO_BINDTODEVICE", Const, 0}, + {"SO_BINTIME", Const, 0}, + {"SO_BROADCAST", Const, 0}, + {"SO_BSDCOMPAT", Const, 0}, + {"SO_DEBUG", Const, 0}, + {"SO_DETACH_FILTER", Const, 0}, + {"SO_DOMAIN", Const, 0}, + {"SO_DONTROUTE", Const, 0}, + {"SO_DONTTRUNC", Const, 0}, + {"SO_ERROR", Const, 0}, + {"SO_KEEPALIVE", Const, 0}, + {"SO_LABEL", Const, 0}, + {"SO_LINGER", Const, 0}, + {"SO_LINGER_SEC", Const, 0}, + {"SO_LISTENINCQLEN", Const, 0}, + {"SO_LISTENQLEN", Const, 0}, + {"SO_LISTENQLIMIT", Const, 0}, + {"SO_MARK", Const, 0}, + {"SO_NETPROC", Const, 1}, + {"SO_NKE", Const, 0}, + {"SO_NOADDRERR", Const, 0}, + {"SO_NOHEADER", Const, 1}, + {"SO_NOSIGPIPE", Const, 0}, + {"SO_NOTIFYCONFLICT", Const, 0}, + {"SO_NO_CHECK", Const, 0}, + {"SO_NO_DDP", Const, 0}, + {"SO_NO_OFFLOAD", Const, 0}, + {"SO_NP_EXTENSIONS", Const, 0}, + {"SO_NREAD", Const, 0}, + {"SO_NUMRCVPKT", Const, 16}, + {"SO_NWRITE", Const, 0}, + {"SO_OOBINLINE", Const, 0}, + {"SO_OVERFLOWED", Const, 1}, + {"SO_PASSCRED", Const, 0}, + {"SO_PASSSEC", Const, 0}, + {"SO_PEERCRED", Const, 0}, + {"SO_PEERLABEL", Const, 0}, + {"SO_PEERNAME", Const, 0}, + {"SO_PEERSEC", Const, 0}, + {"SO_PRIORITY", Const, 0}, + {"SO_PROTOCOL", Const, 0}, + {"SO_PROTOTYPE", Const, 1}, + {"SO_RANDOMPORT", Const, 0}, + {"SO_RCVBUF", Const, 0}, + {"SO_RCVBUFFORCE", Const, 0}, + {"SO_RCVLOWAT", Const, 0}, + {"SO_RCVTIMEO", Const, 0}, + {"SO_RESTRICTIONS", Const, 0}, + {"SO_RESTRICT_DENYIN", Const, 0}, + {"SO_RESTRICT_DENYOUT", Const, 0}, + {"SO_RESTRICT_DENYSET", Const, 0}, + {"SO_REUSEADDR", Const, 0}, + {"SO_REUSEPORT", Const, 0}, + {"SO_REUSESHAREUID", Const, 0}, + {"SO_RTABLE", Const, 1}, + {"SO_RXQ_OVFL", Const, 0}, + {"SO_SECURITY_AUTHENTICATION", Const, 0}, + {"SO_SECURITY_ENCRYPTION_NETWORK", Const, 0}, + {"SO_SECURITY_ENCRYPTION_TRANSPORT", Const, 0}, + {"SO_SETFIB", Const, 0}, + {"SO_SNDBUF", Const, 0}, + {"SO_SNDBUFFORCE", Const, 0}, + {"SO_SNDLOWAT", Const, 0}, + {"SO_SNDTIMEO", Const, 0}, + {"SO_SPLICE", Const, 1}, + {"SO_TIMESTAMP", Const, 0}, + {"SO_TIMESTAMPING", Const, 0}, + {"SO_TIMESTAMPNS", Const, 0}, + {"SO_TIMESTAMP_MONOTONIC", Const, 0}, + {"SO_TYPE", Const, 0}, + {"SO_UPCALLCLOSEWAIT", Const, 0}, + {"SO_UPDATE_ACCEPT_CONTEXT", Const, 0}, + {"SO_UPDATE_CONNECT_CONTEXT", Const, 1}, + {"SO_USELOOPBACK", Const, 0}, + {"SO_USER_COOKIE", Const, 1}, + {"SO_VENDOR", Const, 3}, + {"SO_WANTMORE", Const, 0}, + {"SO_WANTOOBFLAG", Const, 0}, + {"SSLExtraCertChainPolicyPara", Type, 0}, + {"SSLExtraCertChainPolicyPara.AuthType", Field, 0}, + {"SSLExtraCertChainPolicyPara.Checks", Field, 0}, + {"SSLExtraCertChainPolicyPara.ServerName", Field, 0}, + {"SSLExtraCertChainPolicyPara.Size", Field, 0}, + {"STANDARD_RIGHTS_ALL", Const, 0}, + {"STANDARD_RIGHTS_EXECUTE", Const, 0}, + {"STANDARD_RIGHTS_READ", Const, 0}, + {"STANDARD_RIGHTS_REQUIRED", Const, 0}, + {"STANDARD_RIGHTS_WRITE", Const, 0}, + {"STARTF_USESHOWWINDOW", Const, 0}, + {"STARTF_USESTDHANDLES", Const, 0}, + {"STD_ERROR_HANDLE", Const, 0}, + {"STD_INPUT_HANDLE", Const, 0}, + {"STD_OUTPUT_HANDLE", Const, 0}, + {"SUBLANG_ENGLISH_US", Const, 0}, + {"SW_FORCEMINIMIZE", Const, 0}, + {"SW_HIDE", Const, 0}, + {"SW_MAXIMIZE", Const, 0}, + {"SW_MINIMIZE", Const, 0}, + {"SW_NORMAL", Const, 0}, + {"SW_RESTORE", Const, 0}, + {"SW_SHOW", Const, 0}, + {"SW_SHOWDEFAULT", Const, 0}, + {"SW_SHOWMAXIMIZED", Const, 0}, + {"SW_SHOWMINIMIZED", Const, 0}, + {"SW_SHOWMINNOACTIVE", Const, 0}, + {"SW_SHOWNA", Const, 0}, + {"SW_SHOWNOACTIVATE", Const, 0}, + {"SW_SHOWNORMAL", Const, 0}, + {"SYMBOLIC_LINK_FLAG_DIRECTORY", Const, 4}, + {"SYNCHRONIZE", Const, 0}, + {"SYSCTL_VERSION", Const, 1}, + {"SYSCTL_VERS_0", Const, 1}, + {"SYSCTL_VERS_1", Const, 1}, + {"SYSCTL_VERS_MASK", Const, 1}, + {"SYS_ABORT2", Const, 0}, + {"SYS_ACCEPT", Const, 0}, + {"SYS_ACCEPT4", Const, 0}, + {"SYS_ACCEPT_NOCANCEL", Const, 0}, + {"SYS_ACCESS", Const, 0}, + {"SYS_ACCESS_EXTENDED", Const, 0}, + {"SYS_ACCT", Const, 0}, + {"SYS_ADD_KEY", Const, 0}, + {"SYS_ADD_PROFIL", Const, 0}, + {"SYS_ADJFREQ", Const, 1}, + {"SYS_ADJTIME", Const, 0}, + {"SYS_ADJTIMEX", Const, 0}, + {"SYS_AFS_SYSCALL", Const, 0}, + {"SYS_AIO_CANCEL", Const, 0}, + {"SYS_AIO_ERROR", Const, 0}, + {"SYS_AIO_FSYNC", Const, 0}, + {"SYS_AIO_MLOCK", Const, 14}, + {"SYS_AIO_READ", Const, 0}, + {"SYS_AIO_RETURN", Const, 0}, + {"SYS_AIO_SUSPEND", Const, 0}, + {"SYS_AIO_SUSPEND_NOCANCEL", Const, 0}, + {"SYS_AIO_WAITCOMPLETE", Const, 14}, + {"SYS_AIO_WRITE", Const, 0}, + {"SYS_ALARM", Const, 0}, + {"SYS_ARCH_PRCTL", Const, 0}, + {"SYS_ARM_FADVISE64_64", Const, 0}, + {"SYS_ARM_SYNC_FILE_RANGE", Const, 0}, + {"SYS_ATGETMSG", Const, 0}, + {"SYS_ATPGETREQ", Const, 0}, + {"SYS_ATPGETRSP", Const, 0}, + {"SYS_ATPSNDREQ", Const, 0}, + {"SYS_ATPSNDRSP", Const, 0}, + {"SYS_ATPUTMSG", Const, 0}, + {"SYS_ATSOCKET", Const, 0}, + {"SYS_AUDIT", Const, 0}, + {"SYS_AUDITCTL", Const, 0}, + {"SYS_AUDITON", Const, 0}, + {"SYS_AUDIT_SESSION_JOIN", Const, 0}, + {"SYS_AUDIT_SESSION_PORT", Const, 0}, + {"SYS_AUDIT_SESSION_SELF", Const, 0}, + {"SYS_BDFLUSH", Const, 0}, + {"SYS_BIND", Const, 0}, + {"SYS_BINDAT", Const, 3}, + {"SYS_BREAK", Const, 0}, + {"SYS_BRK", Const, 0}, + {"SYS_BSDTHREAD_CREATE", Const, 0}, + {"SYS_BSDTHREAD_REGISTER", Const, 0}, + {"SYS_BSDTHREAD_TERMINATE", Const, 0}, + {"SYS_CAPGET", Const, 0}, + {"SYS_CAPSET", Const, 0}, + {"SYS_CAP_ENTER", Const, 0}, + {"SYS_CAP_FCNTLS_GET", Const, 1}, + {"SYS_CAP_FCNTLS_LIMIT", Const, 1}, + {"SYS_CAP_GETMODE", Const, 0}, + {"SYS_CAP_GETRIGHTS", Const, 0}, + {"SYS_CAP_IOCTLS_GET", Const, 1}, + {"SYS_CAP_IOCTLS_LIMIT", Const, 1}, + {"SYS_CAP_NEW", Const, 0}, + {"SYS_CAP_RIGHTS_GET", Const, 1}, + {"SYS_CAP_RIGHTS_LIMIT", Const, 1}, + {"SYS_CHDIR", Const, 0}, + {"SYS_CHFLAGS", Const, 0}, + {"SYS_CHFLAGSAT", Const, 3}, + {"SYS_CHMOD", Const, 0}, + {"SYS_CHMOD_EXTENDED", Const, 0}, + {"SYS_CHOWN", Const, 0}, + {"SYS_CHOWN32", Const, 0}, + {"SYS_CHROOT", Const, 0}, + {"SYS_CHUD", Const, 0}, + {"SYS_CLOCK_ADJTIME", Const, 0}, + {"SYS_CLOCK_GETCPUCLOCKID2", Const, 1}, + {"SYS_CLOCK_GETRES", Const, 0}, + {"SYS_CLOCK_GETTIME", Const, 0}, + {"SYS_CLOCK_NANOSLEEP", Const, 0}, + {"SYS_CLOCK_SETTIME", Const, 0}, + {"SYS_CLONE", Const, 0}, + {"SYS_CLOSE", Const, 0}, + {"SYS_CLOSEFROM", Const, 0}, + {"SYS_CLOSE_NOCANCEL", Const, 0}, + {"SYS_CONNECT", Const, 0}, + {"SYS_CONNECTAT", Const, 3}, + {"SYS_CONNECT_NOCANCEL", Const, 0}, + {"SYS_COPYFILE", Const, 0}, + {"SYS_CPUSET", Const, 0}, + {"SYS_CPUSET_GETAFFINITY", Const, 0}, + {"SYS_CPUSET_GETID", Const, 0}, + {"SYS_CPUSET_SETAFFINITY", Const, 0}, + {"SYS_CPUSET_SETID", Const, 0}, + {"SYS_CREAT", Const, 0}, + {"SYS_CREATE_MODULE", Const, 0}, + {"SYS_CSOPS", Const, 0}, + {"SYS_CSOPS_AUDITTOKEN", Const, 16}, + {"SYS_DELETE", Const, 0}, + {"SYS_DELETE_MODULE", Const, 0}, + {"SYS_DUP", Const, 0}, + {"SYS_DUP2", Const, 0}, + {"SYS_DUP3", Const, 0}, + {"SYS_EACCESS", Const, 0}, + {"SYS_EPOLL_CREATE", Const, 0}, + {"SYS_EPOLL_CREATE1", Const, 0}, + {"SYS_EPOLL_CTL", Const, 0}, + {"SYS_EPOLL_CTL_OLD", Const, 0}, + {"SYS_EPOLL_PWAIT", Const, 0}, + {"SYS_EPOLL_WAIT", Const, 0}, + {"SYS_EPOLL_WAIT_OLD", Const, 0}, + {"SYS_EVENTFD", Const, 0}, + {"SYS_EVENTFD2", Const, 0}, + {"SYS_EXCHANGEDATA", Const, 0}, + {"SYS_EXECVE", Const, 0}, + {"SYS_EXIT", Const, 0}, + {"SYS_EXIT_GROUP", Const, 0}, + {"SYS_EXTATTRCTL", Const, 0}, + {"SYS_EXTATTR_DELETE_FD", Const, 0}, + {"SYS_EXTATTR_DELETE_FILE", Const, 0}, + {"SYS_EXTATTR_DELETE_LINK", Const, 0}, + {"SYS_EXTATTR_GET_FD", Const, 0}, + {"SYS_EXTATTR_GET_FILE", Const, 0}, + {"SYS_EXTATTR_GET_LINK", Const, 0}, + {"SYS_EXTATTR_LIST_FD", Const, 0}, + {"SYS_EXTATTR_LIST_FILE", Const, 0}, + {"SYS_EXTATTR_LIST_LINK", Const, 0}, + {"SYS_EXTATTR_SET_FD", Const, 0}, + {"SYS_EXTATTR_SET_FILE", Const, 0}, + {"SYS_EXTATTR_SET_LINK", Const, 0}, + {"SYS_FACCESSAT", Const, 0}, + {"SYS_FADVISE64", Const, 0}, + {"SYS_FADVISE64_64", Const, 0}, + {"SYS_FALLOCATE", Const, 0}, + {"SYS_FANOTIFY_INIT", Const, 0}, + {"SYS_FANOTIFY_MARK", Const, 0}, + {"SYS_FCHDIR", Const, 0}, + {"SYS_FCHFLAGS", Const, 0}, + {"SYS_FCHMOD", Const, 0}, + {"SYS_FCHMODAT", Const, 0}, + {"SYS_FCHMOD_EXTENDED", Const, 0}, + {"SYS_FCHOWN", Const, 0}, + {"SYS_FCHOWN32", Const, 0}, + {"SYS_FCHOWNAT", Const, 0}, + {"SYS_FCHROOT", Const, 1}, + {"SYS_FCNTL", Const, 0}, + {"SYS_FCNTL64", Const, 0}, + {"SYS_FCNTL_NOCANCEL", Const, 0}, + {"SYS_FDATASYNC", Const, 0}, + {"SYS_FEXECVE", Const, 0}, + {"SYS_FFCLOCK_GETCOUNTER", Const, 0}, + {"SYS_FFCLOCK_GETESTIMATE", Const, 0}, + {"SYS_FFCLOCK_SETESTIMATE", Const, 0}, + {"SYS_FFSCTL", Const, 0}, + {"SYS_FGETATTRLIST", Const, 0}, + {"SYS_FGETXATTR", Const, 0}, + {"SYS_FHOPEN", Const, 0}, + {"SYS_FHSTAT", Const, 0}, + {"SYS_FHSTATFS", Const, 0}, + {"SYS_FILEPORT_MAKEFD", Const, 0}, + {"SYS_FILEPORT_MAKEPORT", Const, 0}, + {"SYS_FKTRACE", Const, 1}, + {"SYS_FLISTXATTR", Const, 0}, + {"SYS_FLOCK", Const, 0}, + {"SYS_FORK", Const, 0}, + {"SYS_FPATHCONF", Const, 0}, + {"SYS_FREEBSD6_FTRUNCATE", Const, 0}, + {"SYS_FREEBSD6_LSEEK", Const, 0}, + {"SYS_FREEBSD6_MMAP", Const, 0}, + {"SYS_FREEBSD6_PREAD", Const, 0}, + {"SYS_FREEBSD6_PWRITE", Const, 0}, + {"SYS_FREEBSD6_TRUNCATE", Const, 0}, + {"SYS_FREMOVEXATTR", Const, 0}, + {"SYS_FSCTL", Const, 0}, + {"SYS_FSETATTRLIST", Const, 0}, + {"SYS_FSETXATTR", Const, 0}, + {"SYS_FSGETPATH", Const, 0}, + {"SYS_FSTAT", Const, 0}, + {"SYS_FSTAT64", Const, 0}, + {"SYS_FSTAT64_EXTENDED", Const, 0}, + {"SYS_FSTATAT", Const, 0}, + {"SYS_FSTATAT64", Const, 0}, + {"SYS_FSTATFS", Const, 0}, + {"SYS_FSTATFS64", Const, 0}, + {"SYS_FSTATV", Const, 0}, + {"SYS_FSTATVFS1", Const, 1}, + {"SYS_FSTAT_EXTENDED", Const, 0}, + {"SYS_FSYNC", Const, 0}, + {"SYS_FSYNC_NOCANCEL", Const, 0}, + {"SYS_FSYNC_RANGE", Const, 1}, + {"SYS_FTIME", Const, 0}, + {"SYS_FTRUNCATE", Const, 0}, + {"SYS_FTRUNCATE64", Const, 0}, + {"SYS_FUTEX", Const, 0}, + {"SYS_FUTIMENS", Const, 1}, + {"SYS_FUTIMES", Const, 0}, + {"SYS_FUTIMESAT", Const, 0}, + {"SYS_GETATTRLIST", Const, 0}, + {"SYS_GETAUDIT", Const, 0}, + {"SYS_GETAUDIT_ADDR", Const, 0}, + {"SYS_GETAUID", Const, 0}, + {"SYS_GETCONTEXT", Const, 0}, + {"SYS_GETCPU", Const, 0}, + {"SYS_GETCWD", Const, 0}, + {"SYS_GETDENTS", Const, 0}, + {"SYS_GETDENTS64", Const, 0}, + {"SYS_GETDIRENTRIES", Const, 0}, + {"SYS_GETDIRENTRIES64", Const, 0}, + {"SYS_GETDIRENTRIESATTR", Const, 0}, + {"SYS_GETDTABLECOUNT", Const, 1}, + {"SYS_GETDTABLESIZE", Const, 0}, + {"SYS_GETEGID", Const, 0}, + {"SYS_GETEGID32", Const, 0}, + {"SYS_GETEUID", Const, 0}, + {"SYS_GETEUID32", Const, 0}, + {"SYS_GETFH", Const, 0}, + {"SYS_GETFSSTAT", Const, 0}, + {"SYS_GETFSSTAT64", Const, 0}, + {"SYS_GETGID", Const, 0}, + {"SYS_GETGID32", Const, 0}, + {"SYS_GETGROUPS", Const, 0}, + {"SYS_GETGROUPS32", Const, 0}, + {"SYS_GETHOSTUUID", Const, 0}, + {"SYS_GETITIMER", Const, 0}, + {"SYS_GETLCID", Const, 0}, + {"SYS_GETLOGIN", Const, 0}, + {"SYS_GETLOGINCLASS", Const, 0}, + {"SYS_GETPEERNAME", Const, 0}, + {"SYS_GETPGID", Const, 0}, + {"SYS_GETPGRP", Const, 0}, + {"SYS_GETPID", Const, 0}, + {"SYS_GETPMSG", Const, 0}, + {"SYS_GETPPID", Const, 0}, + {"SYS_GETPRIORITY", Const, 0}, + {"SYS_GETRESGID", Const, 0}, + {"SYS_GETRESGID32", Const, 0}, + {"SYS_GETRESUID", Const, 0}, + {"SYS_GETRESUID32", Const, 0}, + {"SYS_GETRLIMIT", Const, 0}, + {"SYS_GETRTABLE", Const, 1}, + {"SYS_GETRUSAGE", Const, 0}, + {"SYS_GETSGROUPS", Const, 0}, + {"SYS_GETSID", Const, 0}, + {"SYS_GETSOCKNAME", Const, 0}, + {"SYS_GETSOCKOPT", Const, 0}, + {"SYS_GETTHRID", Const, 1}, + {"SYS_GETTID", Const, 0}, + {"SYS_GETTIMEOFDAY", Const, 0}, + {"SYS_GETUID", Const, 0}, + {"SYS_GETUID32", Const, 0}, + {"SYS_GETVFSSTAT", Const, 1}, + {"SYS_GETWGROUPS", Const, 0}, + {"SYS_GETXATTR", Const, 0}, + {"SYS_GET_KERNEL_SYMS", Const, 0}, + {"SYS_GET_MEMPOLICY", Const, 0}, + {"SYS_GET_ROBUST_LIST", Const, 0}, + {"SYS_GET_THREAD_AREA", Const, 0}, + {"SYS_GSSD_SYSCALL", Const, 14}, + {"SYS_GTTY", Const, 0}, + {"SYS_IDENTITYSVC", Const, 0}, + {"SYS_IDLE", Const, 0}, + {"SYS_INITGROUPS", Const, 0}, + {"SYS_INIT_MODULE", Const, 0}, + {"SYS_INOTIFY_ADD_WATCH", Const, 0}, + {"SYS_INOTIFY_INIT", Const, 0}, + {"SYS_INOTIFY_INIT1", Const, 0}, + {"SYS_INOTIFY_RM_WATCH", Const, 0}, + {"SYS_IOCTL", Const, 0}, + {"SYS_IOPERM", Const, 0}, + {"SYS_IOPL", Const, 0}, + {"SYS_IOPOLICYSYS", Const, 0}, + {"SYS_IOPRIO_GET", Const, 0}, + {"SYS_IOPRIO_SET", Const, 0}, + {"SYS_IO_CANCEL", Const, 0}, + {"SYS_IO_DESTROY", Const, 0}, + {"SYS_IO_GETEVENTS", Const, 0}, + {"SYS_IO_SETUP", Const, 0}, + {"SYS_IO_SUBMIT", Const, 0}, + {"SYS_IPC", Const, 0}, + {"SYS_ISSETUGID", Const, 0}, + {"SYS_JAIL", Const, 0}, + {"SYS_JAIL_ATTACH", Const, 0}, + {"SYS_JAIL_GET", Const, 0}, + {"SYS_JAIL_REMOVE", Const, 0}, + {"SYS_JAIL_SET", Const, 0}, + {"SYS_KAS_INFO", Const, 16}, + {"SYS_KDEBUG_TRACE", Const, 0}, + {"SYS_KENV", Const, 0}, + {"SYS_KEVENT", Const, 0}, + {"SYS_KEVENT64", Const, 0}, + {"SYS_KEXEC_LOAD", Const, 0}, + {"SYS_KEYCTL", Const, 0}, + {"SYS_KILL", Const, 0}, + {"SYS_KLDFIND", Const, 0}, + {"SYS_KLDFIRSTMOD", Const, 0}, + {"SYS_KLDLOAD", Const, 0}, + {"SYS_KLDNEXT", Const, 0}, + {"SYS_KLDSTAT", Const, 0}, + {"SYS_KLDSYM", Const, 0}, + {"SYS_KLDUNLOAD", Const, 0}, + {"SYS_KLDUNLOADF", Const, 0}, + {"SYS_KMQ_NOTIFY", Const, 14}, + {"SYS_KMQ_OPEN", Const, 14}, + {"SYS_KMQ_SETATTR", Const, 14}, + {"SYS_KMQ_TIMEDRECEIVE", Const, 14}, + {"SYS_KMQ_TIMEDSEND", Const, 14}, + {"SYS_KMQ_UNLINK", Const, 14}, + {"SYS_KQUEUE", Const, 0}, + {"SYS_KQUEUE1", Const, 1}, + {"SYS_KSEM_CLOSE", Const, 14}, + {"SYS_KSEM_DESTROY", Const, 14}, + {"SYS_KSEM_GETVALUE", Const, 14}, + {"SYS_KSEM_INIT", Const, 14}, + {"SYS_KSEM_OPEN", Const, 14}, + {"SYS_KSEM_POST", Const, 14}, + {"SYS_KSEM_TIMEDWAIT", Const, 14}, + {"SYS_KSEM_TRYWAIT", Const, 14}, + {"SYS_KSEM_UNLINK", Const, 14}, + {"SYS_KSEM_WAIT", Const, 14}, + {"SYS_KTIMER_CREATE", Const, 0}, + {"SYS_KTIMER_DELETE", Const, 0}, + {"SYS_KTIMER_GETOVERRUN", Const, 0}, + {"SYS_KTIMER_GETTIME", Const, 0}, + {"SYS_KTIMER_SETTIME", Const, 0}, + {"SYS_KTRACE", Const, 0}, + {"SYS_LCHFLAGS", Const, 0}, + {"SYS_LCHMOD", Const, 0}, + {"SYS_LCHOWN", Const, 0}, + {"SYS_LCHOWN32", Const, 0}, + {"SYS_LEDGER", Const, 16}, + {"SYS_LGETFH", Const, 0}, + {"SYS_LGETXATTR", Const, 0}, + {"SYS_LINK", Const, 0}, + {"SYS_LINKAT", Const, 0}, + {"SYS_LIO_LISTIO", Const, 0}, + {"SYS_LISTEN", Const, 0}, + {"SYS_LISTXATTR", Const, 0}, + {"SYS_LLISTXATTR", Const, 0}, + {"SYS_LOCK", Const, 0}, + {"SYS_LOOKUP_DCOOKIE", Const, 0}, + {"SYS_LPATHCONF", Const, 0}, + {"SYS_LREMOVEXATTR", Const, 0}, + {"SYS_LSEEK", Const, 0}, + {"SYS_LSETXATTR", Const, 0}, + {"SYS_LSTAT", Const, 0}, + {"SYS_LSTAT64", Const, 0}, + {"SYS_LSTAT64_EXTENDED", Const, 0}, + {"SYS_LSTATV", Const, 0}, + {"SYS_LSTAT_EXTENDED", Const, 0}, + {"SYS_LUTIMES", Const, 0}, + {"SYS_MAC_SYSCALL", Const, 0}, + {"SYS_MADVISE", Const, 0}, + {"SYS_MADVISE1", Const, 0}, + {"SYS_MAXSYSCALL", Const, 0}, + {"SYS_MBIND", Const, 0}, + {"SYS_MIGRATE_PAGES", Const, 0}, + {"SYS_MINCORE", Const, 0}, + {"SYS_MINHERIT", Const, 0}, + {"SYS_MKCOMPLEX", Const, 0}, + {"SYS_MKDIR", Const, 0}, + {"SYS_MKDIRAT", Const, 0}, + {"SYS_MKDIR_EXTENDED", Const, 0}, + {"SYS_MKFIFO", Const, 0}, + {"SYS_MKFIFOAT", Const, 0}, + {"SYS_MKFIFO_EXTENDED", Const, 0}, + {"SYS_MKNOD", Const, 0}, + {"SYS_MKNODAT", Const, 0}, + {"SYS_MLOCK", Const, 0}, + {"SYS_MLOCKALL", Const, 0}, + {"SYS_MMAP", Const, 0}, + {"SYS_MMAP2", Const, 0}, + {"SYS_MODCTL", Const, 1}, + {"SYS_MODFIND", Const, 0}, + {"SYS_MODFNEXT", Const, 0}, + {"SYS_MODIFY_LDT", Const, 0}, + {"SYS_MODNEXT", Const, 0}, + {"SYS_MODSTAT", Const, 0}, + {"SYS_MODWATCH", Const, 0}, + {"SYS_MOUNT", Const, 0}, + {"SYS_MOVE_PAGES", Const, 0}, + {"SYS_MPROTECT", Const, 0}, + {"SYS_MPX", Const, 0}, + {"SYS_MQUERY", Const, 1}, + {"SYS_MQ_GETSETATTR", Const, 0}, + {"SYS_MQ_NOTIFY", Const, 0}, + {"SYS_MQ_OPEN", Const, 0}, + {"SYS_MQ_TIMEDRECEIVE", Const, 0}, + {"SYS_MQ_TIMEDSEND", Const, 0}, + {"SYS_MQ_UNLINK", Const, 0}, + {"SYS_MREMAP", Const, 0}, + {"SYS_MSGCTL", Const, 0}, + {"SYS_MSGGET", Const, 0}, + {"SYS_MSGRCV", Const, 0}, + {"SYS_MSGRCV_NOCANCEL", Const, 0}, + {"SYS_MSGSND", Const, 0}, + {"SYS_MSGSND_NOCANCEL", Const, 0}, + {"SYS_MSGSYS", Const, 0}, + {"SYS_MSYNC", Const, 0}, + {"SYS_MSYNC_NOCANCEL", Const, 0}, + {"SYS_MUNLOCK", Const, 0}, + {"SYS_MUNLOCKALL", Const, 0}, + {"SYS_MUNMAP", Const, 0}, + {"SYS_NAME_TO_HANDLE_AT", Const, 0}, + {"SYS_NANOSLEEP", Const, 0}, + {"SYS_NEWFSTATAT", Const, 0}, + {"SYS_NFSCLNT", Const, 0}, + {"SYS_NFSSERVCTL", Const, 0}, + {"SYS_NFSSVC", Const, 0}, + {"SYS_NFSTAT", Const, 0}, + {"SYS_NICE", Const, 0}, + {"SYS_NLM_SYSCALL", Const, 14}, + {"SYS_NLSTAT", Const, 0}, + {"SYS_NMOUNT", Const, 0}, + {"SYS_NSTAT", Const, 0}, + {"SYS_NTP_ADJTIME", Const, 0}, + {"SYS_NTP_GETTIME", Const, 0}, + {"SYS_NUMA_GETAFFINITY", Const, 14}, + {"SYS_NUMA_SETAFFINITY", Const, 14}, + {"SYS_OABI_SYSCALL_BASE", Const, 0}, + {"SYS_OBREAK", Const, 0}, + {"SYS_OLDFSTAT", Const, 0}, + {"SYS_OLDLSTAT", Const, 0}, + {"SYS_OLDOLDUNAME", Const, 0}, + {"SYS_OLDSTAT", Const, 0}, + {"SYS_OLDUNAME", Const, 0}, + {"SYS_OPEN", Const, 0}, + {"SYS_OPENAT", Const, 0}, + {"SYS_OPENBSD_POLL", Const, 0}, + {"SYS_OPEN_BY_HANDLE_AT", Const, 0}, + {"SYS_OPEN_DPROTECTED_NP", Const, 16}, + {"SYS_OPEN_EXTENDED", Const, 0}, + {"SYS_OPEN_NOCANCEL", Const, 0}, + {"SYS_OVADVISE", Const, 0}, + {"SYS_PACCEPT", Const, 1}, + {"SYS_PATHCONF", Const, 0}, + {"SYS_PAUSE", Const, 0}, + {"SYS_PCICONFIG_IOBASE", Const, 0}, + {"SYS_PCICONFIG_READ", Const, 0}, + {"SYS_PCICONFIG_WRITE", Const, 0}, + {"SYS_PDFORK", Const, 0}, + {"SYS_PDGETPID", Const, 0}, + {"SYS_PDKILL", Const, 0}, + {"SYS_PERF_EVENT_OPEN", Const, 0}, + {"SYS_PERSONALITY", Const, 0}, + {"SYS_PID_HIBERNATE", Const, 0}, + {"SYS_PID_RESUME", Const, 0}, + {"SYS_PID_SHUTDOWN_SOCKETS", Const, 0}, + {"SYS_PID_SUSPEND", Const, 0}, + {"SYS_PIPE", Const, 0}, + {"SYS_PIPE2", Const, 0}, + {"SYS_PIVOT_ROOT", Const, 0}, + {"SYS_PMC_CONTROL", Const, 1}, + {"SYS_PMC_GET_INFO", Const, 1}, + {"SYS_POLL", Const, 0}, + {"SYS_POLLTS", Const, 1}, + {"SYS_POLL_NOCANCEL", Const, 0}, + {"SYS_POSIX_FADVISE", Const, 0}, + {"SYS_POSIX_FALLOCATE", Const, 0}, + {"SYS_POSIX_OPENPT", Const, 0}, + {"SYS_POSIX_SPAWN", Const, 0}, + {"SYS_PPOLL", Const, 0}, + {"SYS_PRCTL", Const, 0}, + {"SYS_PREAD", Const, 0}, + {"SYS_PREAD64", Const, 0}, + {"SYS_PREADV", Const, 0}, + {"SYS_PREAD_NOCANCEL", Const, 0}, + {"SYS_PRLIMIT64", Const, 0}, + {"SYS_PROCCTL", Const, 3}, + {"SYS_PROCESS_POLICY", Const, 0}, + {"SYS_PROCESS_VM_READV", Const, 0}, + {"SYS_PROCESS_VM_WRITEV", Const, 0}, + {"SYS_PROC_INFO", Const, 0}, + {"SYS_PROF", Const, 0}, + {"SYS_PROFIL", Const, 0}, + {"SYS_PSELECT", Const, 0}, + {"SYS_PSELECT6", Const, 0}, + {"SYS_PSET_ASSIGN", Const, 1}, + {"SYS_PSET_CREATE", Const, 1}, + {"SYS_PSET_DESTROY", Const, 1}, + {"SYS_PSYNCH_CVBROAD", Const, 0}, + {"SYS_PSYNCH_CVCLRPREPOST", Const, 0}, + {"SYS_PSYNCH_CVSIGNAL", Const, 0}, + {"SYS_PSYNCH_CVWAIT", Const, 0}, + {"SYS_PSYNCH_MUTEXDROP", Const, 0}, + {"SYS_PSYNCH_MUTEXWAIT", Const, 0}, + {"SYS_PSYNCH_RW_DOWNGRADE", Const, 0}, + {"SYS_PSYNCH_RW_LONGRDLOCK", Const, 0}, + {"SYS_PSYNCH_RW_RDLOCK", Const, 0}, + {"SYS_PSYNCH_RW_UNLOCK", Const, 0}, + {"SYS_PSYNCH_RW_UNLOCK2", Const, 0}, + {"SYS_PSYNCH_RW_UPGRADE", Const, 0}, + {"SYS_PSYNCH_RW_WRLOCK", Const, 0}, + {"SYS_PSYNCH_RW_YIELDWRLOCK", Const, 0}, + {"SYS_PTRACE", Const, 0}, + {"SYS_PUTPMSG", Const, 0}, + {"SYS_PWRITE", Const, 0}, + {"SYS_PWRITE64", Const, 0}, + {"SYS_PWRITEV", Const, 0}, + {"SYS_PWRITE_NOCANCEL", Const, 0}, + {"SYS_QUERY_MODULE", Const, 0}, + {"SYS_QUOTACTL", Const, 0}, + {"SYS_RASCTL", Const, 1}, + {"SYS_RCTL_ADD_RULE", Const, 0}, + {"SYS_RCTL_GET_LIMITS", Const, 0}, + {"SYS_RCTL_GET_RACCT", Const, 0}, + {"SYS_RCTL_GET_RULES", Const, 0}, + {"SYS_RCTL_REMOVE_RULE", Const, 0}, + {"SYS_READ", Const, 0}, + {"SYS_READAHEAD", Const, 0}, + {"SYS_READDIR", Const, 0}, + {"SYS_READLINK", Const, 0}, + {"SYS_READLINKAT", Const, 0}, + {"SYS_READV", Const, 0}, + {"SYS_READV_NOCANCEL", Const, 0}, + {"SYS_READ_NOCANCEL", Const, 0}, + {"SYS_REBOOT", Const, 0}, + {"SYS_RECV", Const, 0}, + {"SYS_RECVFROM", Const, 0}, + {"SYS_RECVFROM_NOCANCEL", Const, 0}, + {"SYS_RECVMMSG", Const, 0}, + {"SYS_RECVMSG", Const, 0}, + {"SYS_RECVMSG_NOCANCEL", Const, 0}, + {"SYS_REMAP_FILE_PAGES", Const, 0}, + {"SYS_REMOVEXATTR", Const, 0}, + {"SYS_RENAME", Const, 0}, + {"SYS_RENAMEAT", Const, 0}, + {"SYS_REQUEST_KEY", Const, 0}, + {"SYS_RESTART_SYSCALL", Const, 0}, + {"SYS_REVOKE", Const, 0}, + {"SYS_RFORK", Const, 0}, + {"SYS_RMDIR", Const, 0}, + {"SYS_RTPRIO", Const, 0}, + {"SYS_RTPRIO_THREAD", Const, 0}, + {"SYS_RT_SIGACTION", Const, 0}, + {"SYS_RT_SIGPENDING", Const, 0}, + {"SYS_RT_SIGPROCMASK", Const, 0}, + {"SYS_RT_SIGQUEUEINFO", Const, 0}, + {"SYS_RT_SIGRETURN", Const, 0}, + {"SYS_RT_SIGSUSPEND", Const, 0}, + {"SYS_RT_SIGTIMEDWAIT", Const, 0}, + {"SYS_RT_TGSIGQUEUEINFO", Const, 0}, + {"SYS_SBRK", Const, 0}, + {"SYS_SCHED_GETAFFINITY", Const, 0}, + {"SYS_SCHED_GETPARAM", Const, 0}, + {"SYS_SCHED_GETSCHEDULER", Const, 0}, + {"SYS_SCHED_GET_PRIORITY_MAX", Const, 0}, + {"SYS_SCHED_GET_PRIORITY_MIN", Const, 0}, + {"SYS_SCHED_RR_GET_INTERVAL", Const, 0}, + {"SYS_SCHED_SETAFFINITY", Const, 0}, + {"SYS_SCHED_SETPARAM", Const, 0}, + {"SYS_SCHED_SETSCHEDULER", Const, 0}, + {"SYS_SCHED_YIELD", Const, 0}, + {"SYS_SCTP_GENERIC_RECVMSG", Const, 0}, + {"SYS_SCTP_GENERIC_SENDMSG", Const, 0}, + {"SYS_SCTP_GENERIC_SENDMSG_IOV", Const, 0}, + {"SYS_SCTP_PEELOFF", Const, 0}, + {"SYS_SEARCHFS", Const, 0}, + {"SYS_SECURITY", Const, 0}, + {"SYS_SELECT", Const, 0}, + {"SYS_SELECT_NOCANCEL", Const, 0}, + {"SYS_SEMCONFIG", Const, 1}, + {"SYS_SEMCTL", Const, 0}, + {"SYS_SEMGET", Const, 0}, + {"SYS_SEMOP", Const, 0}, + {"SYS_SEMSYS", Const, 0}, + {"SYS_SEMTIMEDOP", Const, 0}, + {"SYS_SEM_CLOSE", Const, 0}, + {"SYS_SEM_DESTROY", Const, 0}, + {"SYS_SEM_GETVALUE", Const, 0}, + {"SYS_SEM_INIT", Const, 0}, + {"SYS_SEM_OPEN", Const, 0}, + {"SYS_SEM_POST", Const, 0}, + {"SYS_SEM_TRYWAIT", Const, 0}, + {"SYS_SEM_UNLINK", Const, 0}, + {"SYS_SEM_WAIT", Const, 0}, + {"SYS_SEM_WAIT_NOCANCEL", Const, 0}, + {"SYS_SEND", Const, 0}, + {"SYS_SENDFILE", Const, 0}, + {"SYS_SENDFILE64", Const, 0}, + {"SYS_SENDMMSG", Const, 0}, + {"SYS_SENDMSG", Const, 0}, + {"SYS_SENDMSG_NOCANCEL", Const, 0}, + {"SYS_SENDTO", Const, 0}, + {"SYS_SENDTO_NOCANCEL", Const, 0}, + {"SYS_SETATTRLIST", Const, 0}, + {"SYS_SETAUDIT", Const, 0}, + {"SYS_SETAUDIT_ADDR", Const, 0}, + {"SYS_SETAUID", Const, 0}, + {"SYS_SETCONTEXT", Const, 0}, + {"SYS_SETDOMAINNAME", Const, 0}, + {"SYS_SETEGID", Const, 0}, + {"SYS_SETEUID", Const, 0}, + {"SYS_SETFIB", Const, 0}, + {"SYS_SETFSGID", Const, 0}, + {"SYS_SETFSGID32", Const, 0}, + {"SYS_SETFSUID", Const, 0}, + {"SYS_SETFSUID32", Const, 0}, + {"SYS_SETGID", Const, 0}, + {"SYS_SETGID32", Const, 0}, + {"SYS_SETGROUPS", Const, 0}, + {"SYS_SETGROUPS32", Const, 0}, + {"SYS_SETHOSTNAME", Const, 0}, + {"SYS_SETITIMER", Const, 0}, + {"SYS_SETLCID", Const, 0}, + {"SYS_SETLOGIN", Const, 0}, + {"SYS_SETLOGINCLASS", Const, 0}, + {"SYS_SETNS", Const, 0}, + {"SYS_SETPGID", Const, 0}, + {"SYS_SETPRIORITY", Const, 0}, + {"SYS_SETPRIVEXEC", Const, 0}, + {"SYS_SETREGID", Const, 0}, + {"SYS_SETREGID32", Const, 0}, + {"SYS_SETRESGID", Const, 0}, + {"SYS_SETRESGID32", Const, 0}, + {"SYS_SETRESUID", Const, 0}, + {"SYS_SETRESUID32", Const, 0}, + {"SYS_SETREUID", Const, 0}, + {"SYS_SETREUID32", Const, 0}, + {"SYS_SETRLIMIT", Const, 0}, + {"SYS_SETRTABLE", Const, 1}, + {"SYS_SETSGROUPS", Const, 0}, + {"SYS_SETSID", Const, 0}, + {"SYS_SETSOCKOPT", Const, 0}, + {"SYS_SETTID", Const, 0}, + {"SYS_SETTID_WITH_PID", Const, 0}, + {"SYS_SETTIMEOFDAY", Const, 0}, + {"SYS_SETUID", Const, 0}, + {"SYS_SETUID32", Const, 0}, + {"SYS_SETWGROUPS", Const, 0}, + {"SYS_SETXATTR", Const, 0}, + {"SYS_SET_MEMPOLICY", Const, 0}, + {"SYS_SET_ROBUST_LIST", Const, 0}, + {"SYS_SET_THREAD_AREA", Const, 0}, + {"SYS_SET_TID_ADDRESS", Const, 0}, + {"SYS_SGETMASK", Const, 0}, + {"SYS_SHARED_REGION_CHECK_NP", Const, 0}, + {"SYS_SHARED_REGION_MAP_AND_SLIDE_NP", Const, 0}, + {"SYS_SHMAT", Const, 0}, + {"SYS_SHMCTL", Const, 0}, + {"SYS_SHMDT", Const, 0}, + {"SYS_SHMGET", Const, 0}, + {"SYS_SHMSYS", Const, 0}, + {"SYS_SHM_OPEN", Const, 0}, + {"SYS_SHM_UNLINK", Const, 0}, + {"SYS_SHUTDOWN", Const, 0}, + {"SYS_SIGACTION", Const, 0}, + {"SYS_SIGALTSTACK", Const, 0}, + {"SYS_SIGNAL", Const, 0}, + {"SYS_SIGNALFD", Const, 0}, + {"SYS_SIGNALFD4", Const, 0}, + {"SYS_SIGPENDING", Const, 0}, + {"SYS_SIGPROCMASK", Const, 0}, + {"SYS_SIGQUEUE", Const, 0}, + {"SYS_SIGQUEUEINFO", Const, 1}, + {"SYS_SIGRETURN", Const, 0}, + {"SYS_SIGSUSPEND", Const, 0}, + {"SYS_SIGSUSPEND_NOCANCEL", Const, 0}, + {"SYS_SIGTIMEDWAIT", Const, 0}, + {"SYS_SIGWAIT", Const, 0}, + {"SYS_SIGWAITINFO", Const, 0}, + {"SYS_SOCKET", Const, 0}, + {"SYS_SOCKETCALL", Const, 0}, + {"SYS_SOCKETPAIR", Const, 0}, + {"SYS_SPLICE", Const, 0}, + {"SYS_SSETMASK", Const, 0}, + {"SYS_SSTK", Const, 0}, + {"SYS_STACK_SNAPSHOT", Const, 0}, + {"SYS_STAT", Const, 0}, + {"SYS_STAT64", Const, 0}, + {"SYS_STAT64_EXTENDED", Const, 0}, + {"SYS_STATFS", Const, 0}, + {"SYS_STATFS64", Const, 0}, + {"SYS_STATV", Const, 0}, + {"SYS_STATVFS1", Const, 1}, + {"SYS_STAT_EXTENDED", Const, 0}, + {"SYS_STIME", Const, 0}, + {"SYS_STTY", Const, 0}, + {"SYS_SWAPCONTEXT", Const, 0}, + {"SYS_SWAPCTL", Const, 1}, + {"SYS_SWAPOFF", Const, 0}, + {"SYS_SWAPON", Const, 0}, + {"SYS_SYMLINK", Const, 0}, + {"SYS_SYMLINKAT", Const, 0}, + {"SYS_SYNC", Const, 0}, + {"SYS_SYNCFS", Const, 0}, + {"SYS_SYNC_FILE_RANGE", Const, 0}, + {"SYS_SYSARCH", Const, 0}, + {"SYS_SYSCALL", Const, 0}, + {"SYS_SYSCALL_BASE", Const, 0}, + {"SYS_SYSFS", Const, 0}, + {"SYS_SYSINFO", Const, 0}, + {"SYS_SYSLOG", Const, 0}, + {"SYS_TEE", Const, 0}, + {"SYS_TGKILL", Const, 0}, + {"SYS_THREAD_SELFID", Const, 0}, + {"SYS_THR_CREATE", Const, 0}, + {"SYS_THR_EXIT", Const, 0}, + {"SYS_THR_KILL", Const, 0}, + {"SYS_THR_KILL2", Const, 0}, + {"SYS_THR_NEW", Const, 0}, + {"SYS_THR_SELF", Const, 0}, + {"SYS_THR_SET_NAME", Const, 0}, + {"SYS_THR_SUSPEND", Const, 0}, + {"SYS_THR_WAKE", Const, 0}, + {"SYS_TIME", Const, 0}, + {"SYS_TIMERFD_CREATE", Const, 0}, + {"SYS_TIMERFD_GETTIME", Const, 0}, + {"SYS_TIMERFD_SETTIME", Const, 0}, + {"SYS_TIMER_CREATE", Const, 0}, + {"SYS_TIMER_DELETE", Const, 0}, + {"SYS_TIMER_GETOVERRUN", Const, 0}, + {"SYS_TIMER_GETTIME", Const, 0}, + {"SYS_TIMER_SETTIME", Const, 0}, + {"SYS_TIMES", Const, 0}, + {"SYS_TKILL", Const, 0}, + {"SYS_TRUNCATE", Const, 0}, + {"SYS_TRUNCATE64", Const, 0}, + {"SYS_TUXCALL", Const, 0}, + {"SYS_UGETRLIMIT", Const, 0}, + {"SYS_ULIMIT", Const, 0}, + {"SYS_UMASK", Const, 0}, + {"SYS_UMASK_EXTENDED", Const, 0}, + {"SYS_UMOUNT", Const, 0}, + {"SYS_UMOUNT2", Const, 0}, + {"SYS_UNAME", Const, 0}, + {"SYS_UNDELETE", Const, 0}, + {"SYS_UNLINK", Const, 0}, + {"SYS_UNLINKAT", Const, 0}, + {"SYS_UNMOUNT", Const, 0}, + {"SYS_UNSHARE", Const, 0}, + {"SYS_USELIB", Const, 0}, + {"SYS_USTAT", Const, 0}, + {"SYS_UTIME", Const, 0}, + {"SYS_UTIMENSAT", Const, 0}, + {"SYS_UTIMES", Const, 0}, + {"SYS_UTRACE", Const, 0}, + {"SYS_UUIDGEN", Const, 0}, + {"SYS_VADVISE", Const, 1}, + {"SYS_VFORK", Const, 0}, + {"SYS_VHANGUP", Const, 0}, + {"SYS_VM86", Const, 0}, + {"SYS_VM86OLD", Const, 0}, + {"SYS_VMSPLICE", Const, 0}, + {"SYS_VM_PRESSURE_MONITOR", Const, 0}, + {"SYS_VSERVER", Const, 0}, + {"SYS_WAIT4", Const, 0}, + {"SYS_WAIT4_NOCANCEL", Const, 0}, + {"SYS_WAIT6", Const, 1}, + {"SYS_WAITEVENT", Const, 0}, + {"SYS_WAITID", Const, 0}, + {"SYS_WAITID_NOCANCEL", Const, 0}, + {"SYS_WAITPID", Const, 0}, + {"SYS_WATCHEVENT", Const, 0}, + {"SYS_WORKQ_KERNRETURN", Const, 0}, + {"SYS_WORKQ_OPEN", Const, 0}, + {"SYS_WRITE", Const, 0}, + {"SYS_WRITEV", Const, 0}, + {"SYS_WRITEV_NOCANCEL", Const, 0}, + {"SYS_WRITE_NOCANCEL", Const, 0}, + {"SYS_YIELD", Const, 0}, + {"SYS__LLSEEK", Const, 0}, + {"SYS__LWP_CONTINUE", Const, 1}, + {"SYS__LWP_CREATE", Const, 1}, + {"SYS__LWP_CTL", Const, 1}, + {"SYS__LWP_DETACH", Const, 1}, + {"SYS__LWP_EXIT", Const, 1}, + {"SYS__LWP_GETNAME", Const, 1}, + {"SYS__LWP_GETPRIVATE", Const, 1}, + {"SYS__LWP_KILL", Const, 1}, + {"SYS__LWP_PARK", Const, 1}, + {"SYS__LWP_SELF", Const, 1}, + {"SYS__LWP_SETNAME", Const, 1}, + {"SYS__LWP_SETPRIVATE", Const, 1}, + {"SYS__LWP_SUSPEND", Const, 1}, + {"SYS__LWP_UNPARK", Const, 1}, + {"SYS__LWP_UNPARK_ALL", Const, 1}, + {"SYS__LWP_WAIT", Const, 1}, + {"SYS__LWP_WAKEUP", Const, 1}, + {"SYS__NEWSELECT", Const, 0}, + {"SYS__PSET_BIND", Const, 1}, + {"SYS__SCHED_GETAFFINITY", Const, 1}, + {"SYS__SCHED_GETPARAM", Const, 1}, + {"SYS__SCHED_SETAFFINITY", Const, 1}, + {"SYS__SCHED_SETPARAM", Const, 1}, + {"SYS__SYSCTL", Const, 0}, + {"SYS__UMTX_LOCK", Const, 0}, + {"SYS__UMTX_OP", Const, 0}, + {"SYS__UMTX_UNLOCK", Const, 0}, + {"SYS___ACL_ACLCHECK_FD", Const, 0}, + {"SYS___ACL_ACLCHECK_FILE", Const, 0}, + {"SYS___ACL_ACLCHECK_LINK", Const, 0}, + {"SYS___ACL_DELETE_FD", Const, 0}, + {"SYS___ACL_DELETE_FILE", Const, 0}, + {"SYS___ACL_DELETE_LINK", Const, 0}, + {"SYS___ACL_GET_FD", Const, 0}, + {"SYS___ACL_GET_FILE", Const, 0}, + {"SYS___ACL_GET_LINK", Const, 0}, + {"SYS___ACL_SET_FD", Const, 0}, + {"SYS___ACL_SET_FILE", Const, 0}, + {"SYS___ACL_SET_LINK", Const, 0}, + {"SYS___CAP_RIGHTS_GET", Const, 14}, + {"SYS___CLONE", Const, 1}, + {"SYS___DISABLE_THREADSIGNAL", Const, 0}, + {"SYS___GETCWD", Const, 0}, + {"SYS___GETLOGIN", Const, 1}, + {"SYS___GET_TCB", Const, 1}, + {"SYS___MAC_EXECVE", Const, 0}, + {"SYS___MAC_GETFSSTAT", Const, 0}, + {"SYS___MAC_GET_FD", Const, 0}, + {"SYS___MAC_GET_FILE", Const, 0}, + {"SYS___MAC_GET_LCID", Const, 0}, + {"SYS___MAC_GET_LCTX", Const, 0}, + {"SYS___MAC_GET_LINK", Const, 0}, + {"SYS___MAC_GET_MOUNT", Const, 0}, + {"SYS___MAC_GET_PID", Const, 0}, + {"SYS___MAC_GET_PROC", Const, 0}, + {"SYS___MAC_MOUNT", Const, 0}, + {"SYS___MAC_SET_FD", Const, 0}, + {"SYS___MAC_SET_FILE", Const, 0}, + {"SYS___MAC_SET_LCTX", Const, 0}, + {"SYS___MAC_SET_LINK", Const, 0}, + {"SYS___MAC_SET_PROC", Const, 0}, + {"SYS___MAC_SYSCALL", Const, 0}, + {"SYS___OLD_SEMWAIT_SIGNAL", Const, 0}, + {"SYS___OLD_SEMWAIT_SIGNAL_NOCANCEL", Const, 0}, + {"SYS___POSIX_CHOWN", Const, 1}, + {"SYS___POSIX_FCHOWN", Const, 1}, + {"SYS___POSIX_LCHOWN", Const, 1}, + {"SYS___POSIX_RENAME", Const, 1}, + {"SYS___PTHREAD_CANCELED", Const, 0}, + {"SYS___PTHREAD_CHDIR", Const, 0}, + {"SYS___PTHREAD_FCHDIR", Const, 0}, + {"SYS___PTHREAD_KILL", Const, 0}, + {"SYS___PTHREAD_MARKCANCEL", Const, 0}, + {"SYS___PTHREAD_SIGMASK", Const, 0}, + {"SYS___QUOTACTL", Const, 1}, + {"SYS___SEMCTL", Const, 1}, + {"SYS___SEMWAIT_SIGNAL", Const, 0}, + {"SYS___SEMWAIT_SIGNAL_NOCANCEL", Const, 0}, + {"SYS___SETLOGIN", Const, 1}, + {"SYS___SETUGID", Const, 0}, + {"SYS___SET_TCB", Const, 1}, + {"SYS___SIGACTION_SIGTRAMP", Const, 1}, + {"SYS___SIGTIMEDWAIT", Const, 1}, + {"SYS___SIGWAIT", Const, 0}, + {"SYS___SIGWAIT_NOCANCEL", Const, 0}, + {"SYS___SYSCTL", Const, 0}, + {"SYS___TFORK", Const, 1}, + {"SYS___THREXIT", Const, 1}, + {"SYS___THRSIGDIVERT", Const, 1}, + {"SYS___THRSLEEP", Const, 1}, + {"SYS___THRWAKEUP", Const, 1}, + {"S_ARCH1", Const, 1}, + {"S_ARCH2", Const, 1}, + {"S_BLKSIZE", Const, 0}, + {"S_IEXEC", Const, 0}, + {"S_IFBLK", Const, 0}, + {"S_IFCHR", Const, 0}, + {"S_IFDIR", Const, 0}, + {"S_IFIFO", Const, 0}, + {"S_IFLNK", Const, 0}, + {"S_IFMT", Const, 0}, + {"S_IFREG", Const, 0}, + {"S_IFSOCK", Const, 0}, + {"S_IFWHT", Const, 0}, + {"S_IREAD", Const, 0}, + {"S_IRGRP", Const, 0}, + {"S_IROTH", Const, 0}, + {"S_IRUSR", Const, 0}, + {"S_IRWXG", Const, 0}, + {"S_IRWXO", Const, 0}, + {"S_IRWXU", Const, 0}, + {"S_ISGID", Const, 0}, + {"S_ISTXT", Const, 0}, + {"S_ISUID", Const, 0}, + {"S_ISVTX", Const, 0}, + {"S_IWGRP", Const, 0}, + {"S_IWOTH", Const, 0}, + {"S_IWRITE", Const, 0}, + {"S_IWUSR", Const, 0}, + {"S_IXGRP", Const, 0}, + {"S_IXOTH", Const, 0}, + {"S_IXUSR", Const, 0}, + {"S_LOGIN_SET", Const, 1}, + {"SecurityAttributes", Type, 0}, + {"SecurityAttributes.InheritHandle", Field, 0}, + {"SecurityAttributes.Length", Field, 0}, + {"SecurityAttributes.SecurityDescriptor", Field, 0}, + {"Seek", Func, 0}, + {"Select", Func, 0}, + {"Sendfile", Func, 0}, + {"Sendmsg", Func, 0}, + {"SendmsgN", Func, 3}, + {"Sendto", Func, 0}, + {"Servent", Type, 0}, + {"Servent.Aliases", Field, 0}, + {"Servent.Name", Field, 0}, + {"Servent.Port", Field, 0}, + {"Servent.Proto", Field, 0}, + {"SetBpf", Func, 0}, + {"SetBpfBuflen", Func, 0}, + {"SetBpfDatalink", Func, 0}, + {"SetBpfHeadercmpl", Func, 0}, + {"SetBpfImmediate", Func, 0}, + {"SetBpfInterface", Func, 0}, + {"SetBpfPromisc", Func, 0}, + {"SetBpfTimeout", Func, 0}, + {"SetCurrentDirectory", Func, 0}, + {"SetEndOfFile", Func, 0}, + {"SetEnvironmentVariable", Func, 0}, + {"SetFileAttributes", Func, 0}, + {"SetFileCompletionNotificationModes", Func, 2}, + {"SetFilePointer", Func, 0}, + {"SetFileTime", Func, 0}, + {"SetHandleInformation", Func, 0}, + {"SetKevent", Func, 0}, + {"SetLsfPromisc", Func, 0}, + {"SetNonblock", Func, 0}, + {"Setdomainname", Func, 0}, + {"Setegid", Func, 0}, + {"Setenv", Func, 0}, + {"Seteuid", Func, 0}, + {"Setfsgid", Func, 0}, + {"Setfsuid", Func, 0}, + {"Setgid", Func, 0}, + {"Setgroups", Func, 0}, + {"Sethostname", Func, 0}, + {"Setlogin", Func, 0}, + {"Setpgid", Func, 0}, + {"Setpriority", Func, 0}, + {"Setprivexec", Func, 0}, + {"Setregid", Func, 0}, + {"Setresgid", Func, 0}, + {"Setresuid", Func, 0}, + {"Setreuid", Func, 0}, + {"Setrlimit", Func, 0}, + {"Setsid", Func, 0}, + {"Setsockopt", Func, 0}, + {"SetsockoptByte", Func, 0}, + {"SetsockoptICMPv6Filter", Func, 2}, + {"SetsockoptIPMreq", Func, 0}, + {"SetsockoptIPMreqn", Func, 0}, + {"SetsockoptIPv6Mreq", Func, 0}, + {"SetsockoptInet4Addr", Func, 0}, + {"SetsockoptInt", Func, 0}, + {"SetsockoptLinger", Func, 0}, + {"SetsockoptString", Func, 0}, + {"SetsockoptTimeval", Func, 0}, + {"Settimeofday", Func, 0}, + {"Setuid", Func, 0}, + {"Setxattr", Func, 1}, + {"Shutdown", Func, 0}, + {"SidTypeAlias", Const, 0}, + {"SidTypeComputer", Const, 0}, + {"SidTypeDeletedAccount", Const, 0}, + {"SidTypeDomain", Const, 0}, + {"SidTypeGroup", Const, 0}, + {"SidTypeInvalid", Const, 0}, + {"SidTypeLabel", Const, 0}, + {"SidTypeUnknown", Const, 0}, + {"SidTypeUser", Const, 0}, + {"SidTypeWellKnownGroup", Const, 0}, + {"Signal", Type, 0}, + {"SizeofBpfHdr", Const, 0}, + {"SizeofBpfInsn", Const, 0}, + {"SizeofBpfProgram", Const, 0}, + {"SizeofBpfStat", Const, 0}, + {"SizeofBpfVersion", Const, 0}, + {"SizeofBpfZbuf", Const, 0}, + {"SizeofBpfZbufHeader", Const, 0}, + {"SizeofCmsghdr", Const, 0}, + {"SizeofICMPv6Filter", Const, 2}, + {"SizeofIPMreq", Const, 0}, + {"SizeofIPMreqn", Const, 0}, + {"SizeofIPv6MTUInfo", Const, 2}, + {"SizeofIPv6Mreq", Const, 0}, + {"SizeofIfAddrmsg", Const, 0}, + {"SizeofIfAnnounceMsghdr", Const, 1}, + {"SizeofIfData", Const, 0}, + {"SizeofIfInfomsg", Const, 0}, + {"SizeofIfMsghdr", Const, 0}, + {"SizeofIfaMsghdr", Const, 0}, + {"SizeofIfmaMsghdr", Const, 0}, + {"SizeofIfmaMsghdr2", Const, 0}, + {"SizeofInet4Pktinfo", Const, 0}, + {"SizeofInet6Pktinfo", Const, 0}, + {"SizeofInotifyEvent", Const, 0}, + {"SizeofLinger", Const, 0}, + {"SizeofMsghdr", Const, 0}, + {"SizeofNlAttr", Const, 0}, + {"SizeofNlMsgerr", Const, 0}, + {"SizeofNlMsghdr", Const, 0}, + {"SizeofRtAttr", Const, 0}, + {"SizeofRtGenmsg", Const, 0}, + {"SizeofRtMetrics", Const, 0}, + {"SizeofRtMsg", Const, 0}, + {"SizeofRtMsghdr", Const, 0}, + {"SizeofRtNexthop", Const, 0}, + {"SizeofSockFilter", Const, 0}, + {"SizeofSockFprog", Const, 0}, + {"SizeofSockaddrAny", Const, 0}, + {"SizeofSockaddrDatalink", Const, 0}, + {"SizeofSockaddrInet4", Const, 0}, + {"SizeofSockaddrInet6", Const, 0}, + {"SizeofSockaddrLinklayer", Const, 0}, + {"SizeofSockaddrNetlink", Const, 0}, + {"SizeofSockaddrUnix", Const, 0}, + {"SizeofTCPInfo", Const, 1}, + {"SizeofUcred", Const, 0}, + {"SlicePtrFromStrings", Func, 1}, + {"SockFilter", Type, 0}, + {"SockFilter.Code", Field, 0}, + {"SockFilter.Jf", Field, 0}, + {"SockFilter.Jt", Field, 0}, + {"SockFilter.K", Field, 0}, + {"SockFprog", Type, 0}, + {"SockFprog.Filter", Field, 0}, + {"SockFprog.Len", Field, 0}, + {"SockFprog.Pad_cgo_0", Field, 0}, + {"Sockaddr", Type, 0}, + {"SockaddrDatalink", Type, 0}, + {"SockaddrDatalink.Alen", Field, 0}, + {"SockaddrDatalink.Data", Field, 0}, + {"SockaddrDatalink.Family", Field, 0}, + {"SockaddrDatalink.Index", Field, 0}, + {"SockaddrDatalink.Len", Field, 0}, + {"SockaddrDatalink.Nlen", Field, 0}, + {"SockaddrDatalink.Slen", Field, 0}, + {"SockaddrDatalink.Type", Field, 0}, + {"SockaddrGen", Type, 0}, + {"SockaddrInet4", Type, 0}, + {"SockaddrInet4.Addr", Field, 0}, + {"SockaddrInet4.Port", Field, 0}, + {"SockaddrInet6", Type, 0}, + {"SockaddrInet6.Addr", Field, 0}, + {"SockaddrInet6.Port", Field, 0}, + {"SockaddrInet6.ZoneId", Field, 0}, + {"SockaddrLinklayer", Type, 0}, + {"SockaddrLinklayer.Addr", Field, 0}, + {"SockaddrLinklayer.Halen", Field, 0}, + {"SockaddrLinklayer.Hatype", Field, 0}, + {"SockaddrLinklayer.Ifindex", Field, 0}, + {"SockaddrLinklayer.Pkttype", Field, 0}, + {"SockaddrLinklayer.Protocol", Field, 0}, + {"SockaddrNetlink", Type, 0}, + {"SockaddrNetlink.Family", Field, 0}, + {"SockaddrNetlink.Groups", Field, 0}, + {"SockaddrNetlink.Pad", Field, 0}, + {"SockaddrNetlink.Pid", Field, 0}, + {"SockaddrUnix", Type, 0}, + {"SockaddrUnix.Name", Field, 0}, + {"Socket", Func, 0}, + {"SocketControlMessage", Type, 0}, + {"SocketControlMessage.Data", Field, 0}, + {"SocketControlMessage.Header", Field, 0}, + {"SocketDisableIPv6", Var, 0}, + {"Socketpair", Func, 0}, + {"Splice", Func, 0}, + {"StartProcess", Func, 0}, + {"StartupInfo", Type, 0}, + {"StartupInfo.Cb", Field, 0}, + {"StartupInfo.Desktop", Field, 0}, + {"StartupInfo.FillAttribute", Field, 0}, + {"StartupInfo.Flags", Field, 0}, + {"StartupInfo.ShowWindow", Field, 0}, + {"StartupInfo.StdErr", Field, 0}, + {"StartupInfo.StdInput", Field, 0}, + {"StartupInfo.StdOutput", Field, 0}, + {"StartupInfo.Title", Field, 0}, + {"StartupInfo.X", Field, 0}, + {"StartupInfo.XCountChars", Field, 0}, + {"StartupInfo.XSize", Field, 0}, + {"StartupInfo.Y", Field, 0}, + {"StartupInfo.YCountChars", Field, 0}, + {"StartupInfo.YSize", Field, 0}, + {"Stat", Func, 0}, + {"Stat_t", Type, 0}, + {"Stat_t.Atim", Field, 0}, + {"Stat_t.Atim_ext", Field, 12}, + {"Stat_t.Atimespec", Field, 0}, + {"Stat_t.Birthtimespec", Field, 0}, + {"Stat_t.Blksize", Field, 0}, + {"Stat_t.Blocks", Field, 0}, + {"Stat_t.Btim_ext", Field, 12}, + {"Stat_t.Ctim", Field, 0}, + {"Stat_t.Ctim_ext", Field, 12}, + {"Stat_t.Ctimespec", Field, 0}, + {"Stat_t.Dev", Field, 0}, + {"Stat_t.Flags", Field, 0}, + {"Stat_t.Gen", Field, 0}, + {"Stat_t.Gid", Field, 0}, + {"Stat_t.Ino", Field, 0}, + {"Stat_t.Lspare", Field, 0}, + {"Stat_t.Lspare0", Field, 2}, + {"Stat_t.Lspare1", Field, 2}, + {"Stat_t.Mode", Field, 0}, + {"Stat_t.Mtim", Field, 0}, + {"Stat_t.Mtim_ext", Field, 12}, + {"Stat_t.Mtimespec", Field, 0}, + {"Stat_t.Nlink", Field, 0}, + {"Stat_t.Pad_cgo_0", Field, 0}, + {"Stat_t.Pad_cgo_1", Field, 0}, + {"Stat_t.Pad_cgo_2", Field, 0}, + {"Stat_t.Padding0", Field, 12}, + {"Stat_t.Padding1", Field, 12}, + {"Stat_t.Qspare", Field, 0}, + {"Stat_t.Rdev", Field, 0}, + {"Stat_t.Size", Field, 0}, + {"Stat_t.Spare", Field, 2}, + {"Stat_t.Uid", Field, 0}, + {"Stat_t.X__pad0", Field, 0}, + {"Stat_t.X__pad1", Field, 0}, + {"Stat_t.X__pad2", Field, 0}, + {"Stat_t.X__st_birthtim", Field, 2}, + {"Stat_t.X__st_ino", Field, 0}, + {"Stat_t.X__unused", Field, 0}, + {"Statfs", Func, 0}, + {"Statfs_t", Type, 0}, + {"Statfs_t.Asyncreads", Field, 0}, + {"Statfs_t.Asyncwrites", Field, 0}, + {"Statfs_t.Bavail", Field, 0}, + {"Statfs_t.Bfree", Field, 0}, + {"Statfs_t.Blocks", Field, 0}, + {"Statfs_t.Bsize", Field, 0}, + {"Statfs_t.Charspare", Field, 0}, + {"Statfs_t.F_asyncreads", Field, 2}, + {"Statfs_t.F_asyncwrites", Field, 2}, + {"Statfs_t.F_bavail", Field, 2}, + {"Statfs_t.F_bfree", Field, 2}, + {"Statfs_t.F_blocks", Field, 2}, + {"Statfs_t.F_bsize", Field, 2}, + {"Statfs_t.F_ctime", Field, 2}, + {"Statfs_t.F_favail", Field, 2}, + {"Statfs_t.F_ffree", Field, 2}, + {"Statfs_t.F_files", Field, 2}, + {"Statfs_t.F_flags", Field, 2}, + {"Statfs_t.F_fsid", Field, 2}, + {"Statfs_t.F_fstypename", Field, 2}, + {"Statfs_t.F_iosize", Field, 2}, + {"Statfs_t.F_mntfromname", Field, 2}, + {"Statfs_t.F_mntfromspec", Field, 3}, + {"Statfs_t.F_mntonname", Field, 2}, + {"Statfs_t.F_namemax", Field, 2}, + {"Statfs_t.F_owner", Field, 2}, + {"Statfs_t.F_spare", Field, 2}, + {"Statfs_t.F_syncreads", Field, 2}, + {"Statfs_t.F_syncwrites", Field, 2}, + {"Statfs_t.Ffree", Field, 0}, + {"Statfs_t.Files", Field, 0}, + {"Statfs_t.Flags", Field, 0}, + {"Statfs_t.Frsize", Field, 0}, + {"Statfs_t.Fsid", Field, 0}, + {"Statfs_t.Fssubtype", Field, 0}, + {"Statfs_t.Fstypename", Field, 0}, + {"Statfs_t.Iosize", Field, 0}, + {"Statfs_t.Mntfromname", Field, 0}, + {"Statfs_t.Mntonname", Field, 0}, + {"Statfs_t.Mount_info", Field, 2}, + {"Statfs_t.Namelen", Field, 0}, + {"Statfs_t.Namemax", Field, 0}, + {"Statfs_t.Owner", Field, 0}, + {"Statfs_t.Pad_cgo_0", Field, 0}, + {"Statfs_t.Pad_cgo_1", Field, 2}, + {"Statfs_t.Reserved", Field, 0}, + {"Statfs_t.Spare", Field, 0}, + {"Statfs_t.Syncreads", Field, 0}, + {"Statfs_t.Syncwrites", Field, 0}, + {"Statfs_t.Type", Field, 0}, + {"Statfs_t.Version", Field, 0}, + {"Stderr", Var, 0}, + {"Stdin", Var, 0}, + {"Stdout", Var, 0}, + {"StringBytePtr", Func, 0}, + {"StringByteSlice", Func, 0}, + {"StringSlicePtr", Func, 0}, + {"StringToSid", Func, 0}, + {"StringToUTF16", Func, 0}, + {"StringToUTF16Ptr", Func, 0}, + {"Symlink", Func, 0}, + {"Sync", Func, 0}, + {"SyncFileRange", Func, 0}, + {"SysProcAttr", Type, 0}, + {"SysProcAttr.AdditionalInheritedHandles", Field, 17}, + {"SysProcAttr.AmbientCaps", Field, 9}, + {"SysProcAttr.CgroupFD", Field, 20}, + {"SysProcAttr.Chroot", Field, 0}, + {"SysProcAttr.Cloneflags", Field, 2}, + {"SysProcAttr.CmdLine", Field, 0}, + {"SysProcAttr.CreationFlags", Field, 1}, + {"SysProcAttr.Credential", Field, 0}, + {"SysProcAttr.Ctty", Field, 1}, + {"SysProcAttr.Foreground", Field, 5}, + {"SysProcAttr.GidMappings", Field, 4}, + {"SysProcAttr.GidMappingsEnableSetgroups", Field, 5}, + {"SysProcAttr.HideWindow", Field, 0}, + {"SysProcAttr.Jail", Field, 21}, + {"SysProcAttr.NoInheritHandles", Field, 16}, + {"SysProcAttr.Noctty", Field, 0}, + {"SysProcAttr.ParentProcess", Field, 17}, + {"SysProcAttr.Pdeathsig", Field, 0}, + {"SysProcAttr.Pgid", Field, 5}, + {"SysProcAttr.PidFD", Field, 22}, + {"SysProcAttr.ProcessAttributes", Field, 13}, + {"SysProcAttr.Ptrace", Field, 0}, + {"SysProcAttr.Setctty", Field, 0}, + {"SysProcAttr.Setpgid", Field, 0}, + {"SysProcAttr.Setsid", Field, 0}, + {"SysProcAttr.ThreadAttributes", Field, 13}, + {"SysProcAttr.Token", Field, 10}, + {"SysProcAttr.UidMappings", Field, 4}, + {"SysProcAttr.Unshareflags", Field, 7}, + {"SysProcAttr.UseCgroupFD", Field, 20}, + {"SysProcIDMap", Type, 4}, + {"SysProcIDMap.ContainerID", Field, 4}, + {"SysProcIDMap.HostID", Field, 4}, + {"SysProcIDMap.Size", Field, 4}, + {"Syscall", Func, 0}, + {"Syscall12", Func, 0}, + {"Syscall15", Func, 0}, + {"Syscall18", Func, 12}, + {"Syscall6", Func, 0}, + {"Syscall9", Func, 0}, + {"SyscallN", Func, 18}, + {"Sysctl", Func, 0}, + {"SysctlUint32", Func, 0}, + {"Sysctlnode", Type, 2}, + {"Sysctlnode.Flags", Field, 2}, + {"Sysctlnode.Name", Field, 2}, + {"Sysctlnode.Num", Field, 2}, + {"Sysctlnode.Un", Field, 2}, + {"Sysctlnode.Ver", Field, 2}, + {"Sysctlnode.X__rsvd", Field, 2}, + {"Sysctlnode.X_sysctl_desc", Field, 2}, + {"Sysctlnode.X_sysctl_func", Field, 2}, + {"Sysctlnode.X_sysctl_parent", Field, 2}, + {"Sysctlnode.X_sysctl_size", Field, 2}, + {"Sysinfo", Func, 0}, + {"Sysinfo_t", Type, 0}, + {"Sysinfo_t.Bufferram", Field, 0}, + {"Sysinfo_t.Freehigh", Field, 0}, + {"Sysinfo_t.Freeram", Field, 0}, + {"Sysinfo_t.Freeswap", Field, 0}, + {"Sysinfo_t.Loads", Field, 0}, + {"Sysinfo_t.Pad", Field, 0}, + {"Sysinfo_t.Pad_cgo_0", Field, 0}, + {"Sysinfo_t.Pad_cgo_1", Field, 0}, + {"Sysinfo_t.Procs", Field, 0}, + {"Sysinfo_t.Sharedram", Field, 0}, + {"Sysinfo_t.Totalhigh", Field, 0}, + {"Sysinfo_t.Totalram", Field, 0}, + {"Sysinfo_t.Totalswap", Field, 0}, + {"Sysinfo_t.Unit", Field, 0}, + {"Sysinfo_t.Uptime", Field, 0}, + {"Sysinfo_t.X_f", Field, 0}, + {"Systemtime", Type, 0}, + {"Systemtime.Day", Field, 0}, + {"Systemtime.DayOfWeek", Field, 0}, + {"Systemtime.Hour", Field, 0}, + {"Systemtime.Milliseconds", Field, 0}, + {"Systemtime.Minute", Field, 0}, + {"Systemtime.Month", Field, 0}, + {"Systemtime.Second", Field, 0}, + {"Systemtime.Year", Field, 0}, + {"TCGETS", Const, 0}, + {"TCIFLUSH", Const, 1}, + {"TCIOFLUSH", Const, 1}, + {"TCOFLUSH", Const, 1}, + {"TCPInfo", Type, 1}, + {"TCPInfo.Advmss", Field, 1}, + {"TCPInfo.Ato", Field, 1}, + {"TCPInfo.Backoff", Field, 1}, + {"TCPInfo.Ca_state", Field, 1}, + {"TCPInfo.Fackets", Field, 1}, + {"TCPInfo.Last_ack_recv", Field, 1}, + {"TCPInfo.Last_ack_sent", Field, 1}, + {"TCPInfo.Last_data_recv", Field, 1}, + {"TCPInfo.Last_data_sent", Field, 1}, + {"TCPInfo.Lost", Field, 1}, + {"TCPInfo.Options", Field, 1}, + {"TCPInfo.Pad_cgo_0", Field, 1}, + {"TCPInfo.Pmtu", Field, 1}, + {"TCPInfo.Probes", Field, 1}, + {"TCPInfo.Rcv_mss", Field, 1}, + {"TCPInfo.Rcv_rtt", Field, 1}, + {"TCPInfo.Rcv_space", Field, 1}, + {"TCPInfo.Rcv_ssthresh", Field, 1}, + {"TCPInfo.Reordering", Field, 1}, + {"TCPInfo.Retrans", Field, 1}, + {"TCPInfo.Retransmits", Field, 1}, + {"TCPInfo.Rto", Field, 1}, + {"TCPInfo.Rtt", Field, 1}, + {"TCPInfo.Rttvar", Field, 1}, + {"TCPInfo.Sacked", Field, 1}, + {"TCPInfo.Snd_cwnd", Field, 1}, + {"TCPInfo.Snd_mss", Field, 1}, + {"TCPInfo.Snd_ssthresh", Field, 1}, + {"TCPInfo.State", Field, 1}, + {"TCPInfo.Total_retrans", Field, 1}, + {"TCPInfo.Unacked", Field, 1}, + {"TCPKeepalive", Type, 3}, + {"TCPKeepalive.Interval", Field, 3}, + {"TCPKeepalive.OnOff", Field, 3}, + {"TCPKeepalive.Time", Field, 3}, + {"TCP_CA_NAME_MAX", Const, 0}, + {"TCP_CONGCTL", Const, 1}, + {"TCP_CONGESTION", Const, 0}, + {"TCP_CONNECTIONTIMEOUT", Const, 0}, + {"TCP_CORK", Const, 0}, + {"TCP_DEFER_ACCEPT", Const, 0}, + {"TCP_ENABLE_ECN", Const, 16}, + {"TCP_INFO", Const, 0}, + {"TCP_KEEPALIVE", Const, 0}, + {"TCP_KEEPCNT", Const, 0}, + {"TCP_KEEPIDLE", Const, 0}, + {"TCP_KEEPINIT", Const, 1}, + {"TCP_KEEPINTVL", Const, 0}, + {"TCP_LINGER2", Const, 0}, + {"TCP_MAXBURST", Const, 0}, + {"TCP_MAXHLEN", Const, 0}, + {"TCP_MAXOLEN", Const, 0}, + {"TCP_MAXSEG", Const, 0}, + {"TCP_MAXWIN", Const, 0}, + {"TCP_MAX_SACK", Const, 0}, + {"TCP_MAX_WINSHIFT", Const, 0}, + {"TCP_MD5SIG", Const, 0}, + {"TCP_MD5SIG_MAXKEYLEN", Const, 0}, + {"TCP_MINMSS", Const, 0}, + {"TCP_MINMSSOVERLOAD", Const, 0}, + {"TCP_MSS", Const, 0}, + {"TCP_NODELAY", Const, 0}, + {"TCP_NOOPT", Const, 0}, + {"TCP_NOPUSH", Const, 0}, + {"TCP_NOTSENT_LOWAT", Const, 16}, + {"TCP_NSTATES", Const, 1}, + {"TCP_QUICKACK", Const, 0}, + {"TCP_RXT_CONNDROPTIME", Const, 0}, + {"TCP_RXT_FINDROP", Const, 0}, + {"TCP_SACK_ENABLE", Const, 1}, + {"TCP_SENDMOREACKS", Const, 16}, + {"TCP_SYNCNT", Const, 0}, + {"TCP_VENDOR", Const, 3}, + {"TCP_WINDOW_CLAMP", Const, 0}, + {"TCSAFLUSH", Const, 1}, + {"TCSETS", Const, 0}, + {"TF_DISCONNECT", Const, 0}, + {"TF_REUSE_SOCKET", Const, 0}, + {"TF_USE_DEFAULT_WORKER", Const, 0}, + {"TF_USE_KERNEL_APC", Const, 0}, + {"TF_USE_SYSTEM_THREAD", Const, 0}, + {"TF_WRITE_BEHIND", Const, 0}, + {"TH32CS_INHERIT", Const, 4}, + {"TH32CS_SNAPALL", Const, 4}, + {"TH32CS_SNAPHEAPLIST", Const, 4}, + {"TH32CS_SNAPMODULE", Const, 4}, + {"TH32CS_SNAPMODULE32", Const, 4}, + {"TH32CS_SNAPPROCESS", Const, 4}, + {"TH32CS_SNAPTHREAD", Const, 4}, + {"TIME_ZONE_ID_DAYLIGHT", Const, 0}, + {"TIME_ZONE_ID_STANDARD", Const, 0}, + {"TIME_ZONE_ID_UNKNOWN", Const, 0}, + {"TIOCCBRK", Const, 0}, + {"TIOCCDTR", Const, 0}, + {"TIOCCONS", Const, 0}, + {"TIOCDCDTIMESTAMP", Const, 0}, + {"TIOCDRAIN", Const, 0}, + {"TIOCDSIMICROCODE", Const, 0}, + {"TIOCEXCL", Const, 0}, + {"TIOCEXT", Const, 0}, + {"TIOCFLAG_CDTRCTS", Const, 1}, + {"TIOCFLAG_CLOCAL", Const, 1}, + {"TIOCFLAG_CRTSCTS", Const, 1}, + {"TIOCFLAG_MDMBUF", Const, 1}, + {"TIOCFLAG_PPS", Const, 1}, + {"TIOCFLAG_SOFTCAR", Const, 1}, + {"TIOCFLUSH", Const, 0}, + {"TIOCGDEV", Const, 0}, + {"TIOCGDRAINWAIT", Const, 0}, + {"TIOCGETA", Const, 0}, + {"TIOCGETD", Const, 0}, + {"TIOCGFLAGS", Const, 1}, + {"TIOCGICOUNT", Const, 0}, + {"TIOCGLCKTRMIOS", Const, 0}, + {"TIOCGLINED", Const, 1}, + {"TIOCGPGRP", Const, 0}, + {"TIOCGPTN", Const, 0}, + {"TIOCGQSIZE", Const, 1}, + {"TIOCGRANTPT", Const, 1}, + {"TIOCGRS485", Const, 0}, + {"TIOCGSERIAL", Const, 0}, + {"TIOCGSID", Const, 0}, + {"TIOCGSIZE", Const, 1}, + {"TIOCGSOFTCAR", Const, 0}, + {"TIOCGTSTAMP", Const, 1}, + {"TIOCGWINSZ", Const, 0}, + {"TIOCINQ", Const, 0}, + {"TIOCIXOFF", Const, 0}, + {"TIOCIXON", Const, 0}, + {"TIOCLINUX", Const, 0}, + {"TIOCMBIC", Const, 0}, + {"TIOCMBIS", Const, 0}, + {"TIOCMGDTRWAIT", Const, 0}, + {"TIOCMGET", Const, 0}, + {"TIOCMIWAIT", Const, 0}, + {"TIOCMODG", Const, 0}, + {"TIOCMODS", Const, 0}, + {"TIOCMSDTRWAIT", Const, 0}, + {"TIOCMSET", Const, 0}, + {"TIOCM_CAR", Const, 0}, + {"TIOCM_CD", Const, 0}, + {"TIOCM_CTS", Const, 0}, + {"TIOCM_DCD", Const, 0}, + {"TIOCM_DSR", Const, 0}, + {"TIOCM_DTR", Const, 0}, + {"TIOCM_LE", Const, 0}, + {"TIOCM_RI", Const, 0}, + {"TIOCM_RNG", Const, 0}, + {"TIOCM_RTS", Const, 0}, + {"TIOCM_SR", Const, 0}, + {"TIOCM_ST", Const, 0}, + {"TIOCNOTTY", Const, 0}, + {"TIOCNXCL", Const, 0}, + {"TIOCOUTQ", Const, 0}, + {"TIOCPKT", Const, 0}, + {"TIOCPKT_DATA", Const, 0}, + {"TIOCPKT_DOSTOP", Const, 0}, + {"TIOCPKT_FLUSHREAD", Const, 0}, + {"TIOCPKT_FLUSHWRITE", Const, 0}, + {"TIOCPKT_IOCTL", Const, 0}, + {"TIOCPKT_NOSTOP", Const, 0}, + {"TIOCPKT_START", Const, 0}, + {"TIOCPKT_STOP", Const, 0}, + {"TIOCPTMASTER", Const, 0}, + {"TIOCPTMGET", Const, 1}, + {"TIOCPTSNAME", Const, 1}, + {"TIOCPTYGNAME", Const, 0}, + {"TIOCPTYGRANT", Const, 0}, + {"TIOCPTYUNLK", Const, 0}, + {"TIOCRCVFRAME", Const, 1}, + {"TIOCREMOTE", Const, 0}, + {"TIOCSBRK", Const, 0}, + {"TIOCSCONS", Const, 0}, + {"TIOCSCTTY", Const, 0}, + {"TIOCSDRAINWAIT", Const, 0}, + {"TIOCSDTR", Const, 0}, + {"TIOCSERCONFIG", Const, 0}, + {"TIOCSERGETLSR", Const, 0}, + {"TIOCSERGETMULTI", Const, 0}, + {"TIOCSERGSTRUCT", Const, 0}, + {"TIOCSERGWILD", Const, 0}, + {"TIOCSERSETMULTI", Const, 0}, + {"TIOCSERSWILD", Const, 0}, + {"TIOCSER_TEMT", Const, 0}, + {"TIOCSETA", Const, 0}, + {"TIOCSETAF", Const, 0}, + {"TIOCSETAW", Const, 0}, + {"TIOCSETD", Const, 0}, + {"TIOCSFLAGS", Const, 1}, + {"TIOCSIG", Const, 0}, + {"TIOCSLCKTRMIOS", Const, 0}, + {"TIOCSLINED", Const, 1}, + {"TIOCSPGRP", Const, 0}, + {"TIOCSPTLCK", Const, 0}, + {"TIOCSQSIZE", Const, 1}, + {"TIOCSRS485", Const, 0}, + {"TIOCSSERIAL", Const, 0}, + {"TIOCSSIZE", Const, 1}, + {"TIOCSSOFTCAR", Const, 0}, + {"TIOCSTART", Const, 0}, + {"TIOCSTAT", Const, 0}, + {"TIOCSTI", Const, 0}, + {"TIOCSTOP", Const, 0}, + {"TIOCSTSTAMP", Const, 1}, + {"TIOCSWINSZ", Const, 0}, + {"TIOCTIMESTAMP", Const, 0}, + {"TIOCUCNTL", Const, 0}, + {"TIOCVHANGUP", Const, 0}, + {"TIOCXMTFRAME", Const, 1}, + {"TOKEN_ADJUST_DEFAULT", Const, 0}, + {"TOKEN_ADJUST_GROUPS", Const, 0}, + {"TOKEN_ADJUST_PRIVILEGES", Const, 0}, + {"TOKEN_ADJUST_SESSIONID", Const, 11}, + {"TOKEN_ALL_ACCESS", Const, 0}, + {"TOKEN_ASSIGN_PRIMARY", Const, 0}, + {"TOKEN_DUPLICATE", Const, 0}, + {"TOKEN_EXECUTE", Const, 0}, + {"TOKEN_IMPERSONATE", Const, 0}, + {"TOKEN_QUERY", Const, 0}, + {"TOKEN_QUERY_SOURCE", Const, 0}, + {"TOKEN_READ", Const, 0}, + {"TOKEN_WRITE", Const, 0}, + {"TOSTOP", Const, 0}, + {"TRUNCATE_EXISTING", Const, 0}, + {"TUNATTACHFILTER", Const, 0}, + {"TUNDETACHFILTER", Const, 0}, + {"TUNGETFEATURES", Const, 0}, + {"TUNGETIFF", Const, 0}, + {"TUNGETSNDBUF", Const, 0}, + {"TUNGETVNETHDRSZ", Const, 0}, + {"TUNSETDEBUG", Const, 0}, + {"TUNSETGROUP", Const, 0}, + {"TUNSETIFF", Const, 0}, + {"TUNSETLINK", Const, 0}, + {"TUNSETNOCSUM", Const, 0}, + {"TUNSETOFFLOAD", Const, 0}, + {"TUNSETOWNER", Const, 0}, + {"TUNSETPERSIST", Const, 0}, + {"TUNSETSNDBUF", Const, 0}, + {"TUNSETTXFILTER", Const, 0}, + {"TUNSETVNETHDRSZ", Const, 0}, + {"Tee", Func, 0}, + {"TerminateProcess", Func, 0}, + {"Termios", Type, 0}, + {"Termios.Cc", Field, 0}, + {"Termios.Cflag", Field, 0}, + {"Termios.Iflag", Field, 0}, + {"Termios.Ispeed", Field, 0}, + {"Termios.Lflag", Field, 0}, + {"Termios.Line", Field, 0}, + {"Termios.Oflag", Field, 0}, + {"Termios.Ospeed", Field, 0}, + {"Termios.Pad_cgo_0", Field, 0}, + {"Tgkill", Func, 0}, + {"Time", Func, 0}, + {"Time_t", Type, 0}, + {"Times", Func, 0}, + {"Timespec", Type, 0}, + {"Timespec.Nsec", Field, 0}, + {"Timespec.Pad_cgo_0", Field, 2}, + {"Timespec.Sec", Field, 0}, + {"TimespecToNsec", Func, 0}, + {"Timeval", Type, 0}, + {"Timeval.Pad_cgo_0", Field, 0}, + {"Timeval.Sec", Field, 0}, + {"Timeval.Usec", Field, 0}, + {"Timeval32", Type, 0}, + {"Timeval32.Sec", Field, 0}, + {"Timeval32.Usec", Field, 0}, + {"TimevalToNsec", Func, 0}, + {"Timex", Type, 0}, + {"Timex.Calcnt", Field, 0}, + {"Timex.Constant", Field, 0}, + {"Timex.Errcnt", Field, 0}, + {"Timex.Esterror", Field, 0}, + {"Timex.Freq", Field, 0}, + {"Timex.Jitcnt", Field, 0}, + {"Timex.Jitter", Field, 0}, + {"Timex.Maxerror", Field, 0}, + {"Timex.Modes", Field, 0}, + {"Timex.Offset", Field, 0}, + {"Timex.Pad_cgo_0", Field, 0}, + {"Timex.Pad_cgo_1", Field, 0}, + {"Timex.Pad_cgo_2", Field, 0}, + {"Timex.Pad_cgo_3", Field, 0}, + {"Timex.Ppsfreq", Field, 0}, + {"Timex.Precision", Field, 0}, + {"Timex.Shift", Field, 0}, + {"Timex.Stabil", Field, 0}, + {"Timex.Status", Field, 0}, + {"Timex.Stbcnt", Field, 0}, + {"Timex.Tai", Field, 0}, + {"Timex.Tick", Field, 0}, + {"Timex.Time", Field, 0}, + {"Timex.Tolerance", Field, 0}, + {"Timezoneinformation", Type, 0}, + {"Timezoneinformation.Bias", Field, 0}, + {"Timezoneinformation.DaylightBias", Field, 0}, + {"Timezoneinformation.DaylightDate", Field, 0}, + {"Timezoneinformation.DaylightName", Field, 0}, + {"Timezoneinformation.StandardBias", Field, 0}, + {"Timezoneinformation.StandardDate", Field, 0}, + {"Timezoneinformation.StandardName", Field, 0}, + {"Tms", Type, 0}, + {"Tms.Cstime", Field, 0}, + {"Tms.Cutime", Field, 0}, + {"Tms.Stime", Field, 0}, + {"Tms.Utime", Field, 0}, + {"Token", Type, 0}, + {"TokenAccessInformation", Const, 0}, + {"TokenAuditPolicy", Const, 0}, + {"TokenDefaultDacl", Const, 0}, + {"TokenElevation", Const, 0}, + {"TokenElevationType", Const, 0}, + {"TokenGroups", Const, 0}, + {"TokenGroupsAndPrivileges", Const, 0}, + {"TokenHasRestrictions", Const, 0}, + {"TokenImpersonationLevel", Const, 0}, + {"TokenIntegrityLevel", Const, 0}, + {"TokenLinkedToken", Const, 0}, + {"TokenLogonSid", Const, 0}, + {"TokenMandatoryPolicy", Const, 0}, + {"TokenOrigin", Const, 0}, + {"TokenOwner", Const, 0}, + {"TokenPrimaryGroup", Const, 0}, + {"TokenPrivileges", Const, 0}, + {"TokenRestrictedSids", Const, 0}, + {"TokenSandBoxInert", Const, 0}, + {"TokenSessionId", Const, 0}, + {"TokenSessionReference", Const, 0}, + {"TokenSource", Const, 0}, + {"TokenStatistics", Const, 0}, + {"TokenType", Const, 0}, + {"TokenUIAccess", Const, 0}, + {"TokenUser", Const, 0}, + {"TokenVirtualizationAllowed", Const, 0}, + {"TokenVirtualizationEnabled", Const, 0}, + {"Tokenprimarygroup", Type, 0}, + {"Tokenprimarygroup.PrimaryGroup", Field, 0}, + {"Tokenuser", Type, 0}, + {"Tokenuser.User", Field, 0}, + {"TranslateAccountName", Func, 0}, + {"TranslateName", Func, 0}, + {"TransmitFile", Func, 0}, + {"TransmitFileBuffers", Type, 0}, + {"TransmitFileBuffers.Head", Field, 0}, + {"TransmitFileBuffers.HeadLength", Field, 0}, + {"TransmitFileBuffers.Tail", Field, 0}, + {"TransmitFileBuffers.TailLength", Field, 0}, + {"Truncate", Func, 0}, + {"UNIX_PATH_MAX", Const, 12}, + {"USAGE_MATCH_TYPE_AND", Const, 0}, + {"USAGE_MATCH_TYPE_OR", Const, 0}, + {"UTF16FromString", Func, 1}, + {"UTF16PtrFromString", Func, 1}, + {"UTF16ToString", Func, 0}, + {"Ucred", Type, 0}, + {"Ucred.Gid", Field, 0}, + {"Ucred.Pid", Field, 0}, + {"Ucred.Uid", Field, 0}, + {"Umask", Func, 0}, + {"Uname", Func, 0}, + {"Undelete", Func, 0}, + {"UnixCredentials", Func, 0}, + {"UnixRights", Func, 0}, + {"Unlink", Func, 0}, + {"Unlinkat", Func, 0}, + {"UnmapViewOfFile", Func, 0}, + {"Unmount", Func, 0}, + {"Unsetenv", Func, 4}, + {"Unshare", Func, 0}, + {"UserInfo10", Type, 0}, + {"UserInfo10.Comment", Field, 0}, + {"UserInfo10.FullName", Field, 0}, + {"UserInfo10.Name", Field, 0}, + {"UserInfo10.UsrComment", Field, 0}, + {"Ustat", Func, 0}, + {"Ustat_t", Type, 0}, + {"Ustat_t.Fname", Field, 0}, + {"Ustat_t.Fpack", Field, 0}, + {"Ustat_t.Pad_cgo_0", Field, 0}, + {"Ustat_t.Pad_cgo_1", Field, 0}, + {"Ustat_t.Tfree", Field, 0}, + {"Ustat_t.Tinode", Field, 0}, + {"Utimbuf", Type, 0}, + {"Utimbuf.Actime", Field, 0}, + {"Utimbuf.Modtime", Field, 0}, + {"Utime", Func, 0}, + {"Utimes", Func, 0}, + {"UtimesNano", Func, 1}, + {"Utsname", Type, 0}, + {"Utsname.Domainname", Field, 0}, + {"Utsname.Machine", Field, 0}, + {"Utsname.Nodename", Field, 0}, + {"Utsname.Release", Field, 0}, + {"Utsname.Sysname", Field, 0}, + {"Utsname.Version", Field, 0}, + {"VDISCARD", Const, 0}, + {"VDSUSP", Const, 1}, + {"VEOF", Const, 0}, + {"VEOL", Const, 0}, + {"VEOL2", Const, 0}, + {"VERASE", Const, 0}, + {"VERASE2", Const, 1}, + {"VINTR", Const, 0}, + {"VKILL", Const, 0}, + {"VLNEXT", Const, 0}, + {"VMIN", Const, 0}, + {"VQUIT", Const, 0}, + {"VREPRINT", Const, 0}, + {"VSTART", Const, 0}, + {"VSTATUS", Const, 1}, + {"VSTOP", Const, 0}, + {"VSUSP", Const, 0}, + {"VSWTC", Const, 0}, + {"VT0", Const, 1}, + {"VT1", Const, 1}, + {"VTDLY", Const, 1}, + {"VTIME", Const, 0}, + {"VWERASE", Const, 0}, + {"VirtualLock", Func, 0}, + {"VirtualUnlock", Func, 0}, + {"WAIT_ABANDONED", Const, 0}, + {"WAIT_FAILED", Const, 0}, + {"WAIT_OBJECT_0", Const, 0}, + {"WAIT_TIMEOUT", Const, 0}, + {"WALL", Const, 0}, + {"WALLSIG", Const, 1}, + {"WALTSIG", Const, 1}, + {"WCLONE", Const, 0}, + {"WCONTINUED", Const, 0}, + {"WCOREFLAG", Const, 0}, + {"WEXITED", Const, 0}, + {"WLINUXCLONE", Const, 0}, + {"WNOHANG", Const, 0}, + {"WNOTHREAD", Const, 0}, + {"WNOWAIT", Const, 0}, + {"WNOZOMBIE", Const, 1}, + {"WOPTSCHECKED", Const, 1}, + {"WORDSIZE", Const, 0}, + {"WSABuf", Type, 0}, + {"WSABuf.Buf", Field, 0}, + {"WSABuf.Len", Field, 0}, + {"WSACleanup", Func, 0}, + {"WSADESCRIPTION_LEN", Const, 0}, + {"WSAData", Type, 0}, + {"WSAData.Description", Field, 0}, + {"WSAData.HighVersion", Field, 0}, + {"WSAData.MaxSockets", Field, 0}, + {"WSAData.MaxUdpDg", Field, 0}, + {"WSAData.SystemStatus", Field, 0}, + {"WSAData.VendorInfo", Field, 0}, + {"WSAData.Version", Field, 0}, + {"WSAEACCES", Const, 2}, + {"WSAECONNABORTED", Const, 9}, + {"WSAECONNRESET", Const, 3}, + {"WSAEnumProtocols", Func, 2}, + {"WSAID_CONNECTEX", Var, 1}, + {"WSAIoctl", Func, 0}, + {"WSAPROTOCOL_LEN", Const, 2}, + {"WSAProtocolChain", Type, 2}, + {"WSAProtocolChain.ChainEntries", Field, 2}, + {"WSAProtocolChain.ChainLen", Field, 2}, + {"WSAProtocolInfo", Type, 2}, + {"WSAProtocolInfo.AddressFamily", Field, 2}, + {"WSAProtocolInfo.CatalogEntryId", Field, 2}, + {"WSAProtocolInfo.MaxSockAddr", Field, 2}, + {"WSAProtocolInfo.MessageSize", Field, 2}, + {"WSAProtocolInfo.MinSockAddr", Field, 2}, + {"WSAProtocolInfo.NetworkByteOrder", Field, 2}, + {"WSAProtocolInfo.Protocol", Field, 2}, + {"WSAProtocolInfo.ProtocolChain", Field, 2}, + {"WSAProtocolInfo.ProtocolMaxOffset", Field, 2}, + {"WSAProtocolInfo.ProtocolName", Field, 2}, + {"WSAProtocolInfo.ProviderFlags", Field, 2}, + {"WSAProtocolInfo.ProviderId", Field, 2}, + {"WSAProtocolInfo.ProviderReserved", Field, 2}, + {"WSAProtocolInfo.SecurityScheme", Field, 2}, + {"WSAProtocolInfo.ServiceFlags1", Field, 2}, + {"WSAProtocolInfo.ServiceFlags2", Field, 2}, + {"WSAProtocolInfo.ServiceFlags3", Field, 2}, + {"WSAProtocolInfo.ServiceFlags4", Field, 2}, + {"WSAProtocolInfo.SocketType", Field, 2}, + {"WSAProtocolInfo.Version", Field, 2}, + {"WSARecv", Func, 0}, + {"WSARecvFrom", Func, 0}, + {"WSASYS_STATUS_LEN", Const, 0}, + {"WSASend", Func, 0}, + {"WSASendTo", Func, 0}, + {"WSASendto", Func, 0}, + {"WSAStartup", Func, 0}, + {"WSTOPPED", Const, 0}, + {"WTRAPPED", Const, 1}, + {"WUNTRACED", Const, 0}, + {"Wait4", Func, 0}, + {"WaitForSingleObject", Func, 0}, + {"WaitStatus", Type, 0}, + {"WaitStatus.ExitCode", Field, 0}, + {"Win32FileAttributeData", Type, 0}, + {"Win32FileAttributeData.CreationTime", Field, 0}, + {"Win32FileAttributeData.FileAttributes", Field, 0}, + {"Win32FileAttributeData.FileSizeHigh", Field, 0}, + {"Win32FileAttributeData.FileSizeLow", Field, 0}, + {"Win32FileAttributeData.LastAccessTime", Field, 0}, + {"Win32FileAttributeData.LastWriteTime", Field, 0}, + {"Win32finddata", Type, 0}, + {"Win32finddata.AlternateFileName", Field, 0}, + {"Win32finddata.CreationTime", Field, 0}, + {"Win32finddata.FileAttributes", Field, 0}, + {"Win32finddata.FileName", Field, 0}, + {"Win32finddata.FileSizeHigh", Field, 0}, + {"Win32finddata.FileSizeLow", Field, 0}, + {"Win32finddata.LastAccessTime", Field, 0}, + {"Win32finddata.LastWriteTime", Field, 0}, + {"Win32finddata.Reserved0", Field, 0}, + {"Win32finddata.Reserved1", Field, 0}, + {"Write", Func, 0}, + {"WriteConsole", Func, 1}, + {"WriteFile", Func, 0}, + {"X509_ASN_ENCODING", Const, 0}, + {"XCASE", Const, 0}, + {"XP1_CONNECTIONLESS", Const, 2}, + {"XP1_CONNECT_DATA", Const, 2}, + {"XP1_DISCONNECT_DATA", Const, 2}, + {"XP1_EXPEDITED_DATA", Const, 2}, + {"XP1_GRACEFUL_CLOSE", Const, 2}, + {"XP1_GUARANTEED_DELIVERY", Const, 2}, + {"XP1_GUARANTEED_ORDER", Const, 2}, + {"XP1_IFS_HANDLES", Const, 2}, + {"XP1_MESSAGE_ORIENTED", Const, 2}, + {"XP1_MULTIPOINT_CONTROL_PLANE", Const, 2}, + {"XP1_MULTIPOINT_DATA_PLANE", Const, 2}, + {"XP1_PARTIAL_MESSAGE", Const, 2}, + {"XP1_PSEUDO_STREAM", Const, 2}, + {"XP1_QOS_SUPPORTED", Const, 2}, + {"XP1_SAN_SUPPORT_SDP", Const, 2}, + {"XP1_SUPPORT_BROADCAST", Const, 2}, + {"XP1_SUPPORT_MULTIPOINT", Const, 2}, + {"XP1_UNI_RECV", Const, 2}, + {"XP1_UNI_SEND", Const, 2}, + }, + "syscall/js": { + {"CopyBytesToGo", Func, 0}, + {"CopyBytesToJS", Func, 0}, + {"Error", Type, 0}, + {"Func", Type, 0}, + {"FuncOf", Func, 0}, + {"Global", Func, 0}, + {"Null", Func, 0}, + {"Type", Type, 0}, + {"TypeBoolean", Const, 0}, + {"TypeFunction", Const, 0}, + {"TypeNull", Const, 0}, + {"TypeNumber", Const, 0}, + {"TypeObject", Const, 0}, + {"TypeString", Const, 0}, + {"TypeSymbol", Const, 0}, + {"TypeUndefined", Const, 0}, + {"Undefined", Func, 0}, + {"Value", Type, 0}, + {"ValueError", Type, 0}, + {"ValueOf", Func, 0}, + }, + "testing": { + {"(*B).Cleanup", Method, 14}, + {"(*B).Elapsed", Method, 20}, + {"(*B).Error", Method, 0}, + {"(*B).Errorf", Method, 0}, + {"(*B).Fail", Method, 0}, + {"(*B).FailNow", Method, 0}, + {"(*B).Failed", Method, 0}, + {"(*B).Fatal", Method, 0}, + {"(*B).Fatalf", Method, 0}, + {"(*B).Helper", Method, 9}, + {"(*B).Log", Method, 0}, + {"(*B).Logf", Method, 0}, + {"(*B).Name", Method, 8}, + {"(*B).ReportAllocs", Method, 1}, + {"(*B).ReportMetric", Method, 13}, + {"(*B).ResetTimer", Method, 0}, + {"(*B).Run", Method, 7}, + {"(*B).RunParallel", Method, 3}, + {"(*B).SetBytes", Method, 0}, + {"(*B).SetParallelism", Method, 3}, + {"(*B).Setenv", Method, 17}, + {"(*B).Skip", Method, 1}, + {"(*B).SkipNow", Method, 1}, + {"(*B).Skipf", Method, 1}, + {"(*B).Skipped", Method, 1}, + {"(*B).StartTimer", Method, 0}, + {"(*B).StopTimer", Method, 0}, + {"(*B).TempDir", Method, 15}, + {"(*F).Add", Method, 18}, + {"(*F).Cleanup", Method, 18}, + {"(*F).Error", Method, 18}, + {"(*F).Errorf", Method, 18}, + {"(*F).Fail", Method, 18}, + {"(*F).FailNow", Method, 18}, + {"(*F).Failed", Method, 18}, + {"(*F).Fatal", Method, 18}, + {"(*F).Fatalf", Method, 18}, + {"(*F).Fuzz", Method, 18}, + {"(*F).Helper", Method, 18}, + {"(*F).Log", Method, 18}, + {"(*F).Logf", Method, 18}, + {"(*F).Name", Method, 18}, + {"(*F).Setenv", Method, 18}, + {"(*F).Skip", Method, 18}, + {"(*F).SkipNow", Method, 18}, + {"(*F).Skipf", Method, 18}, + {"(*F).Skipped", Method, 18}, + {"(*F).TempDir", Method, 18}, + {"(*M).Run", Method, 4}, + {"(*PB).Next", Method, 3}, + {"(*T).Cleanup", Method, 14}, + {"(*T).Deadline", Method, 15}, + {"(*T).Error", Method, 0}, + {"(*T).Errorf", Method, 0}, + {"(*T).Fail", Method, 0}, + {"(*T).FailNow", Method, 0}, + {"(*T).Failed", Method, 0}, + {"(*T).Fatal", Method, 0}, + {"(*T).Fatalf", Method, 0}, + {"(*T).Helper", Method, 9}, + {"(*T).Log", Method, 0}, + {"(*T).Logf", Method, 0}, + {"(*T).Name", Method, 8}, + {"(*T).Parallel", Method, 0}, + {"(*T).Run", Method, 7}, + {"(*T).Setenv", Method, 17}, + {"(*T).Skip", Method, 1}, + {"(*T).SkipNow", Method, 1}, + {"(*T).Skipf", Method, 1}, + {"(*T).Skipped", Method, 1}, + {"(*T).TempDir", Method, 15}, + {"(BenchmarkResult).AllocedBytesPerOp", Method, 1}, + {"(BenchmarkResult).AllocsPerOp", Method, 1}, + {"(BenchmarkResult).MemString", Method, 1}, + {"(BenchmarkResult).NsPerOp", Method, 0}, + {"(BenchmarkResult).String", Method, 0}, + {"AllocsPerRun", Func, 1}, + {"B", Type, 0}, + {"B.N", Field, 0}, + {"Benchmark", Func, 0}, + {"BenchmarkResult", Type, 0}, + {"BenchmarkResult.Bytes", Field, 0}, + {"BenchmarkResult.Extra", Field, 13}, + {"BenchmarkResult.MemAllocs", Field, 1}, + {"BenchmarkResult.MemBytes", Field, 1}, + {"BenchmarkResult.N", Field, 0}, + {"BenchmarkResult.T", Field, 0}, + {"Cover", Type, 2}, + {"Cover.Blocks", Field, 2}, + {"Cover.Counters", Field, 2}, + {"Cover.CoveredPackages", Field, 2}, + {"Cover.Mode", Field, 2}, + {"CoverBlock", Type, 2}, + {"CoverBlock.Col0", Field, 2}, + {"CoverBlock.Col1", Field, 2}, + {"CoverBlock.Line0", Field, 2}, + {"CoverBlock.Line1", Field, 2}, + {"CoverBlock.Stmts", Field, 2}, + {"CoverMode", Func, 8}, + {"Coverage", Func, 4}, + {"F", Type, 18}, + {"Init", Func, 13}, + {"InternalBenchmark", Type, 0}, + {"InternalBenchmark.F", Field, 0}, + {"InternalBenchmark.Name", Field, 0}, + {"InternalExample", Type, 0}, + {"InternalExample.F", Field, 0}, + {"InternalExample.Name", Field, 0}, + {"InternalExample.Output", Field, 0}, + {"InternalExample.Unordered", Field, 7}, + {"InternalFuzzTarget", Type, 18}, + {"InternalFuzzTarget.Fn", Field, 18}, + {"InternalFuzzTarget.Name", Field, 18}, + {"InternalTest", Type, 0}, + {"InternalTest.F", Field, 0}, + {"InternalTest.Name", Field, 0}, + {"M", Type, 4}, + {"Main", Func, 0}, + {"MainStart", Func, 4}, + {"PB", Type, 3}, + {"RegisterCover", Func, 2}, + {"RunBenchmarks", Func, 0}, + {"RunExamples", Func, 0}, + {"RunTests", Func, 0}, + {"Short", Func, 0}, + {"T", Type, 0}, + {"TB", Type, 2}, + {"Testing", Func, 21}, + {"Verbose", Func, 1}, + }, + "testing/fstest": { + {"(MapFS).Glob", Method, 16}, + {"(MapFS).Open", Method, 16}, + {"(MapFS).ReadDir", Method, 16}, + {"(MapFS).ReadFile", Method, 16}, + {"(MapFS).Stat", Method, 16}, + {"(MapFS).Sub", Method, 16}, + {"MapFS", Type, 16}, + {"MapFile", Type, 16}, + {"MapFile.Data", Field, 16}, + {"MapFile.ModTime", Field, 16}, + {"MapFile.Mode", Field, 16}, + {"MapFile.Sys", Field, 16}, + {"TestFS", Func, 16}, + }, + "testing/iotest": { + {"DataErrReader", Func, 0}, + {"ErrReader", Func, 16}, + {"ErrTimeout", Var, 0}, + {"HalfReader", Func, 0}, + {"NewReadLogger", Func, 0}, + {"NewWriteLogger", Func, 0}, + {"OneByteReader", Func, 0}, + {"TestReader", Func, 16}, + {"TimeoutReader", Func, 0}, + {"TruncateWriter", Func, 0}, + }, + "testing/quick": { + {"(*CheckEqualError).Error", Method, 0}, + {"(*CheckError).Error", Method, 0}, + {"(SetupError).Error", Method, 0}, + {"Check", Func, 0}, + {"CheckEqual", Func, 0}, + {"CheckEqualError", Type, 0}, + {"CheckEqualError.CheckError", Field, 0}, + {"CheckEqualError.Out1", Field, 0}, + {"CheckEqualError.Out2", Field, 0}, + {"CheckError", Type, 0}, + {"CheckError.Count", Field, 0}, + {"CheckError.In", Field, 0}, + {"Config", Type, 0}, + {"Config.MaxCount", Field, 0}, + {"Config.MaxCountScale", Field, 0}, + {"Config.Rand", Field, 0}, + {"Config.Values", Field, 0}, + {"Generator", Type, 0}, + {"SetupError", Type, 0}, + {"Value", Func, 0}, + }, + "testing/slogtest": { + {"Run", Func, 22}, + {"TestHandler", Func, 21}, + }, + "text/scanner": { + {"(*Position).IsValid", Method, 0}, + {"(*Scanner).Init", Method, 0}, + {"(*Scanner).IsValid", Method, 0}, + {"(*Scanner).Next", Method, 0}, + {"(*Scanner).Peek", Method, 0}, + {"(*Scanner).Pos", Method, 0}, + {"(*Scanner).Scan", Method, 0}, + {"(*Scanner).TokenText", Method, 0}, + {"(Position).String", Method, 0}, + {"(Scanner).String", Method, 0}, + {"Char", Const, 0}, + {"Comment", Const, 0}, + {"EOF", Const, 0}, + {"Float", Const, 0}, + {"GoTokens", Const, 0}, + {"GoWhitespace", Const, 0}, + {"Ident", Const, 0}, + {"Int", Const, 0}, + {"Position", Type, 0}, + {"Position.Column", Field, 0}, + {"Position.Filename", Field, 0}, + {"Position.Line", Field, 0}, + {"Position.Offset", Field, 0}, + {"RawString", Const, 0}, + {"ScanChars", Const, 0}, + {"ScanComments", Const, 0}, + {"ScanFloats", Const, 0}, + {"ScanIdents", Const, 0}, + {"ScanInts", Const, 0}, + {"ScanRawStrings", Const, 0}, + {"ScanStrings", Const, 0}, + {"Scanner", Type, 0}, + {"Scanner.Error", Field, 0}, + {"Scanner.ErrorCount", Field, 0}, + {"Scanner.IsIdentRune", Field, 4}, + {"Scanner.Mode", Field, 0}, + {"Scanner.Position", Field, 0}, + {"Scanner.Whitespace", Field, 0}, + {"SkipComments", Const, 0}, + {"String", Const, 0}, + {"TokenString", Func, 0}, + }, + "text/tabwriter": { + {"(*Writer).Flush", Method, 0}, + {"(*Writer).Init", Method, 0}, + {"(*Writer).Write", Method, 0}, + {"AlignRight", Const, 0}, + {"Debug", Const, 0}, + {"DiscardEmptyColumns", Const, 0}, + {"Escape", Const, 0}, + {"FilterHTML", Const, 0}, + {"NewWriter", Func, 0}, + {"StripEscape", Const, 0}, + {"TabIndent", Const, 0}, + {"Writer", Type, 0}, + }, + "text/template": { + {"(*Template).AddParseTree", Method, 0}, + {"(*Template).Clone", Method, 0}, + {"(*Template).DefinedTemplates", Method, 5}, + {"(*Template).Delims", Method, 0}, + {"(*Template).Execute", Method, 0}, + {"(*Template).ExecuteTemplate", Method, 0}, + {"(*Template).Funcs", Method, 0}, + {"(*Template).Lookup", Method, 0}, + {"(*Template).Name", Method, 0}, + {"(*Template).New", Method, 0}, + {"(*Template).Option", Method, 5}, + {"(*Template).Parse", Method, 0}, + {"(*Template).ParseFS", Method, 16}, + {"(*Template).ParseFiles", Method, 0}, + {"(*Template).ParseGlob", Method, 0}, + {"(*Template).Templates", Method, 0}, + {"(ExecError).Error", Method, 6}, + {"(ExecError).Unwrap", Method, 13}, + {"(Template).Copy", Method, 2}, + {"(Template).ErrorContext", Method, 1}, + {"ExecError", Type, 6}, + {"ExecError.Err", Field, 6}, + {"ExecError.Name", Field, 6}, + {"FuncMap", Type, 0}, + {"HTMLEscape", Func, 0}, + {"HTMLEscapeString", Func, 0}, + {"HTMLEscaper", Func, 0}, + {"IsTrue", Func, 6}, + {"JSEscape", Func, 0}, + {"JSEscapeString", Func, 0}, + {"JSEscaper", Func, 0}, + {"Must", Func, 0}, + {"New", Func, 0}, + {"ParseFS", Func, 16}, + {"ParseFiles", Func, 0}, + {"ParseGlob", Func, 0}, + {"Template", Type, 0}, + {"Template.Tree", Field, 0}, + {"URLQueryEscaper", Func, 0}, + }, + "text/template/parse": { + {"(*ActionNode).Copy", Method, 0}, + {"(*ActionNode).String", Method, 0}, + {"(*BoolNode).Copy", Method, 0}, + {"(*BoolNode).String", Method, 0}, + {"(*BranchNode).Copy", Method, 4}, + {"(*BranchNode).String", Method, 0}, + {"(*BreakNode).Copy", Method, 18}, + {"(*BreakNode).String", Method, 18}, + {"(*ChainNode).Add", Method, 1}, + {"(*ChainNode).Copy", Method, 1}, + {"(*ChainNode).String", Method, 1}, + {"(*CommandNode).Copy", Method, 0}, + {"(*CommandNode).String", Method, 0}, + {"(*CommentNode).Copy", Method, 16}, + {"(*CommentNode).String", Method, 16}, + {"(*ContinueNode).Copy", Method, 18}, + {"(*ContinueNode).String", Method, 18}, + {"(*DotNode).Copy", Method, 0}, + {"(*DotNode).String", Method, 0}, + {"(*DotNode).Type", Method, 0}, + {"(*FieldNode).Copy", Method, 0}, + {"(*FieldNode).String", Method, 0}, + {"(*IdentifierNode).Copy", Method, 0}, + {"(*IdentifierNode).SetPos", Method, 1}, + {"(*IdentifierNode).SetTree", Method, 4}, + {"(*IdentifierNode).String", Method, 0}, + {"(*IfNode).Copy", Method, 0}, + {"(*IfNode).String", Method, 0}, + {"(*ListNode).Copy", Method, 0}, + {"(*ListNode).CopyList", Method, 0}, + {"(*ListNode).String", Method, 0}, + {"(*NilNode).Copy", Method, 1}, + {"(*NilNode).String", Method, 1}, + {"(*NilNode).Type", Method, 1}, + {"(*NumberNode).Copy", Method, 0}, + {"(*NumberNode).String", Method, 0}, + {"(*PipeNode).Copy", Method, 0}, + {"(*PipeNode).CopyPipe", Method, 0}, + {"(*PipeNode).String", Method, 0}, + {"(*RangeNode).Copy", Method, 0}, + {"(*RangeNode).String", Method, 0}, + {"(*StringNode).Copy", Method, 0}, + {"(*StringNode).String", Method, 0}, + {"(*TemplateNode).Copy", Method, 0}, + {"(*TemplateNode).String", Method, 0}, + {"(*TextNode).Copy", Method, 0}, + {"(*TextNode).String", Method, 0}, + {"(*Tree).Copy", Method, 2}, + {"(*Tree).ErrorContext", Method, 1}, + {"(*Tree).Parse", Method, 0}, + {"(*VariableNode).Copy", Method, 0}, + {"(*VariableNode).String", Method, 0}, + {"(*WithNode).Copy", Method, 0}, + {"(*WithNode).String", Method, 0}, + {"(ActionNode).Position", Method, 1}, + {"(ActionNode).Type", Method, 0}, + {"(BoolNode).Position", Method, 1}, + {"(BoolNode).Type", Method, 0}, + {"(BranchNode).Position", Method, 1}, + {"(BranchNode).Type", Method, 0}, + {"(BreakNode).Position", Method, 18}, + {"(BreakNode).Type", Method, 18}, + {"(ChainNode).Position", Method, 1}, + {"(ChainNode).Type", Method, 1}, + {"(CommandNode).Position", Method, 1}, + {"(CommandNode).Type", Method, 0}, + {"(CommentNode).Position", Method, 16}, + {"(CommentNode).Type", Method, 16}, + {"(ContinueNode).Position", Method, 18}, + {"(ContinueNode).Type", Method, 18}, + {"(DotNode).Position", Method, 1}, + {"(FieldNode).Position", Method, 1}, + {"(FieldNode).Type", Method, 0}, + {"(IdentifierNode).Position", Method, 1}, + {"(IdentifierNode).Type", Method, 0}, + {"(IfNode).Position", Method, 1}, + {"(IfNode).Type", Method, 0}, + {"(ListNode).Position", Method, 1}, + {"(ListNode).Type", Method, 0}, + {"(NilNode).Position", Method, 1}, + {"(NodeType).Type", Method, 0}, + {"(NumberNode).Position", Method, 1}, + {"(NumberNode).Type", Method, 0}, + {"(PipeNode).Position", Method, 1}, + {"(PipeNode).Type", Method, 0}, + {"(Pos).Position", Method, 1}, + {"(RangeNode).Position", Method, 1}, + {"(RangeNode).Type", Method, 0}, + {"(StringNode).Position", Method, 1}, + {"(StringNode).Type", Method, 0}, + {"(TemplateNode).Position", Method, 1}, + {"(TemplateNode).Type", Method, 0}, + {"(TextNode).Position", Method, 1}, + {"(TextNode).Type", Method, 0}, + {"(VariableNode).Position", Method, 1}, + {"(VariableNode).Type", Method, 0}, + {"(WithNode).Position", Method, 1}, + {"(WithNode).Type", Method, 0}, + {"ActionNode", Type, 0}, + {"ActionNode.Line", Field, 0}, + {"ActionNode.NodeType", Field, 0}, + {"ActionNode.Pipe", Field, 0}, + {"ActionNode.Pos", Field, 1}, + {"BoolNode", Type, 0}, + {"BoolNode.NodeType", Field, 0}, + {"BoolNode.Pos", Field, 1}, + {"BoolNode.True", Field, 0}, + {"BranchNode", Type, 0}, + {"BranchNode.ElseList", Field, 0}, + {"BranchNode.Line", Field, 0}, + {"BranchNode.List", Field, 0}, + {"BranchNode.NodeType", Field, 0}, + {"BranchNode.Pipe", Field, 0}, + {"BranchNode.Pos", Field, 1}, + {"BreakNode", Type, 18}, + {"BreakNode.Line", Field, 18}, + {"BreakNode.NodeType", Field, 18}, + {"BreakNode.Pos", Field, 18}, + {"ChainNode", Type, 1}, + {"ChainNode.Field", Field, 1}, + {"ChainNode.Node", Field, 1}, + {"ChainNode.NodeType", Field, 1}, + {"ChainNode.Pos", Field, 1}, + {"CommandNode", Type, 0}, + {"CommandNode.Args", Field, 0}, + {"CommandNode.NodeType", Field, 0}, + {"CommandNode.Pos", Field, 1}, + {"CommentNode", Type, 16}, + {"CommentNode.NodeType", Field, 16}, + {"CommentNode.Pos", Field, 16}, + {"CommentNode.Text", Field, 16}, + {"ContinueNode", Type, 18}, + {"ContinueNode.Line", Field, 18}, + {"ContinueNode.NodeType", Field, 18}, + {"ContinueNode.Pos", Field, 18}, + {"DotNode", Type, 0}, + {"DotNode.NodeType", Field, 4}, + {"DotNode.Pos", Field, 1}, + {"FieldNode", Type, 0}, + {"FieldNode.Ident", Field, 0}, + {"FieldNode.NodeType", Field, 0}, + {"FieldNode.Pos", Field, 1}, + {"IdentifierNode", Type, 0}, + {"IdentifierNode.Ident", Field, 0}, + {"IdentifierNode.NodeType", Field, 0}, + {"IdentifierNode.Pos", Field, 1}, + {"IfNode", Type, 0}, + {"IfNode.BranchNode", Field, 0}, + {"IsEmptyTree", Func, 0}, + {"ListNode", Type, 0}, + {"ListNode.NodeType", Field, 0}, + {"ListNode.Nodes", Field, 0}, + {"ListNode.Pos", Field, 1}, + {"Mode", Type, 16}, + {"New", Func, 0}, + {"NewIdentifier", Func, 0}, + {"NilNode", Type, 1}, + {"NilNode.NodeType", Field, 4}, + {"NilNode.Pos", Field, 1}, + {"Node", Type, 0}, + {"NodeAction", Const, 0}, + {"NodeBool", Const, 0}, + {"NodeBreak", Const, 18}, + {"NodeChain", Const, 1}, + {"NodeCommand", Const, 0}, + {"NodeComment", Const, 16}, + {"NodeContinue", Const, 18}, + {"NodeDot", Const, 0}, + {"NodeField", Const, 0}, + {"NodeIdentifier", Const, 0}, + {"NodeIf", Const, 0}, + {"NodeList", Const, 0}, + {"NodeNil", Const, 1}, + {"NodeNumber", Const, 0}, + {"NodePipe", Const, 0}, + {"NodeRange", Const, 0}, + {"NodeString", Const, 0}, + {"NodeTemplate", Const, 0}, + {"NodeText", Const, 0}, + {"NodeType", Type, 0}, + {"NodeVariable", Const, 0}, + {"NodeWith", Const, 0}, + {"NumberNode", Type, 0}, + {"NumberNode.Complex128", Field, 0}, + {"NumberNode.Float64", Field, 0}, + {"NumberNode.Int64", Field, 0}, + {"NumberNode.IsComplex", Field, 0}, + {"NumberNode.IsFloat", Field, 0}, + {"NumberNode.IsInt", Field, 0}, + {"NumberNode.IsUint", Field, 0}, + {"NumberNode.NodeType", Field, 0}, + {"NumberNode.Pos", Field, 1}, + {"NumberNode.Text", Field, 0}, + {"NumberNode.Uint64", Field, 0}, + {"Parse", Func, 0}, + {"ParseComments", Const, 16}, + {"PipeNode", Type, 0}, + {"PipeNode.Cmds", Field, 0}, + {"PipeNode.Decl", Field, 0}, + {"PipeNode.IsAssign", Field, 11}, + {"PipeNode.Line", Field, 0}, + {"PipeNode.NodeType", Field, 0}, + {"PipeNode.Pos", Field, 1}, + {"Pos", Type, 1}, + {"RangeNode", Type, 0}, + {"RangeNode.BranchNode", Field, 0}, + {"SkipFuncCheck", Const, 17}, + {"StringNode", Type, 0}, + {"StringNode.NodeType", Field, 0}, + {"StringNode.Pos", Field, 1}, + {"StringNode.Quoted", Field, 0}, + {"StringNode.Text", Field, 0}, + {"TemplateNode", Type, 0}, + {"TemplateNode.Line", Field, 0}, + {"TemplateNode.Name", Field, 0}, + {"TemplateNode.NodeType", Field, 0}, + {"TemplateNode.Pipe", Field, 0}, + {"TemplateNode.Pos", Field, 1}, + {"TextNode", Type, 0}, + {"TextNode.NodeType", Field, 0}, + {"TextNode.Pos", Field, 1}, + {"TextNode.Text", Field, 0}, + {"Tree", Type, 0}, + {"Tree.Mode", Field, 16}, + {"Tree.Name", Field, 0}, + {"Tree.ParseName", Field, 1}, + {"Tree.Root", Field, 0}, + {"VariableNode", Type, 0}, + {"VariableNode.Ident", Field, 0}, + {"VariableNode.NodeType", Field, 0}, + {"VariableNode.Pos", Field, 1}, + {"WithNode", Type, 0}, + {"WithNode.BranchNode", Field, 0}, + }, + "time": { + {"(*Location).String", Method, 0}, + {"(*ParseError).Error", Method, 0}, + {"(*Ticker).Reset", Method, 15}, + {"(*Ticker).Stop", Method, 0}, + {"(*Time).GobDecode", Method, 0}, + {"(*Time).UnmarshalBinary", Method, 2}, + {"(*Time).UnmarshalJSON", Method, 0}, + {"(*Time).UnmarshalText", Method, 2}, + {"(*Timer).Reset", Method, 1}, + {"(*Timer).Stop", Method, 0}, + {"(Duration).Abs", Method, 19}, + {"(Duration).Hours", Method, 0}, + {"(Duration).Microseconds", Method, 13}, + {"(Duration).Milliseconds", Method, 13}, + {"(Duration).Minutes", Method, 0}, + {"(Duration).Nanoseconds", Method, 0}, + {"(Duration).Round", Method, 9}, + {"(Duration).Seconds", Method, 0}, + {"(Duration).String", Method, 0}, + {"(Duration).Truncate", Method, 9}, + {"(Month).String", Method, 0}, + {"(Time).Add", Method, 0}, + {"(Time).AddDate", Method, 0}, + {"(Time).After", Method, 0}, + {"(Time).AppendFormat", Method, 5}, + {"(Time).Before", Method, 0}, + {"(Time).Clock", Method, 0}, + {"(Time).Compare", Method, 20}, + {"(Time).Date", Method, 0}, + {"(Time).Day", Method, 0}, + {"(Time).Equal", Method, 0}, + {"(Time).Format", Method, 0}, + {"(Time).GoString", Method, 17}, + {"(Time).GobEncode", Method, 0}, + {"(Time).Hour", Method, 0}, + {"(Time).ISOWeek", Method, 0}, + {"(Time).In", Method, 0}, + {"(Time).IsDST", Method, 17}, + {"(Time).IsZero", Method, 0}, + {"(Time).Local", Method, 0}, + {"(Time).Location", Method, 0}, + {"(Time).MarshalBinary", Method, 2}, + {"(Time).MarshalJSON", Method, 0}, + {"(Time).MarshalText", Method, 2}, + {"(Time).Minute", Method, 0}, + {"(Time).Month", Method, 0}, + {"(Time).Nanosecond", Method, 0}, + {"(Time).Round", Method, 1}, + {"(Time).Second", Method, 0}, + {"(Time).String", Method, 0}, + {"(Time).Sub", Method, 0}, + {"(Time).Truncate", Method, 1}, + {"(Time).UTC", Method, 0}, + {"(Time).Unix", Method, 0}, + {"(Time).UnixMicro", Method, 17}, + {"(Time).UnixMilli", Method, 17}, + {"(Time).UnixNano", Method, 0}, + {"(Time).Weekday", Method, 0}, + {"(Time).Year", Method, 0}, + {"(Time).YearDay", Method, 1}, + {"(Time).Zone", Method, 0}, + {"(Time).ZoneBounds", Method, 19}, + {"(Weekday).String", Method, 0}, + {"ANSIC", Const, 0}, + {"After", Func, 0}, + {"AfterFunc", Func, 0}, + {"April", Const, 0}, + {"August", Const, 0}, + {"Date", Func, 0}, + {"DateOnly", Const, 20}, + {"DateTime", Const, 20}, + {"December", Const, 0}, + {"Duration", Type, 0}, + {"February", Const, 0}, + {"FixedZone", Func, 0}, + {"Friday", Const, 0}, + {"Hour", Const, 0}, + {"January", Const, 0}, + {"July", Const, 0}, + {"June", Const, 0}, + {"Kitchen", Const, 0}, + {"Layout", Const, 17}, + {"LoadLocation", Func, 0}, + {"LoadLocationFromTZData", Func, 10}, + {"Local", Var, 0}, + {"Location", Type, 0}, + {"March", Const, 0}, + {"May", Const, 0}, + {"Microsecond", Const, 0}, + {"Millisecond", Const, 0}, + {"Minute", Const, 0}, + {"Monday", Const, 0}, + {"Month", Type, 0}, + {"Nanosecond", Const, 0}, + {"NewTicker", Func, 0}, + {"NewTimer", Func, 0}, + {"November", Const, 0}, + {"Now", Func, 0}, + {"October", Const, 0}, + {"Parse", Func, 0}, + {"ParseDuration", Func, 0}, + {"ParseError", Type, 0}, + {"ParseError.Layout", Field, 0}, + {"ParseError.LayoutElem", Field, 0}, + {"ParseError.Message", Field, 0}, + {"ParseError.Value", Field, 0}, + {"ParseError.ValueElem", Field, 0}, + {"ParseInLocation", Func, 1}, + {"RFC1123", Const, 0}, + {"RFC1123Z", Const, 0}, + {"RFC3339", Const, 0}, + {"RFC3339Nano", Const, 0}, + {"RFC822", Const, 0}, + {"RFC822Z", Const, 0}, + {"RFC850", Const, 0}, + {"RubyDate", Const, 0}, + {"Saturday", Const, 0}, + {"Second", Const, 0}, + {"September", Const, 0}, + {"Since", Func, 0}, + {"Sleep", Func, 0}, + {"Stamp", Const, 0}, + {"StampMicro", Const, 0}, + {"StampMilli", Const, 0}, + {"StampNano", Const, 0}, + {"Sunday", Const, 0}, + {"Thursday", Const, 0}, + {"Tick", Func, 0}, + {"Ticker", Type, 0}, + {"Ticker.C", Field, 0}, + {"Time", Type, 0}, + {"TimeOnly", Const, 20}, + {"Timer", Type, 0}, + {"Timer.C", Field, 0}, + {"Tuesday", Const, 0}, + {"UTC", Var, 0}, + {"Unix", Func, 0}, + {"UnixDate", Const, 0}, + {"UnixMicro", Func, 17}, + {"UnixMilli", Func, 17}, + {"Until", Func, 8}, + {"Wednesday", Const, 0}, + {"Weekday", Type, 0}, + }, + "unicode": { + {"(SpecialCase).ToLower", Method, 0}, + {"(SpecialCase).ToTitle", Method, 0}, + {"(SpecialCase).ToUpper", Method, 0}, + {"ASCII_Hex_Digit", Var, 0}, + {"Adlam", Var, 7}, + {"Ahom", Var, 5}, + {"Anatolian_Hieroglyphs", Var, 5}, + {"Arabic", Var, 0}, + {"Armenian", Var, 0}, + {"Avestan", Var, 0}, + {"AzeriCase", Var, 0}, + {"Balinese", Var, 0}, + {"Bamum", Var, 0}, + {"Bassa_Vah", Var, 4}, + {"Batak", Var, 0}, + {"Bengali", Var, 0}, + {"Bhaiksuki", Var, 7}, + {"Bidi_Control", Var, 0}, + {"Bopomofo", Var, 0}, + {"Brahmi", Var, 0}, + {"Braille", Var, 0}, + {"Buginese", Var, 0}, + {"Buhid", Var, 0}, + {"C", Var, 0}, + {"Canadian_Aboriginal", Var, 0}, + {"Carian", Var, 0}, + {"CaseRange", Type, 0}, + {"CaseRange.Delta", Field, 0}, + {"CaseRange.Hi", Field, 0}, + {"CaseRange.Lo", Field, 0}, + {"CaseRanges", Var, 0}, + {"Categories", Var, 0}, + {"Caucasian_Albanian", Var, 4}, + {"Cc", Var, 0}, + {"Cf", Var, 0}, + {"Chakma", Var, 1}, + {"Cham", Var, 0}, + {"Cherokee", Var, 0}, + {"Chorasmian", Var, 16}, + {"Co", Var, 0}, + {"Common", Var, 0}, + {"Coptic", Var, 0}, + {"Cs", Var, 0}, + {"Cuneiform", Var, 0}, + {"Cypriot", Var, 0}, + {"Cypro_Minoan", Var, 21}, + {"Cyrillic", Var, 0}, + {"Dash", Var, 0}, + {"Deprecated", Var, 0}, + {"Deseret", Var, 0}, + {"Devanagari", Var, 0}, + {"Diacritic", Var, 0}, + {"Digit", Var, 0}, + {"Dives_Akuru", Var, 16}, + {"Dogra", Var, 13}, + {"Duployan", Var, 4}, + {"Egyptian_Hieroglyphs", Var, 0}, + {"Elbasan", Var, 4}, + {"Elymaic", Var, 14}, + {"Ethiopic", Var, 0}, + {"Extender", Var, 0}, + {"FoldCategory", Var, 0}, + {"FoldScript", Var, 0}, + {"Georgian", Var, 0}, + {"Glagolitic", Var, 0}, + {"Gothic", Var, 0}, + {"Grantha", Var, 4}, + {"GraphicRanges", Var, 0}, + {"Greek", Var, 0}, + {"Gujarati", Var, 0}, + {"Gunjala_Gondi", Var, 13}, + {"Gurmukhi", Var, 0}, + {"Han", Var, 0}, + {"Hangul", Var, 0}, + {"Hanifi_Rohingya", Var, 13}, + {"Hanunoo", Var, 0}, + {"Hatran", Var, 5}, + {"Hebrew", Var, 0}, + {"Hex_Digit", Var, 0}, + {"Hiragana", Var, 0}, + {"Hyphen", Var, 0}, + {"IDS_Binary_Operator", Var, 0}, + {"IDS_Trinary_Operator", Var, 0}, + {"Ideographic", Var, 0}, + {"Imperial_Aramaic", Var, 0}, + {"In", Func, 2}, + {"Inherited", Var, 0}, + {"Inscriptional_Pahlavi", Var, 0}, + {"Inscriptional_Parthian", Var, 0}, + {"Is", Func, 0}, + {"IsControl", Func, 0}, + {"IsDigit", Func, 0}, + {"IsGraphic", Func, 0}, + {"IsLetter", Func, 0}, + {"IsLower", Func, 0}, + {"IsMark", Func, 0}, + {"IsNumber", Func, 0}, + {"IsOneOf", Func, 0}, + {"IsPrint", Func, 0}, + {"IsPunct", Func, 0}, + {"IsSpace", Func, 0}, + {"IsSymbol", Func, 0}, + {"IsTitle", Func, 0}, + {"IsUpper", Func, 0}, + {"Javanese", Var, 0}, + {"Join_Control", Var, 0}, + {"Kaithi", Var, 0}, + {"Kannada", Var, 0}, + {"Katakana", Var, 0}, + {"Kawi", Var, 21}, + {"Kayah_Li", Var, 0}, + {"Kharoshthi", Var, 0}, + {"Khitan_Small_Script", Var, 16}, + {"Khmer", Var, 0}, + {"Khojki", Var, 4}, + {"Khudawadi", Var, 4}, + {"L", Var, 0}, + {"Lao", Var, 0}, + {"Latin", Var, 0}, + {"Lepcha", Var, 0}, + {"Letter", Var, 0}, + {"Limbu", Var, 0}, + {"Linear_A", Var, 4}, + {"Linear_B", Var, 0}, + {"Lisu", Var, 0}, + {"Ll", Var, 0}, + {"Lm", Var, 0}, + {"Lo", Var, 0}, + {"Logical_Order_Exception", Var, 0}, + {"Lower", Var, 0}, + {"LowerCase", Const, 0}, + {"Lt", Var, 0}, + {"Lu", Var, 0}, + {"Lycian", Var, 0}, + {"Lydian", Var, 0}, + {"M", Var, 0}, + {"Mahajani", Var, 4}, + {"Makasar", Var, 13}, + {"Malayalam", Var, 0}, + {"Mandaic", Var, 0}, + {"Manichaean", Var, 4}, + {"Marchen", Var, 7}, + {"Mark", Var, 0}, + {"Masaram_Gondi", Var, 10}, + {"MaxASCII", Const, 0}, + {"MaxCase", Const, 0}, + {"MaxLatin1", Const, 0}, + {"MaxRune", Const, 0}, + {"Mc", Var, 0}, + {"Me", Var, 0}, + {"Medefaidrin", Var, 13}, + {"Meetei_Mayek", Var, 0}, + {"Mende_Kikakui", Var, 4}, + {"Meroitic_Cursive", Var, 1}, + {"Meroitic_Hieroglyphs", Var, 1}, + {"Miao", Var, 1}, + {"Mn", Var, 0}, + {"Modi", Var, 4}, + {"Mongolian", Var, 0}, + {"Mro", Var, 4}, + {"Multani", Var, 5}, + {"Myanmar", Var, 0}, + {"N", Var, 0}, + {"Nabataean", Var, 4}, + {"Nag_Mundari", Var, 21}, + {"Nandinagari", Var, 14}, + {"Nd", Var, 0}, + {"New_Tai_Lue", Var, 0}, + {"Newa", Var, 7}, + {"Nko", Var, 0}, + {"Nl", Var, 0}, + {"No", Var, 0}, + {"Noncharacter_Code_Point", Var, 0}, + {"Number", Var, 0}, + {"Nushu", Var, 10}, + {"Nyiakeng_Puachue_Hmong", Var, 14}, + {"Ogham", Var, 0}, + {"Ol_Chiki", Var, 0}, + {"Old_Hungarian", Var, 5}, + {"Old_Italic", Var, 0}, + {"Old_North_Arabian", Var, 4}, + {"Old_Permic", Var, 4}, + {"Old_Persian", Var, 0}, + {"Old_Sogdian", Var, 13}, + {"Old_South_Arabian", Var, 0}, + {"Old_Turkic", Var, 0}, + {"Old_Uyghur", Var, 21}, + {"Oriya", Var, 0}, + {"Osage", Var, 7}, + {"Osmanya", Var, 0}, + {"Other", Var, 0}, + {"Other_Alphabetic", Var, 0}, + {"Other_Default_Ignorable_Code_Point", Var, 0}, + {"Other_Grapheme_Extend", Var, 0}, + {"Other_ID_Continue", Var, 0}, + {"Other_ID_Start", Var, 0}, + {"Other_Lowercase", Var, 0}, + {"Other_Math", Var, 0}, + {"Other_Uppercase", Var, 0}, + {"P", Var, 0}, + {"Pahawh_Hmong", Var, 4}, + {"Palmyrene", Var, 4}, + {"Pattern_Syntax", Var, 0}, + {"Pattern_White_Space", Var, 0}, + {"Pau_Cin_Hau", Var, 4}, + {"Pc", Var, 0}, + {"Pd", Var, 0}, + {"Pe", Var, 0}, + {"Pf", Var, 0}, + {"Phags_Pa", Var, 0}, + {"Phoenician", Var, 0}, + {"Pi", Var, 0}, + {"Po", Var, 0}, + {"Prepended_Concatenation_Mark", Var, 7}, + {"PrintRanges", Var, 0}, + {"Properties", Var, 0}, + {"Ps", Var, 0}, + {"Psalter_Pahlavi", Var, 4}, + {"Punct", Var, 0}, + {"Quotation_Mark", Var, 0}, + {"Radical", Var, 0}, + {"Range16", Type, 0}, + {"Range16.Hi", Field, 0}, + {"Range16.Lo", Field, 0}, + {"Range16.Stride", Field, 0}, + {"Range32", Type, 0}, + {"Range32.Hi", Field, 0}, + {"Range32.Lo", Field, 0}, + {"Range32.Stride", Field, 0}, + {"RangeTable", Type, 0}, + {"RangeTable.LatinOffset", Field, 1}, + {"RangeTable.R16", Field, 0}, + {"RangeTable.R32", Field, 0}, + {"Regional_Indicator", Var, 10}, + {"Rejang", Var, 0}, + {"ReplacementChar", Const, 0}, + {"Runic", Var, 0}, + {"S", Var, 0}, + {"STerm", Var, 0}, + {"Samaritan", Var, 0}, + {"Saurashtra", Var, 0}, + {"Sc", Var, 0}, + {"Scripts", Var, 0}, + {"Sentence_Terminal", Var, 7}, + {"Sharada", Var, 1}, + {"Shavian", Var, 0}, + {"Siddham", Var, 4}, + {"SignWriting", Var, 5}, + {"SimpleFold", Func, 0}, + {"Sinhala", Var, 0}, + {"Sk", Var, 0}, + {"Sm", Var, 0}, + {"So", Var, 0}, + {"Soft_Dotted", Var, 0}, + {"Sogdian", Var, 13}, + {"Sora_Sompeng", Var, 1}, + {"Soyombo", Var, 10}, + {"Space", Var, 0}, + {"SpecialCase", Type, 0}, + {"Sundanese", Var, 0}, + {"Syloti_Nagri", Var, 0}, + {"Symbol", Var, 0}, + {"Syriac", Var, 0}, + {"Tagalog", Var, 0}, + {"Tagbanwa", Var, 0}, + {"Tai_Le", Var, 0}, + {"Tai_Tham", Var, 0}, + {"Tai_Viet", Var, 0}, + {"Takri", Var, 1}, + {"Tamil", Var, 0}, + {"Tangsa", Var, 21}, + {"Tangut", Var, 7}, + {"Telugu", Var, 0}, + {"Terminal_Punctuation", Var, 0}, + {"Thaana", Var, 0}, + {"Thai", Var, 0}, + {"Tibetan", Var, 0}, + {"Tifinagh", Var, 0}, + {"Tirhuta", Var, 4}, + {"Title", Var, 0}, + {"TitleCase", Const, 0}, + {"To", Func, 0}, + {"ToLower", Func, 0}, + {"ToTitle", Func, 0}, + {"ToUpper", Func, 0}, + {"Toto", Var, 21}, + {"TurkishCase", Var, 0}, + {"Ugaritic", Var, 0}, + {"Unified_Ideograph", Var, 0}, + {"Upper", Var, 0}, + {"UpperCase", Const, 0}, + {"UpperLower", Const, 0}, + {"Vai", Var, 0}, + {"Variation_Selector", Var, 0}, + {"Version", Const, 0}, + {"Vithkuqi", Var, 21}, + {"Wancho", Var, 14}, + {"Warang_Citi", Var, 4}, + {"White_Space", Var, 0}, + {"Yezidi", Var, 16}, + {"Yi", Var, 0}, + {"Z", Var, 0}, + {"Zanabazar_Square", Var, 10}, + {"Zl", Var, 0}, + {"Zp", Var, 0}, + {"Zs", Var, 0}, + }, + "unicode/utf16": { + {"AppendRune", Func, 20}, + {"Decode", Func, 0}, + {"DecodeRune", Func, 0}, + {"Encode", Func, 0}, + {"EncodeRune", Func, 0}, + {"IsSurrogate", Func, 0}, + }, + "unicode/utf8": { + {"AppendRune", Func, 18}, + {"DecodeLastRune", Func, 0}, + {"DecodeLastRuneInString", Func, 0}, + {"DecodeRune", Func, 0}, + {"DecodeRuneInString", Func, 0}, + {"EncodeRune", Func, 0}, + {"FullRune", Func, 0}, + {"FullRuneInString", Func, 0}, + {"MaxRune", Const, 0}, + {"RuneCount", Func, 0}, + {"RuneCountInString", Func, 0}, + {"RuneError", Const, 0}, + {"RuneLen", Func, 0}, + {"RuneSelf", Const, 0}, + {"RuneStart", Func, 0}, + {"UTFMax", Const, 0}, + {"Valid", Func, 0}, + {"ValidRune", Func, 1}, + {"ValidString", Func, 0}, + }, + "unsafe": { + {"Add", Func, 0}, + {"Alignof", Func, 0}, + {"Offsetof", Func, 0}, + {"Pointer", Type, 0}, + {"Sizeof", Func, 0}, + {"Slice", Func, 0}, + {"SliceData", Func, 0}, + {"String", Func, 0}, + {"StringData", Func, 0}, + }, +} diff --git a/vendor/golang.org/x/tools/internal/stdlib/stdlib.go b/vendor/golang.org/x/tools/internal/stdlib/stdlib.go new file mode 100644 index 000000000000..98904017f2ca --- /dev/null +++ b/vendor/golang.org/x/tools/internal/stdlib/stdlib.go @@ -0,0 +1,97 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:generate go run generate.go + +// Package stdlib provides a table of all exported symbols in the +// standard library, along with the version at which they first +// appeared. +package stdlib + +import ( + "fmt" + "strings" +) + +type Symbol struct { + Name string + Kind Kind + Version Version // Go version that first included the symbol +} + +// A Kind indicates the kind of a symbol: +// function, variable, constant, type, and so on. +type Kind int8 + +const ( + Invalid Kind = iota // Example name: + Type // "Buffer" + Func // "Println" + Var // "EOF" + Const // "Pi" + Field // "Point.X" + Method // "(*Buffer).Grow" +) + +func (kind Kind) String() string { + return [...]string{ + Invalid: "invalid", + Type: "type", + Func: "func", + Var: "var", + Const: "const", + Field: "field", + Method: "method", + }[kind] +} + +// A Version represents a version of Go of the form "go1.%d". +type Version int8 + +// String returns a version string of the form "go1.23", without allocating. +func (v Version) String() string { return versions[v] } + +var versions [30]string // (increase constant as needed) + +func init() { + for i := range versions { + versions[i] = fmt.Sprintf("go1.%d", i) + } +} + +// HasPackage reports whether the specified package path is part of +// the standard library's public API. +func HasPackage(path string) bool { + _, ok := PackageSymbols[path] + return ok +} + +// SplitField splits the field symbol name into type and field +// components. It must be called only on Field symbols. +// +// Example: "File.Package" -> ("File", "Package") +func (sym *Symbol) SplitField() (typename, name string) { + if sym.Kind != Field { + panic("not a field") + } + typename, name, _ = strings.Cut(sym.Name, ".") + return +} + +// SplitMethod splits the method symbol name into pointer, receiver, +// and method components. It must be called only on Method symbols. +// +// Example: "(*Buffer).Grow" -> (true, "Buffer", "Grow") +func (sym *Symbol) SplitMethod() (ptr bool, recv, name string) { + if sym.Kind != Method { + panic("not a method") + } + recv, name, _ = strings.Cut(sym.Name, ".") + recv = recv[len("(") : len(recv)-len(")")] + ptr = recv[0] == '*' + if ptr { + recv = recv[len("*"):] + } + return +} diff --git a/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go b/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go index 7e638ec24fcb..ff9437a36cd6 100644 --- a/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go +++ b/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go @@ -34,30 +34,16 @@ func GetLines(file *token.File) []int { lines []int _ []struct{} } - type tokenFile118 struct { - _ *token.FileSet // deleted in go1.19 - tokenFile119 - } - - type uP = unsafe.Pointer - switch unsafe.Sizeof(*file) { - case unsafe.Sizeof(tokenFile118{}): - var ptr *tokenFile118 - *(*uP)(uP(&ptr)) = uP(file) - ptr.mu.Lock() - defer ptr.mu.Unlock() - return ptr.lines - case unsafe.Sizeof(tokenFile119{}): - var ptr *tokenFile119 - *(*uP)(uP(&ptr)) = uP(file) - ptr.mu.Lock() - defer ptr.mu.Unlock() - return ptr.lines - - default: + if unsafe.Sizeof(*file) != unsafe.Sizeof(tokenFile119{}) { panic("unexpected token.File size") } + var ptr *tokenFile119 + type uP = unsafe.Pointer + *(*uP)(uP(&ptr)) = uP(file) + ptr.mu.Lock() + defer ptr.mu.Unlock() + return ptr.lines } // AddExistingFiles adds the specified files to the FileSet if they diff --git a/vendor/golang.org/x/tools/internal/typeparams/common.go b/vendor/golang.org/x/tools/internal/typeparams/common.go deleted file mode 100644 index cdab9885314f..000000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/common.go +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package typeparams contains common utilities for writing tools that interact -// with generic Go code, as introduced with Go 1.18. -// -// Many of the types and functions in this package are proxies for the new APIs -// introduced in the standard library with Go 1.18. For example, the -// typeparams.Union type is an alias for go/types.Union, and the ForTypeSpec -// function returns the value of the go/ast.TypeSpec.TypeParams field. At Go -// versions older than 1.18 these helpers are implemented as stubs, allowing -// users of this package to write code that handles generic constructs inline, -// even if the Go version being used to compile does not support generics. -// -// Additionally, this package contains common utilities for working with the -// new generic constructs, to supplement the standard library APIs. Notably, -// the StructuralTerms API computes a minimal representation of the structural -// restrictions on a type parameter. -// -// An external version of these APIs is available in the -// golang.org/x/exp/typeparams module. -package typeparams - -import ( - "fmt" - "go/ast" - "go/token" - "go/types" -) - -// UnpackIndexExpr extracts data from AST nodes that represent index -// expressions. -// -// For an ast.IndexExpr, the resulting indices slice will contain exactly one -// index expression. For an ast.IndexListExpr (go1.18+), it may have a variable -// number of index expressions. -// -// For nodes that don't represent index expressions, the first return value of -// UnpackIndexExpr will be nil. -func UnpackIndexExpr(n ast.Node) (x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack token.Pos) { - switch e := n.(type) { - case *ast.IndexExpr: - return e.X, e.Lbrack, []ast.Expr{e.Index}, e.Rbrack - case *ast.IndexListExpr: - return e.X, e.Lbrack, e.Indices, e.Rbrack - } - return nil, token.NoPos, nil, token.NoPos -} - -// PackIndexExpr returns an *ast.IndexExpr or *ast.IndexListExpr, depending on -// the cardinality of indices. Calling PackIndexExpr with len(indices) == 0 -// will panic. -func PackIndexExpr(x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack token.Pos) ast.Expr { - switch len(indices) { - case 0: - panic("empty indices") - case 1: - return &ast.IndexExpr{ - X: x, - Lbrack: lbrack, - Index: indices[0], - Rbrack: rbrack, - } - default: - return &ast.IndexListExpr{ - X: x, - Lbrack: lbrack, - Indices: indices, - Rbrack: rbrack, - } - } -} - -// IsTypeParam reports whether t is a type parameter. -func IsTypeParam(t types.Type) bool { - _, ok := t.(*types.TypeParam) - return ok -} - -// OriginMethod returns the origin method associated with the method fn. -// For methods on a non-generic receiver base type, this is just -// fn. However, for methods with a generic receiver, OriginMethod returns the -// corresponding method in the method set of the origin type. -// -// As a special case, if fn is not a method (has no receiver), OriginMethod -// returns fn. -func OriginMethod(fn *types.Func) *types.Func { - recv := fn.Type().(*types.Signature).Recv() - if recv == nil { - return fn - } - base := recv.Type() - p, isPtr := base.(*types.Pointer) - if isPtr { - base = p.Elem() - } - named, isNamed := base.(*types.Named) - if !isNamed { - // Receiver is a *types.Interface. - return fn - } - if named.TypeParams().Len() == 0 { - // Receiver base has no type parameters, so we can avoid the lookup below. - return fn - } - orig := named.Origin() - gfn, _, _ := types.LookupFieldOrMethod(orig, true, fn.Pkg(), fn.Name()) - - // This is a fix for a gopls crash (#60628) due to a go/types bug (#60634). In: - // package p - // type T *int - // func (*T) f() {} - // LookupFieldOrMethod(T, true, p, f)=nil, but NewMethodSet(*T)={(*T).f}. - // Here we make them consistent by force. - // (The go/types bug is general, but this workaround is reached only - // for generic T thanks to the early return above.) - if gfn == nil { - mset := types.NewMethodSet(types.NewPointer(orig)) - for i := 0; i < mset.Len(); i++ { - m := mset.At(i) - if m.Obj().Id() == fn.Id() { - gfn = m.Obj() - break - } - } - } - - // In golang/go#61196, we observe another crash, this time inexplicable. - if gfn == nil { - panic(fmt.Sprintf("missing origin method for %s.%s; named == origin: %t, named.NumMethods(): %d, origin.NumMethods(): %d", named, fn, named == orig, named.NumMethods(), orig.NumMethods())) - } - - return gfn.(*types.Func) -} - -// GenericAssignableTo is a generalization of types.AssignableTo that -// implements the following rule for uninstantiated generic types: -// -// If V and T are generic named types, then V is considered assignable to T if, -// for every possible instantation of V[A_1, ..., A_N], the instantiation -// T[A_1, ..., A_N] is valid and V[A_1, ..., A_N] implements T[A_1, ..., A_N]. -// -// If T has structural constraints, they must be satisfied by V. -// -// For example, consider the following type declarations: -// -// type Interface[T any] interface { -// Accept(T) -// } -// -// type Container[T any] struct { -// Element T -// } -// -// func (c Container[T]) Accept(t T) { c.Element = t } -// -// In this case, GenericAssignableTo reports that instantiations of Container -// are assignable to the corresponding instantiation of Interface. -func GenericAssignableTo(ctxt *types.Context, V, T types.Type) bool { - // If V and T are not both named, or do not have matching non-empty type - // parameter lists, fall back on types.AssignableTo. - - VN, Vnamed := V.(*types.Named) - TN, Tnamed := T.(*types.Named) - if !Vnamed || !Tnamed { - return types.AssignableTo(V, T) - } - - vtparams := VN.TypeParams() - ttparams := TN.TypeParams() - if vtparams.Len() == 0 || vtparams.Len() != ttparams.Len() || VN.TypeArgs().Len() != 0 || TN.TypeArgs().Len() != 0 { - return types.AssignableTo(V, T) - } - - // V and T have the same (non-zero) number of type params. Instantiate both - // with the type parameters of V. This must always succeed for V, and will - // succeed for T if and only if the type set of each type parameter of V is a - // subset of the type set of the corresponding type parameter of T, meaning - // that every instantiation of V corresponds to a valid instantiation of T. - - // Minor optimization: ensure we share a context across the two - // instantiations below. - if ctxt == nil { - ctxt = types.NewContext() - } - - var targs []types.Type - for i := 0; i < vtparams.Len(); i++ { - targs = append(targs, vtparams.At(i)) - } - - vinst, err := types.Instantiate(ctxt, V, targs, true) - if err != nil { - panic("type parameters should satisfy their own constraints") - } - - tinst, err := types.Instantiate(ctxt, T, targs, true) - if err != nil { - return false - } - - return types.AssignableTo(vinst, tinst) -} diff --git a/vendor/golang.org/x/tools/internal/typeparams/coretype.go b/vendor/golang.org/x/tools/internal/typeparams/coretype.go deleted file mode 100644 index 7ea8840eab7c..000000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/coretype.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package typeparams - -import ( - "go/types" -) - -// CoreType returns the core type of T or nil if T does not have a core type. -// -// See https://go.dev/ref/spec#Core_types for the definition of a core type. -func CoreType(T types.Type) types.Type { - U := T.Underlying() - if _, ok := U.(*types.Interface); !ok { - return U // for non-interface types, - } - - terms, err := _NormalTerms(U) - if len(terms) == 0 || err != nil { - // len(terms) -> empty type set of interface. - // err != nil => U is invalid, exceeds complexity bounds, or has an empty type set. - return nil // no core type. - } - - U = terms[0].Type().Underlying() - var identical int // i in [0,identical) => Identical(U, terms[i].Type().Underlying()) - for identical = 1; identical < len(terms); identical++ { - if !types.Identical(U, terms[identical].Type().Underlying()) { - break - } - } - - if identical == len(terms) { - // https://go.dev/ref/spec#Core_types - // "There is a single type U which is the underlying type of all types in the type set of T" - return U - } - ch, ok := U.(*types.Chan) - if !ok { - return nil // no core type as identical < len(terms) and U is not a channel. - } - // https://go.dev/ref/spec#Core_types - // "the type chan E if T contains only bidirectional channels, or the type chan<- E or - // <-chan E depending on the direction of the directional channels present." - for chans := identical; chans < len(terms); chans++ { - curr, ok := terms[chans].Type().Underlying().(*types.Chan) - if !ok { - return nil - } - if !types.Identical(ch.Elem(), curr.Elem()) { - return nil // channel elements are not identical. - } - if ch.Dir() == types.SendRecv { - // ch is bidirectional. We can safely always use curr's direction. - ch = curr - } else if curr.Dir() != types.SendRecv && ch.Dir() != curr.Dir() { - // ch and curr are not bidirectional and not the same direction. - return nil - } - } - return ch -} - -// _NormalTerms returns a slice of terms representing the normalized structural -// type restrictions of a type, if any. -// -// For all types other than *types.TypeParam, *types.Interface, and -// *types.Union, this is just a single term with Tilde() == false and -// Type() == typ. For *types.TypeParam, *types.Interface, and *types.Union, see -// below. -// -// Structural type restrictions of a type parameter are created via -// non-interface types embedded in its constraint interface (directly, or via a -// chain of interface embeddings). For example, in the declaration type -// T[P interface{~int; m()}] int the structural restriction of the type -// parameter P is ~int. -// -// With interface embedding and unions, the specification of structural type -// restrictions may be arbitrarily complex. For example, consider the -// following: -// -// type A interface{ ~string|~[]byte } -// -// type B interface{ int|string } -// -// type C interface { ~string|~int } -// -// type T[P interface{ A|B; C }] int -// -// In this example, the structural type restriction of P is ~string|int: A|B -// expands to ~string|~[]byte|int|string, which reduces to ~string|~[]byte|int, -// which when intersected with C (~string|~int) yields ~string|int. -// -// _NormalTerms computes these expansions and reductions, producing a -// "normalized" form of the embeddings. A structural restriction is normalized -// if it is a single union containing no interface terms, and is minimal in the -// sense that removing any term changes the set of types satisfying the -// constraint. It is left as a proof for the reader that, modulo sorting, there -// is exactly one such normalized form. -// -// Because the minimal representation always takes this form, _NormalTerms -// returns a slice of tilde terms corresponding to the terms of the union in -// the normalized structural restriction. An error is returned if the type is -// invalid, exceeds complexity bounds, or has an empty type set. In the latter -// case, _NormalTerms returns ErrEmptyTypeSet. -// -// _NormalTerms makes no guarantees about the order of terms, except that it -// is deterministic. -func _NormalTerms(typ types.Type) ([]*types.Term, error) { - switch typ := typ.(type) { - case *types.TypeParam: - return StructuralTerms(typ) - case *types.Union: - return UnionTermSet(typ) - case *types.Interface: - return InterfaceTermSet(typ) - default: - return []*types.Term{types.NewTerm(false, typ)}, nil - } -} diff --git a/vendor/golang.org/x/tools/internal/typeparams/normalize.go b/vendor/golang.org/x/tools/internal/typeparams/normalize.go deleted file mode 100644 index 93c80fdc96ce..000000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/normalize.go +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package typeparams - -import ( - "errors" - "fmt" - "go/types" - "os" - "strings" -) - -//go:generate go run copytermlist.go - -const debug = false - -var ErrEmptyTypeSet = errors.New("empty type set") - -// StructuralTerms returns a slice of terms representing the normalized -// structural type restrictions of a type parameter, if any. -// -// Structural type restrictions of a type parameter are created via -// non-interface types embedded in its constraint interface (directly, or via a -// chain of interface embeddings). For example, in the declaration -// -// type T[P interface{~int; m()}] int -// -// the structural restriction of the type parameter P is ~int. -// -// With interface embedding and unions, the specification of structural type -// restrictions may be arbitrarily complex. For example, consider the -// following: -// -// type A interface{ ~string|~[]byte } -// -// type B interface{ int|string } -// -// type C interface { ~string|~int } -// -// type T[P interface{ A|B; C }] int -// -// In this example, the structural type restriction of P is ~string|int: A|B -// expands to ~string|~[]byte|int|string, which reduces to ~string|~[]byte|int, -// which when intersected with C (~string|~int) yields ~string|int. -// -// StructuralTerms computes these expansions and reductions, producing a -// "normalized" form of the embeddings. A structural restriction is normalized -// if it is a single union containing no interface terms, and is minimal in the -// sense that removing any term changes the set of types satisfying the -// constraint. It is left as a proof for the reader that, modulo sorting, there -// is exactly one such normalized form. -// -// Because the minimal representation always takes this form, StructuralTerms -// returns a slice of tilde terms corresponding to the terms of the union in -// the normalized structural restriction. An error is returned if the -// constraint interface is invalid, exceeds complexity bounds, or has an empty -// type set. In the latter case, StructuralTerms returns ErrEmptyTypeSet. -// -// StructuralTerms makes no guarantees about the order of terms, except that it -// is deterministic. -func StructuralTerms(tparam *types.TypeParam) ([]*types.Term, error) { - constraint := tparam.Constraint() - if constraint == nil { - return nil, fmt.Errorf("%s has nil constraint", tparam) - } - iface, _ := constraint.Underlying().(*types.Interface) - if iface == nil { - return nil, fmt.Errorf("constraint is %T, not *types.Interface", constraint.Underlying()) - } - return InterfaceTermSet(iface) -} - -// InterfaceTermSet computes the normalized terms for a constraint interface, -// returning an error if the term set cannot be computed or is empty. In the -// latter case, the error will be ErrEmptyTypeSet. -// -// See the documentation of StructuralTerms for more information on -// normalization. -func InterfaceTermSet(iface *types.Interface) ([]*types.Term, error) { - return computeTermSet(iface) -} - -// UnionTermSet computes the normalized terms for a union, returning an error -// if the term set cannot be computed or is empty. In the latter case, the -// error will be ErrEmptyTypeSet. -// -// See the documentation of StructuralTerms for more information on -// normalization. -func UnionTermSet(union *types.Union) ([]*types.Term, error) { - return computeTermSet(union) -} - -func computeTermSet(typ types.Type) ([]*types.Term, error) { - tset, err := computeTermSetInternal(typ, make(map[types.Type]*termSet), 0) - if err != nil { - return nil, err - } - if tset.terms.isEmpty() { - return nil, ErrEmptyTypeSet - } - if tset.terms.isAll() { - return nil, nil - } - var terms []*types.Term - for _, term := range tset.terms { - terms = append(terms, types.NewTerm(term.tilde, term.typ)) - } - return terms, nil -} - -// A termSet holds the normalized set of terms for a given type. -// -// The name termSet is intentionally distinct from 'type set': a type set is -// all types that implement a type (and includes method restrictions), whereas -// a term set just represents the structural restrictions on a type. -type termSet struct { - complete bool - terms termlist -} - -func indentf(depth int, format string, args ...interface{}) { - fmt.Fprintf(os.Stderr, strings.Repeat(".", depth)+format+"\n", args...) -} - -func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth int) (res *termSet, err error) { - if t == nil { - panic("nil type") - } - - if debug { - indentf(depth, "%s", t.String()) - defer func() { - if err != nil { - indentf(depth, "=> %s", err) - } else { - indentf(depth, "=> %s", res.terms.String()) - } - }() - } - - const maxTermCount = 100 - if tset, ok := seen[t]; ok { - if !tset.complete { - return nil, fmt.Errorf("cycle detected in the declaration of %s", t) - } - return tset, nil - } - - // Mark the current type as seen to avoid infinite recursion. - tset := new(termSet) - defer func() { - tset.complete = true - }() - seen[t] = tset - - switch u := t.Underlying().(type) { - case *types.Interface: - // The term set of an interface is the intersection of the term sets of its - // embedded types. - tset.terms = allTermlist - for i := 0; i < u.NumEmbeddeds(); i++ { - embedded := u.EmbeddedType(i) - if _, ok := embedded.Underlying().(*types.TypeParam); ok { - return nil, fmt.Errorf("invalid embedded type %T", embedded) - } - tset2, err := computeTermSetInternal(embedded, seen, depth+1) - if err != nil { - return nil, err - } - tset.terms = tset.terms.intersect(tset2.terms) - } - case *types.Union: - // The term set of a union is the union of term sets of its terms. - tset.terms = nil - for i := 0; i < u.Len(); i++ { - t := u.Term(i) - var terms termlist - switch t.Type().Underlying().(type) { - case *types.Interface: - tset2, err := computeTermSetInternal(t.Type(), seen, depth+1) - if err != nil { - return nil, err - } - terms = tset2.terms - case *types.TypeParam, *types.Union: - // A stand-alone type parameter or union is not permitted as union - // term. - return nil, fmt.Errorf("invalid union term %T", t) - default: - if t.Type() == types.Typ[types.Invalid] { - continue - } - terms = termlist{{t.Tilde(), t.Type()}} - } - tset.terms = tset.terms.union(terms) - if len(tset.terms) > maxTermCount { - return nil, fmt.Errorf("exceeded max term count %d", maxTermCount) - } - } - case *types.TypeParam: - panic("unreachable") - default: - // For all other types, the term set is just a single non-tilde term - // holding the type itself. - if u != types.Typ[types.Invalid] { - tset.terms = termlist{{false, t}} - } - } - return tset, nil -} - -// under is a facade for the go/types internal function of the same name. It is -// used by typeterm.go. -func under(t types.Type) types.Type { - return t.Underlying() -} diff --git a/vendor/golang.org/x/tools/internal/typeparams/termlist.go b/vendor/golang.org/x/tools/internal/typeparams/termlist.go deleted file mode 100644 index cbd12f801314..000000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/termlist.go +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Code generated by copytermlist.go DO NOT EDIT. - -package typeparams - -import ( - "bytes" - "go/types" -) - -// A termlist represents the type set represented by the union -// t1 ∪ y2 ∪ ... tn of the type sets of the terms t1 to tn. -// A termlist is in normal form if all terms are disjoint. -// termlist operations don't require the operands to be in -// normal form. -type termlist []*term - -// allTermlist represents the set of all types. -// It is in normal form. -var allTermlist = termlist{new(term)} - -// String prints the termlist exactly (without normalization). -func (xl termlist) String() string { - if len(xl) == 0 { - return "∅" - } - var buf bytes.Buffer - for i, x := range xl { - if i > 0 { - buf.WriteString(" | ") - } - buf.WriteString(x.String()) - } - return buf.String() -} - -// isEmpty reports whether the termlist xl represents the empty set of types. -func (xl termlist) isEmpty() bool { - // If there's a non-nil term, the entire list is not empty. - // If the termlist is in normal form, this requires at most - // one iteration. - for _, x := range xl { - if x != nil { - return false - } - } - return true -} - -// isAll reports whether the termlist xl represents the set of all types. -func (xl termlist) isAll() bool { - // If there's a 𝓤 term, the entire list is 𝓤. - // If the termlist is in normal form, this requires at most - // one iteration. - for _, x := range xl { - if x != nil && x.typ == nil { - return true - } - } - return false -} - -// norm returns the normal form of xl. -func (xl termlist) norm() termlist { - // Quadratic algorithm, but good enough for now. - // TODO(gri) fix asymptotic performance - used := make([]bool, len(xl)) - var rl termlist - for i, xi := range xl { - if xi == nil || used[i] { - continue - } - for j := i + 1; j < len(xl); j++ { - xj := xl[j] - if xj == nil || used[j] { - continue - } - if u1, u2 := xi.union(xj); u2 == nil { - // If we encounter a 𝓤 term, the entire list is 𝓤. - // Exit early. - // (Note that this is not just an optimization; - // if we continue, we may end up with a 𝓤 term - // and other terms and the result would not be - // in normal form.) - if u1.typ == nil { - return allTermlist - } - xi = u1 - used[j] = true // xj is now unioned into xi - ignore it in future iterations - } - } - rl = append(rl, xi) - } - return rl -} - -// union returns the union xl ∪ yl. -func (xl termlist) union(yl termlist) termlist { - return append(xl, yl...).norm() -} - -// intersect returns the intersection xl ∩ yl. -func (xl termlist) intersect(yl termlist) termlist { - if xl.isEmpty() || yl.isEmpty() { - return nil - } - - // Quadratic algorithm, but good enough for now. - // TODO(gri) fix asymptotic performance - var rl termlist - for _, x := range xl { - for _, y := range yl { - if r := x.intersect(y); r != nil { - rl = append(rl, r) - } - } - } - return rl.norm() -} - -// equal reports whether xl and yl represent the same type set. -func (xl termlist) equal(yl termlist) bool { - // TODO(gri) this should be more efficient - return xl.subsetOf(yl) && yl.subsetOf(xl) -} - -// includes reports whether t ∈ xl. -func (xl termlist) includes(t types.Type) bool { - for _, x := range xl { - if x.includes(t) { - return true - } - } - return false -} - -// supersetOf reports whether y ⊆ xl. -func (xl termlist) supersetOf(y *term) bool { - for _, x := range xl { - if y.subsetOf(x) { - return true - } - } - return false -} - -// subsetOf reports whether xl ⊆ yl. -func (xl termlist) subsetOf(yl termlist) bool { - if yl.isEmpty() { - return xl.isEmpty() - } - - // each term x of xl must be a subset of yl - for _, x := range xl { - if !yl.supersetOf(x) { - return false // x is not a subset yl - } - } - return true -} diff --git a/vendor/golang.org/x/tools/internal/typeparams/typeterm.go b/vendor/golang.org/x/tools/internal/typeparams/typeterm.go deleted file mode 100644 index 7350bb702a17..000000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/typeterm.go +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Code generated by copytermlist.go DO NOT EDIT. - -package typeparams - -import "go/types" - -// A term describes elementary type sets: -// -// ∅: (*term)(nil) == ∅ // set of no types (empty set) -// 𝓤: &term{} == 𝓤 // set of all types (𝓤niverse) -// T: &term{false, T} == {T} // set of type T -// ~t: &term{true, t} == {t' | under(t') == t} // set of types with underlying type t -type term struct { - tilde bool // valid if typ != nil - typ types.Type -} - -func (x *term) String() string { - switch { - case x == nil: - return "∅" - case x.typ == nil: - return "𝓤" - case x.tilde: - return "~" + x.typ.String() - default: - return x.typ.String() - } -} - -// equal reports whether x and y represent the same type set. -func (x *term) equal(y *term) bool { - // easy cases - switch { - case x == nil || y == nil: - return x == y - case x.typ == nil || y.typ == nil: - return x.typ == y.typ - } - // ∅ ⊂ x, y ⊂ 𝓤 - - return x.tilde == y.tilde && types.Identical(x.typ, y.typ) -} - -// union returns the union x ∪ y: zero, one, or two non-nil terms. -func (x *term) union(y *term) (_, _ *term) { - // easy cases - switch { - case x == nil && y == nil: - return nil, nil // ∅ ∪ ∅ == ∅ - case x == nil: - return y, nil // ∅ ∪ y == y - case y == nil: - return x, nil // x ∪ ∅ == x - case x.typ == nil: - return x, nil // 𝓤 ∪ y == 𝓤 - case y.typ == nil: - return y, nil // x ∪ 𝓤 == 𝓤 - } - // ∅ ⊂ x, y ⊂ 𝓤 - - if x.disjoint(y) { - return x, y // x ∪ y == (x, y) if x ∩ y == ∅ - } - // x.typ == y.typ - - // ~t ∪ ~t == ~t - // ~t ∪ T == ~t - // T ∪ ~t == ~t - // T ∪ T == T - if x.tilde || !y.tilde { - return x, nil - } - return y, nil -} - -// intersect returns the intersection x ∩ y. -func (x *term) intersect(y *term) *term { - // easy cases - switch { - case x == nil || y == nil: - return nil // ∅ ∩ y == ∅ and ∩ ∅ == ∅ - case x.typ == nil: - return y // 𝓤 ∩ y == y - case y.typ == nil: - return x // x ∩ 𝓤 == x - } - // ∅ ⊂ x, y ⊂ 𝓤 - - if x.disjoint(y) { - return nil // x ∩ y == ∅ if x ∩ y == ∅ - } - // x.typ == y.typ - - // ~t ∩ ~t == ~t - // ~t ∩ T == T - // T ∩ ~t == T - // T ∩ T == T - if !x.tilde || y.tilde { - return x - } - return y -} - -// includes reports whether t ∈ x. -func (x *term) includes(t types.Type) bool { - // easy cases - switch { - case x == nil: - return false // t ∈ ∅ == false - case x.typ == nil: - return true // t ∈ 𝓤 == true - } - // ∅ ⊂ x ⊂ 𝓤 - - u := t - if x.tilde { - u = under(u) - } - return types.Identical(x.typ, u) -} - -// subsetOf reports whether x ⊆ y. -func (x *term) subsetOf(y *term) bool { - // easy cases - switch { - case x == nil: - return true // ∅ ⊆ y == true - case y == nil: - return false // x ⊆ ∅ == false since x != ∅ - case y.typ == nil: - return true // x ⊆ 𝓤 == true - case x.typ == nil: - return false // 𝓤 ⊆ y == false since y != 𝓤 - } - // ∅ ⊂ x, y ⊂ 𝓤 - - if x.disjoint(y) { - return false // x ⊆ y == false if x ∩ y == ∅ - } - // x.typ == y.typ - - // ~t ⊆ ~t == true - // ~t ⊆ T == false - // T ⊆ ~t == true - // T ⊆ T == true - return !x.tilde || y.tilde -} - -// disjoint reports whether x ∩ y == ∅. -// x.typ and y.typ must not be nil. -func (x *term) disjoint(y *term) bool { - if debug && (x.typ == nil || y.typ == nil) { - panic("invalid argument(s)") - } - ux := x.typ - if y.tilde { - ux = under(ux) - } - uy := y.typ - if x.tilde { - uy = under(uy) - } - return !types.Identical(ux, uy) -} diff --git a/vendor/golang.org/x/tools/internal/typesinternal/errorcode.go b/vendor/golang.org/x/tools/internal/typesinternal/errorcode.go index 07484073a57d..e0c27ed251c9 100644 --- a/vendor/golang.org/x/tools/internal/typesinternal/errorcode.go +++ b/vendor/golang.org/x/tools/internal/typesinternal/errorcode.go @@ -167,7 +167,7 @@ const ( UntypedNilUse // WrongAssignCount occurs when the number of values on the right-hand side - // of an assignment or or initialization expression does not match the number + // of an assignment or initialization expression does not match the number // of variables on the left-hand side. // // Example: diff --git a/vendor/golang.org/x/tools/internal/typesinternal/recv.go b/vendor/golang.org/x/tools/internal/typesinternal/recv.go new file mode 100644 index 000000000000..fea7c8b75e8e --- /dev/null +++ b/vendor/golang.org/x/tools/internal/typesinternal/recv.go @@ -0,0 +1,43 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package typesinternal + +import ( + "go/types" + + "golang.org/x/tools/internal/aliases" +) + +// ReceiverNamed returns the named type (if any) associated with the +// type of recv, which may be of the form N or *N, or aliases thereof. +// It also reports whether a Pointer was present. +func ReceiverNamed(recv *types.Var) (isPtr bool, named *types.Named) { + t := recv.Type() + if ptr, ok := aliases.Unalias(t).(*types.Pointer); ok { + isPtr = true + t = ptr.Elem() + } + named, _ = aliases.Unalias(t).(*types.Named) + return +} + +// Unpointer returns T given *T or an alias thereof. +// For all other types it is the identity function. +// It does not look at underlying types. +// The result may be an alias. +// +// Use this function to strip off the optional pointer on a receiver +// in a field or method selection, without losing the named type +// (which is needed to compute the method set). +// +// See also [typeparams.MustDeref], which removes one level of +// indirection from the type, regardless of named types (analogous to +// a LOAD instruction). +func Unpointer(t types.Type) types.Type { + if ptr, ok := aliases.Unalias(t).(*types.Pointer); ok { + return ptr.Elem() + } + return t +} diff --git a/vendor/golang.org/x/tools/internal/typesinternal/toonew.go b/vendor/golang.org/x/tools/internal/typesinternal/toonew.go new file mode 100644 index 000000000000..cc86487eaa0a --- /dev/null +++ b/vendor/golang.org/x/tools/internal/typesinternal/toonew.go @@ -0,0 +1,89 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package typesinternal + +import ( + "go/types" + + "golang.org/x/tools/internal/stdlib" + "golang.org/x/tools/internal/versions" +) + +// TooNewStdSymbols computes the set of package-level symbols +// exported by pkg that are not available at the specified version. +// The result maps each symbol to its minimum version. +// +// The pkg is allowed to contain type errors. +func TooNewStdSymbols(pkg *types.Package, version string) map[types.Object]string { + disallowed := make(map[types.Object]string) + + // Pass 1: package-level symbols. + symbols := stdlib.PackageSymbols[pkg.Path()] + for _, sym := range symbols { + symver := sym.Version.String() + if versions.Before(version, symver) { + switch sym.Kind { + case stdlib.Func, stdlib.Var, stdlib.Const, stdlib.Type: + disallowed[pkg.Scope().Lookup(sym.Name)] = symver + } + } + } + + // Pass 2: fields and methods. + // + // We allow fields and methods if their associated type is + // disallowed, as otherwise we would report false positives + // for compatibility shims. Consider: + // + // //go:build go1.22 + // type T struct { F std.Real } // correct new API + // + // //go:build !go1.22 + // type T struct { F fake } // shim + // type fake struct { ... } + // func (fake) M () {} + // + // These alternative declarations of T use either the std.Real + // type, introduced in go1.22, or a fake type, for the field + // F. (The fakery could be arbitrarily deep, involving more + // nested fields and methods than are shown here.) Clients + // that use the compatibility shim T will compile with any + // version of go, whether older or newer than go1.22, but only + // the newer version will use the std.Real implementation. + // + // Now consider a reference to method M in new(T).F.M() in a + // module that requires a minimum of go1.21. The analysis may + // occur using a version of Go higher than 1.21, selecting the + // first version of T, so the method M is Real.M. This would + // spuriously cause the analyzer to report a reference to a + // too-new symbol even though this expression compiles just + // fine (with the fake implementation) using go1.21. + for _, sym := range symbols { + symVersion := sym.Version.String() + if !versions.Before(version, symVersion) { + continue // allowed + } + + var obj types.Object + switch sym.Kind { + case stdlib.Field: + typename, name := sym.SplitField() + if t := pkg.Scope().Lookup(typename); t != nil && disallowed[t] == "" { + obj, _, _ = types.LookupFieldOrMethod(t.Type(), false, pkg, name) + } + + case stdlib.Method: + ptr, recvname, name := sym.SplitMethod() + if t := pkg.Scope().Lookup(recvname); t != nil && disallowed[t] == "" { + obj, _, _ = types.LookupFieldOrMethod(t.Type(), ptr, pkg, name) + } + } + if obj != nil { + disallowed[obj] = symVersion + } + } + + return disallowed +} diff --git a/vendor/golang.org/x/tools/internal/typesinternal/types.go b/vendor/golang.org/x/tools/internal/typesinternal/types.go index ce7d4351b220..7c77c2fbc038 100644 --- a/vendor/golang.org/x/tools/internal/typesinternal/types.go +++ b/vendor/golang.org/x/tools/internal/typesinternal/types.go @@ -48,5 +48,3 @@ func ReadGo116ErrorData(err types.Error) (code ErrorCode, start, end token.Pos, } return ErrorCode(data[0]), token.Pos(data[1]), token.Pos(data[2]), true } - -var SetGoVersion = func(conf *types.Config, version string) bool { return false } diff --git a/vendor/golang.org/x/tools/internal/typesinternal/types_118.go b/vendor/golang.org/x/tools/internal/typesinternal/types_118.go deleted file mode 100644 index a42b072a67d3..000000000000 --- a/vendor/golang.org/x/tools/internal/typesinternal/types_118.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.18 -// +build go1.18 - -package typesinternal - -import ( - "go/types" -) - -func init() { - SetGoVersion = func(conf *types.Config, version string) bool { - conf.GoVersion = version - return true - } -} diff --git a/vendor/golang.org/x/tools/internal/versions/features.go b/vendor/golang.org/x/tools/internal/versions/features.go new file mode 100644 index 000000000000..b53f17861613 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/versions/features.go @@ -0,0 +1,43 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package versions + +// This file contains predicates for working with file versions to +// decide when a tool should consider a language feature enabled. + +// GoVersions that features in x/tools can be gated to. +const ( + Go1_18 = "go1.18" + Go1_19 = "go1.19" + Go1_20 = "go1.20" + Go1_21 = "go1.21" + Go1_22 = "go1.22" +) + +// Future is an invalid unknown Go version sometime in the future. +// Do not use directly with Compare. +const Future = "" + +// AtLeast reports whether the file version v comes after a Go release. +// +// Use this predicate to enable a behavior once a certain Go release +// has happened (and stays enabled in the future). +func AtLeast(v, release string) bool { + if v == Future { + return true // an unknown future version is always after y. + } + return Compare(Lang(v), Lang(release)) >= 0 +} + +// Before reports whether the file version v is strictly before a Go release. +// +// Use this predicate to disable a behavior once a certain Go release +// has happened (and stays enabled in the future). +func Before(v, release string) bool { + if v == Future { + return false // an unknown future version happens after y. + } + return Compare(Lang(v), Lang(release)) < 0 +} diff --git a/vendor/golang.org/x/tools/internal/versions/toolchain.go b/vendor/golang.org/x/tools/internal/versions/toolchain.go new file mode 100644 index 000000000000..377bf7a53b4a --- /dev/null +++ b/vendor/golang.org/x/tools/internal/versions/toolchain.go @@ -0,0 +1,14 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package versions + +// toolchain is maximum version (<1.22) that the go toolchain used +// to build the current tool is known to support. +// +// When a tool is built with >=1.22, the value of toolchain is unused. +// +// x/tools does not support building with go <1.18. So we take this +// as the minimum possible maximum. +var toolchain string = Go1_18 diff --git a/vendor/golang.org/x/tools/internal/versions/toolchain_go119.go b/vendor/golang.org/x/tools/internal/versions/toolchain_go119.go new file mode 100644 index 000000000000..f65beed9d832 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/versions/toolchain_go119.go @@ -0,0 +1,14 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.19 +// +build go1.19 + +package versions + +func init() { + if Compare(toolchain, Go1_19) < 0 { + toolchain = Go1_19 + } +} diff --git a/vendor/golang.org/x/tools/internal/versions/toolchain_go120.go b/vendor/golang.org/x/tools/internal/versions/toolchain_go120.go new file mode 100644 index 000000000000..1a9efa126cdf --- /dev/null +++ b/vendor/golang.org/x/tools/internal/versions/toolchain_go120.go @@ -0,0 +1,14 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.20 +// +build go1.20 + +package versions + +func init() { + if Compare(toolchain, Go1_20) < 0 { + toolchain = Go1_20 + } +} diff --git a/vendor/golang.org/x/tools/internal/versions/toolchain_go121.go b/vendor/golang.org/x/tools/internal/versions/toolchain_go121.go new file mode 100644 index 000000000000..b7ef216dfecf --- /dev/null +++ b/vendor/golang.org/x/tools/internal/versions/toolchain_go121.go @@ -0,0 +1,14 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.21 +// +build go1.21 + +package versions + +func init() { + if Compare(toolchain, Go1_21) < 0 { + toolchain = Go1_21 + } +} diff --git a/vendor/golang.org/x/tools/internal/versions/types_go121.go b/vendor/golang.org/x/tools/internal/versions/types_go121.go index a7b79207aeeb..b4345d3349e5 100644 --- a/vendor/golang.org/x/tools/internal/versions/types_go121.go +++ b/vendor/golang.org/x/tools/internal/versions/types_go121.go @@ -12,9 +12,19 @@ import ( "go/types" ) -// FileVersions always reports the a file's Go version as the -// zero version at this Go version. -func FileVersions(info *types.Info, file *ast.File) string { return "" } +// FileVersion returns a language version (<=1.21) derived from runtime.Version() +// or an unknown future version. +func FileVersion(info *types.Info, file *ast.File) string { + // In x/tools built with Go <= 1.21, we do not have Info.FileVersions + // available. We use a go version derived from the toolchain used to + // compile the tool by default. + // This will be <= go1.21. We take this as the maximum version that + // this tool can support. + // + // There are no features currently in x/tools that need to tell fine grained + // differences for versions <1.22. + return toolchain +} -// InitFileVersions is a noop at this Go version. +// InitFileVersions is a noop when compiled with this Go version. func InitFileVersions(*types.Info) {} diff --git a/vendor/golang.org/x/tools/internal/versions/types_go122.go b/vendor/golang.org/x/tools/internal/versions/types_go122.go index 7b9ba89a8220..e8180632a526 100644 --- a/vendor/golang.org/x/tools/internal/versions/types_go122.go +++ b/vendor/golang.org/x/tools/internal/versions/types_go122.go @@ -12,10 +12,27 @@ import ( "go/types" ) -// FileVersions maps a file to the file's semantic Go version. -// The reported version is the zero version if a version cannot be determined. -func FileVersions(info *types.Info, file *ast.File) string { - return info.FileVersions[file] +// FileVersions returns a file's Go version. +// The reported version is an unknown Future version if a +// version cannot be determined. +func FileVersion(info *types.Info, file *ast.File) string { + // In tools built with Go >= 1.22, the Go version of a file + // follow a cascades of sources: + // 1) types.Info.FileVersion, which follows the cascade: + // 1.a) file version (ast.File.GoVersion), + // 1.b) the package version (types.Config.GoVersion), or + // 2) is some unknown Future version. + // + // File versions require a valid package version to be provided to types + // in Config.GoVersion. Config.GoVersion is either from the package's module + // or the toolchain (go run). This value should be provided by go/packages + // or unitchecker.Config.GoVersion. + if v := info.FileVersions[file]; IsValid(v) { + return v + } + // Note: we could instead return runtime.Version() [if valid]. + // This would act as a max version on what a tool can support. + return Future } // InitFileVersions initializes info to record Go versions for Go files. diff --git a/vendor/golang.org/x/tools/internal/versions/versions.go b/vendor/golang.org/x/tools/internal/versions/versions.go index e16f6c33a523..8d1f7453dbfc 100644 --- a/vendor/golang.org/x/tools/internal/versions/versions.go +++ b/vendor/golang.org/x/tools/internal/versions/versions.go @@ -4,6 +4,10 @@ package versions +import ( + "strings" +) + // Note: If we use build tags to use go/versions when go >=1.22, // we run into go.dev/issue/53737. Under some operations users would see an // import of "go/versions" even if they would not compile the file. @@ -45,6 +49,7 @@ func IsValid(x string) bool { return isValid(stripGo(x)) } // stripGo converts from a "go1.21" version to a "1.21" version. // If v does not start with "go", stripGo returns the empty string (a known invalid version). func stripGo(v string) string { + v, _, _ = strings.Cut(v, "-") // strip -bigcorp suffix. if len(v) < 2 || v[:2] != "go" { return "" } diff --git a/vendor/k8s.io/kube-openapi/pkg/generators/openapi.go b/vendor/k8s.io/kube-openapi/pkg/generators/openapi.go index 743f5b8b2e1a..1ffcf9094913 100644 --- a/vendor/k8s.io/kube-openapi/pkg/generators/openapi.go +++ b/vendor/k8s.io/kube-openapi/pkg/generators/openapi.go @@ -704,7 +704,7 @@ func defaultFromComments(comments []string, commentPath string, t *types.Type) ( var i interface{} if id, ok := parseSymbolReference(tag, commentPath); ok { - klog.Errorf("%v, %v", id, commentPath) + klog.V(5).Infof("%v, %v", id, commentPath) return nil, &id, nil } else if err := json.Unmarshal([]byte(tag), &i); err != nil { return nil, nil, fmt.Errorf("failed to unmarshal default: %v", err) @@ -844,15 +844,9 @@ func (g openAPITypeWriter) generateDescription(CommentLines []string) { } } - postDoc := strings.TrimLeft(buffer.String(), "\n") - postDoc = strings.TrimRight(postDoc, "\n") - postDoc = strings.Replace(postDoc, "\\\"", "\"", -1) // replace user's \" to " - postDoc = strings.Replace(postDoc, "\"", "\\\"", -1) // Escape " - postDoc = strings.Replace(postDoc, "\n", "\\n", -1) - postDoc = strings.Replace(postDoc, "\t", "\\t", -1) - postDoc = strings.Trim(postDoc, " ") - if postDoc != "" { - g.Do("Description: \"$.$\",\n", postDoc) + postDoc := strings.TrimSpace(buffer.String()) + if len(postDoc) > 0 { + g.Do("Description: $.$,\n", fmt.Sprintf("%#v", postDoc)) } } diff --git a/vendor/k8s.io/kubectl/pkg/cmd/annotate/annotate.go b/vendor/k8s.io/kubectl/pkg/cmd/annotate/annotate.go new file mode 100644 index 000000000000..aeeb5cea372f --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/cmd/annotate/annotate.go @@ -0,0 +1,485 @@ +/* +Copyright 2014 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 annotate + +import ( + "bytes" + "fmt" + "io" + + jsonpatch "github.com/evanphx/json-patch" + "github.com/spf13/cobra" + "k8s.io/klog/v2" + + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructuredscheme" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/json" + + "k8s.io/client-go/tools/clientcmd" + + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/genericiooptions" + "k8s.io/cli-runtime/pkg/printers" + "k8s.io/cli-runtime/pkg/resource" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/polymorphichelpers" + "k8s.io/kubectl/pkg/scheme" + "k8s.io/kubectl/pkg/util/completion" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/templates" +) + +// AnnotateFlags directly reflect the information that CLI is gathering via flags. They will be converted to Options, which +// reflect the runtime requirements for the command. This structure reduces the transformation to wiring and makes +// the logic itself easy to unit test +type AnnotateFlags struct { + // Common user flags + All bool + AllNamespaces bool + DryRunStrategy cmdutil.DryRunStrategy + FieldManager string + FieldSelector string + resource.FilenameOptions + List bool + Local bool + OutputFormat string + overwrite bool + PrintFlags *genericclioptions.PrintFlags + RecordFlags *genericclioptions.RecordFlags + resourceVersion string + Selector string + + genericiooptions.IOStreams +} + +// NewAnnotateFlags returns a default AnnotateFlags +func NewAnnotateFlags(streams genericiooptions.IOStreams) *AnnotateFlags { + return &AnnotateFlags{ + PrintFlags: genericclioptions.NewPrintFlags("annotated").WithTypeSetter(scheme.Scheme), + RecordFlags: genericclioptions.NewRecordFlags(), + IOStreams: streams, + } +} + +// AnnotateOptions have the data required to perform the annotate operation +type AnnotateOptions struct { + all bool + allNamespaces bool + + builder *resource.Builder + dryRunStrategy cmdutil.DryRunStrategy + + enforceNamespace bool + fieldSelector string + fieldManager string + resource.FilenameOptions + + genericiooptions.IOStreams + + list bool + local bool + namespace string + newAnnotations map[string]string + overwrite bool + + PrintObj printers.ResourcePrinterFunc + + Recorder genericclioptions.Recorder + resources []string + resourceVersion string + removeAnnotations []string + selector string + + unstructuredClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error) +} + +var ( + annotateLong = templates.LongDesc(i18n.T(` + Update the annotations on one or more resources. + + All Kubernetes objects support the ability to store additional data with the object as + annotations. Annotations are key/value pairs that can be larger than labels and include + arbitrary string values such as structured JSON. Tools and system extensions may use + annotations to store their own data. + + Attempting to set an annotation that already exists will fail unless --overwrite is set. + If --resource-version is specified and does not match the current resource version on + the server the command will fail.`)) + + annotateExample = templates.Examples(i18n.T(` + # Update pod 'foo' with the annotation 'description' and the value 'my frontend' + # If the same annotation is set multiple times, only the last value will be applied + kubectl annotate pods foo description='my frontend' + + # Update a pod identified by type and name in "pod.json" + kubectl annotate -f pod.json description='my frontend' + + # Update pod 'foo' with the annotation 'description' and the value 'my frontend running nginx', overwriting any existing value + kubectl annotate --overwrite pods foo description='my frontend running nginx' + + # Update all pods in the namespace + kubectl annotate pods --all description='my frontend running nginx' + + # Update pod 'foo' only if the resource is unchanged from version 1 + kubectl annotate pods foo description='my frontend running nginx' --resource-version=1 + + # Update pod 'foo' by removing an annotation named 'description' if it exists + # Does not require the --overwrite flag + kubectl annotate pods foo description-`)) +) + +// NewCmdAnnotate creates the `annotate` command +func NewCmdAnnotate(parent string, f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { + flags := NewAnnotateFlags(streams) + + cmd := &cobra.Command{ + Use: "annotate [--overwrite] (-f FILENAME | TYPE NAME) KEY_1=VAL_1 ... KEY_N=VAL_N [--resource-version=version]", + DisableFlagsInUseLine: true, + Short: i18n.T("Update the annotations on a resource"), + Long: annotateLong + "\n\n" + cmdutil.SuggestAPIResources(parent), + Example: annotateExample, + ValidArgsFunction: completion.ResourceTypeAndNameCompletionFunc(f), + Run: func(cmd *cobra.Command, args []string) { + o, err := flags.ToOptions(f, cmd, args) + cmdutil.CheckErr(err) + cmdutil.CheckErr(o.RunAnnotate()) + }, + } + + flags.AddFlags(cmd, streams) + + return cmd +} + +// AddFlags registers flags for a cli. +func (flags *AnnotateFlags) AddFlags(cmd *cobra.Command, ioStreams genericiooptions.IOStreams) { + flags.PrintFlags.AddFlags(cmd) + flags.RecordFlags.AddFlags(cmd) + + cmdutil.AddDryRunFlag(cmd) + + usage := "identifying the resource to update the annotation" + cmdutil.AddFilenameOptionFlags(cmd, &flags.FilenameOptions, usage) + cmdutil.AddFieldManagerFlagVar(cmd, &flags.FieldManager, "kubectl-annotate") + cmdutil.AddLabelSelectorFlagVar(cmd, &flags.Selector) + + cmd.Flags().BoolVar(&flags.overwrite, "overwrite", flags.overwrite, "If true, allow annotations to be overwritten, otherwise reject annotation updates that overwrite existing annotations.") + cmd.Flags().BoolVar(&flags.List, "list", flags.List, "If true, display the annotations for a given resource.") + cmd.Flags().BoolVar(&flags.Local, "local", flags.Local, "If true, annotation will NOT contact api-server but run locally.") + cmd.Flags().StringVar(&flags.FieldSelector, "field-selector", flags.FieldSelector, "Selector (field query) to filter on, supports '=', '==', and '!='.(e.g. --field-selector key1=value1,key2=value2). The server only supports a limited number of field queries per type.") + cmd.Flags().BoolVar(&flags.All, "all", flags.All, "Select all resources, in the namespace of the specified resource types.") + cmd.Flags().BoolVarP(&flags.AllNamespaces, "all-namespaces", "A", flags.AllNamespaces, "If true, check the specified action in all namespaces.") + cmd.Flags().StringVar(&flags.resourceVersion, "resource-version", flags.resourceVersion, i18n.T("If non-empty, the annotation update will only succeed if this is the current resource-version for the object. Only valid when specifying a single resource.")) +} + +// ToOptions converts from CLI inputs to runtime inputs. +func (flags *AnnotateFlags) ToOptions(f cmdutil.Factory, cmd *cobra.Command, args []string) (*AnnotateOptions, error) { + options := &AnnotateOptions{ + all: flags.All, + allNamespaces: flags.AllNamespaces, + FilenameOptions: flags.FilenameOptions, + fieldSelector: flags.FieldSelector, + fieldManager: flags.FieldManager, + IOStreams: flags.IOStreams, + local: flags.Local, + list: flags.List, + overwrite: flags.overwrite, + resourceVersion: flags.resourceVersion, + Recorder: genericclioptions.NoopRecorder{}, + selector: flags.Selector, + } + + var err error + + flags.RecordFlags.Complete(cmd) + options.Recorder, err = flags.RecordFlags.ToRecorder() + if err != nil { + return nil, err + } + + options.dryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd) + if err != nil { + return nil, err + } + + cmdutil.PrintFlagsWithDryRunStrategy(flags.PrintFlags, options.dryRunStrategy) + printer, err := flags.PrintFlags.ToPrinter() + if err != nil { + return nil, err + } + options.PrintObj = func(obj runtime.Object, out io.Writer) error { + return printer.PrintObj(obj, out) + } + + options.namespace, options.enforceNamespace, err = f.ToRawKubeConfigLoader().Namespace() + if err != nil && !(options.local && clientcmd.IsEmptyConfig(err)) { + return nil, err + } + options.builder = f.NewBuilder() + options.unstructuredClientForMapping = f.UnstructuredClientForMapping + + // retrieves resource and annotation args from args + // also checks args to verify that all resources are specified before annotations + resources, annotationArgs, err := cmdutil.GetResourcesAndPairs(args, "annotation") + if err != nil { + return nil, err + } + options.resources = resources + options.newAnnotations, options.removeAnnotations, err = parseAnnotations(annotationArgs) + if err != nil { + return nil, err + } + + // Checks the options and flags to see if there is sufficient information run the command. + if flags.List && len(flags.OutputFormat) > 0 { + return nil, fmt.Errorf("--list and --output may not be specified together") + } + if flags.All && len(flags.Selector) > 0 { + return nil, fmt.Errorf("cannot set --all and --selector at the same time") + } + if flags.All && len(flags.FieldSelector) > 0 { + return nil, fmt.Errorf("cannot set --all and --field-selector at the same time") + } + + if !flags.Local { + if len(options.resources) < 1 && cmdutil.IsFilenameSliceEmpty(flags.Filenames, flags.Kustomize) { + return nil, fmt.Errorf("one or more resources must be specified as or /") + } + } else { + if options.dryRunStrategy == cmdutil.DryRunServer { + return nil, fmt.Errorf("cannot specify --local and --dry-run=server - did you mean --dry-run=client?") + } + if len(options.resources) > 0 { + return nil, fmt.Errorf("can only use local files by -f rsrc.yaml or --filename=rsrc.json when --local=true is set") + } + if cmdutil.IsFilenameSliceEmpty(flags.Filenames, flags.Kustomize) { + return nil, fmt.Errorf("one or more files must be specified as -f rsrc.yaml or --filename=rsrc.json") + } + } + if len(options.newAnnotations) < 1 && len(options.removeAnnotations) < 1 && !flags.List { + return nil, fmt.Errorf("at least one annotation update is required") + } + err = validateAnnotations(options.removeAnnotations, options.newAnnotations) + if err != nil { + return nil, err + } + + return options, nil +} + +// RunAnnotate does the work +func (o AnnotateOptions) RunAnnotate() error { + b := o.builder. + Unstructured(). + LocalParam(o.local). + ContinueOnError(). + NamespaceParam(o.namespace).DefaultNamespace(). + FilenameParam(o.enforceNamespace, &o.FilenameOptions). + Flatten() + + if !o.local { + b = b.LabelSelectorParam(o.selector). + FieldSelectorParam(o.fieldSelector). + AllNamespaces(o.allNamespaces). + ResourceTypeOrNameArgs(o.all, o.resources...). + Latest() + } + + r := b.Do() + if err := r.Err(); err != nil { + return err + } + + var singleItemImpliedResource bool + r.IntoSingleItemImplied(&singleItemImpliedResource) + + // only apply resource version locking on a single resource. + // we must perform this check after o.builder.Do() as + // []o.resources can not accurately return the proper number + // of resources when they are not passed in "resource/name" format. + if !singleItemImpliedResource && len(o.resourceVersion) > 0 { + return fmt.Errorf("--resource-version may only be used with a single resource") + } + + return r.Visit(func(info *resource.Info, err error) error { + if err != nil { + return err + } + + var outputObj runtime.Object + obj := info.Object + + if o.dryRunStrategy == cmdutil.DryRunClient || o.local || o.list { + if err := o.updateAnnotations(obj); err != nil { + return err + } + outputObj = obj + } else { + mapping := info.ResourceMapping() + name, namespace := info.Name, info.Namespace + + if len(o.resourceVersion) != 0 { + // ensure resourceVersion is always sent in the patch by clearing it from the starting JSON + accessor, err := meta.Accessor(obj) + if err != nil { + return err + } + accessor.SetResourceVersion("") + } + + oldData, err := json.Marshal(obj) + if err != nil { + return err + } + if err := o.Recorder.Record(info.Object); err != nil { + klog.V(4).Infof("error recording current command: %v", err) + } + if err := o.updateAnnotations(obj); err != nil { + return err + } + newData, err := json.Marshal(obj) + if err != nil { + return err + } + patchBytes, err := jsonpatch.CreateMergePatch(oldData, newData) + createdPatch := err == nil + if err != nil { + klog.V(2).Infof("couldn't compute patch: %v", err) + } + + client, err := o.unstructuredClientForMapping(mapping) + if err != nil { + return err + } + helper := resource. + NewHelper(client, mapping). + DryRun(o.dryRunStrategy == cmdutil.DryRunServer). + WithFieldManager(o.fieldManager) + + if createdPatch { + outputObj, err = helper.Patch(namespace, name, types.MergePatchType, patchBytes, nil) + } else { + outputObj, err = helper.Replace(namespace, name, false, obj) + } + if err != nil { + return err + } + } + + if o.list { + accessor, err := meta.Accessor(outputObj) + if err != nil { + return err + } + + indent := "" + if !singleItemImpliedResource { + indent = " " + gvks, _, err := unstructuredscheme.NewUnstructuredObjectTyper().ObjectKinds(info.Object) + if err != nil { + return err + } + fmt.Fprintf(o.Out, "Listing annotations for %s.%s/%s:\n", gvks[0].Kind, gvks[0].Group, info.Name) + } + for k, v := range accessor.GetAnnotations() { + fmt.Fprintf(o.Out, "%s%s=%s\n", indent, k, v) + } + + return nil + } + + return o.PrintObj(outputObj, o.Out) + }) +} + +// parseAnnotations retrieves new and remove annotations from annotation args +func parseAnnotations(annotationArgs []string) (map[string]string, []string, error) { + return cmdutil.ParsePairs(annotationArgs, "annotation", true) +} + +// validateAnnotations checks the format of annotation args and checks removed annotations aren't in the new annotations map +func validateAnnotations(removeAnnotations []string, newAnnotations map[string]string) error { + var modifyRemoveBuf bytes.Buffer + for _, removeAnnotation := range removeAnnotations { + if _, found := newAnnotations[removeAnnotation]; found { + if modifyRemoveBuf.Len() > 0 { + modifyRemoveBuf.WriteString(", ") + } + modifyRemoveBuf.WriteString(fmt.Sprint(removeAnnotation)) + } + } + if modifyRemoveBuf.Len() > 0 { + return fmt.Errorf("can not both modify and remove the following annotation(s) in the same command: %s", modifyRemoveBuf.String()) + } + + return nil +} + +// validateNoAnnotationOverwrites validates that when overwrite is false, to-be-updated annotations don't exist in the object annotation map (yet) +func validateNoAnnotationOverwrites(accessor metav1.Object, annotations map[string]string) error { + var buf bytes.Buffer + for key, value := range annotations { + // change-cause annotation can always be overwritten + if key == polymorphichelpers.ChangeCauseAnnotation { + continue + } + if currValue, found := accessor.GetAnnotations()[key]; found && currValue != value { + if buf.Len() > 0 { + buf.WriteString("; ") + } + buf.WriteString(fmt.Sprintf("'%s' already has a value (%s)", key, currValue)) + } + } + if buf.Len() > 0 { + return fmt.Errorf("--overwrite is false but found the following declared annotation(s): %s", buf.String()) + } + return nil +} + +// updateAnnotations updates annotations of obj +func (o AnnotateOptions) updateAnnotations(obj runtime.Object) error { + accessor, err := meta.Accessor(obj) + if err != nil { + return err + } + if !o.overwrite { + if err := validateNoAnnotationOverwrites(accessor, o.newAnnotations); err != nil { + return err + } + } + + annotations := accessor.GetAnnotations() + if annotations == nil { + annotations = make(map[string]string) + } + + for key, value := range o.newAnnotations { + annotations[key] = value + } + for _, annotation := range o.removeAnnotations { + delete(annotations, annotation) + } + accessor.SetAnnotations(annotations) + + if len(o.resourceVersion) != 0 { + accessor.SetResourceVersion(o.resourceVersion) + } + return nil +} diff --git a/vendor/k8s.io/kubectl/pkg/cmd/attach/attach.go b/vendor/k8s.io/kubectl/pkg/cmd/attach/attach.go new file mode 100644 index 000000000000..c1e8d83dc545 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/cmd/attach/attach.go @@ -0,0 +1,356 @@ +/* +Copyright 2014 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 attach + +import ( + "context" + "fmt" + "io" + "net/url" + "strings" + "time" + + "github.com/spf13/cobra" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/httpstream" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/genericiooptions" + "k8s.io/cli-runtime/pkg/resource" + restclient "k8s.io/client-go/rest" + "k8s.io/client-go/tools/remotecommand" + "k8s.io/kubectl/pkg/cmd/exec" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/cmd/util/podcmd" + "k8s.io/kubectl/pkg/polymorphichelpers" + "k8s.io/kubectl/pkg/scheme" + "k8s.io/kubectl/pkg/util/completion" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/templates" +) + +var ( + attachExample = templates.Examples(i18n.T(` + # Get output from running pod mypod; use the 'kubectl.kubernetes.io/default-container' annotation + # for selecting the container to be attached or the first container in the pod will be chosen + kubectl attach mypod + + # Get output from ruby-container from pod mypod + kubectl attach mypod -c ruby-container + + # Switch to raw terminal mode; sends stdin to 'bash' in ruby-container from pod mypod + # and sends stdout/stderr from 'bash' back to the client + kubectl attach mypod -c ruby-container -i -t + + # Get output from the first pod of a replica set named nginx + kubectl attach rs/nginx + `)) +) + +const ( + defaultPodAttachTimeout = 60 * time.Second + defaultPodLogsTimeout = 20 * time.Second +) + +// AttachOptions declare the arguments accepted by the Attach command +type AttachOptions struct { + exec.StreamOptions + + // whether to disable use of standard error when streaming output from tty + DisableStderr bool + + CommandName string + + Pod *corev1.Pod + + AttachFunc func(*AttachOptions, *corev1.Container, bool, remotecommand.TerminalSizeQueue) func() error + Resources []string + Builder func() *resource.Builder + AttachablePodFn polymorphichelpers.AttachablePodForObjectFunc + restClientGetter genericclioptions.RESTClientGetter + + Attach RemoteAttach + GetPodTimeout time.Duration + Config *restclient.Config +} + +// NewAttachOptions creates the options for attach +func NewAttachOptions(streams genericiooptions.IOStreams) *AttachOptions { + return &AttachOptions{ + StreamOptions: exec.StreamOptions{ + IOStreams: streams, + }, + Attach: &DefaultRemoteAttach{}, + AttachFunc: DefaultAttachFunc, + } +} + +// NewCmdAttach returns the attach Cobra command +func NewCmdAttach(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { + o := NewAttachOptions(streams) + cmd := &cobra.Command{ + Use: "attach (POD | TYPE/NAME) -c CONTAINER", + DisableFlagsInUseLine: true, + Short: i18n.T("Attach to a running container"), + Long: i18n.T("Attach to a process that is already running inside an existing container."), + Example: attachExample, + ValidArgsFunction: completion.PodResourceNameCompletionFunc(f), + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.Run()) + }, + } + cmdutil.AddPodRunningTimeoutFlag(cmd, defaultPodAttachTimeout) + cmdutil.AddContainerVarFlags(cmd, &o.ContainerName, o.ContainerName) + cmd.Flags().BoolVarP(&o.Stdin, "stdin", "i", o.Stdin, "Pass stdin to the container") + cmd.Flags().BoolVarP(&o.TTY, "tty", "t", o.TTY, "Stdin is a TTY") + cmd.Flags().BoolVarP(&o.Quiet, "quiet", "q", o.Quiet, "Only print output from the remote session") + return cmd +} + +// RemoteAttach defines the interface accepted by the Attach command - provided for test stubbing +type RemoteAttach interface { + Attach(url *url.URL, config *restclient.Config, stdin io.Reader, stdout, stderr io.Writer, tty bool, terminalSizeQueue remotecommand.TerminalSizeQueue) error +} + +// DefaultAttachFunc is the default AttachFunc used +func DefaultAttachFunc(o *AttachOptions, containerToAttach *corev1.Container, raw bool, sizeQueue remotecommand.TerminalSizeQueue) func() error { + return func() error { + restClient, err := restclient.RESTClientFor(o.Config) + if err != nil { + return err + } + req := restClient.Post(). + Resource("pods"). + Name(o.Pod.Name). + Namespace(o.Pod.Namespace). + SubResource("attach") + req.VersionedParams(&corev1.PodAttachOptions{ + Container: containerToAttach.Name, + Stdin: o.Stdin, + Stdout: o.Out != nil, + Stderr: !o.DisableStderr, + TTY: raw, + }, scheme.ParameterCodec) + + return o.Attach.Attach(req.URL(), o.Config, o.In, o.Out, o.ErrOut, raw, sizeQueue) + } +} + +// DefaultRemoteAttach is the standard implementation of attaching +type DefaultRemoteAttach struct{} + +// Attach executes attach to a running container +func (*DefaultRemoteAttach) Attach(url *url.URL, config *restclient.Config, stdin io.Reader, stdout, stderr io.Writer, tty bool, terminalSizeQueue remotecommand.TerminalSizeQueue) error { + exec, err := createExecutor(url, config) + if err != nil { + return err + } + return exec.StreamWithContext(context.Background(), remotecommand.StreamOptions{ + Stdin: stdin, + Stdout: stdout, + Stderr: stderr, + Tty: tty, + TerminalSizeQueue: terminalSizeQueue, + }) +} + +// createExecutor returns the Executor or an error if one occurred. +func createExecutor(url *url.URL, config *restclient.Config) (remotecommand.Executor, error) { + exec, err := remotecommand.NewSPDYExecutor(config, "POST", url) + if err != nil { + return nil, err + } + // Fallback executor is default, unless feature flag is explicitly disabled. + if !cmdutil.RemoteCommandWebsockets.IsDisabled() { + // WebSocketExecutor must be "GET" method as described in RFC 6455 Sec. 4.1 (page 17). + websocketExec, err := remotecommand.NewWebSocketExecutor(config, "GET", url.String()) + if err != nil { + return nil, err + } + exec, err = remotecommand.NewFallbackExecutor(websocketExec, exec, httpstream.IsUpgradeFailure) + if err != nil { + return nil, err + } + } + return exec, nil +} + +// Complete verifies command line arguments and loads data from the command environment +func (o *AttachOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { + var err error + o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace() + if err != nil { + return err + } + + o.AttachablePodFn = polymorphichelpers.AttachablePodForObjectFn + + o.GetPodTimeout, err = cmdutil.GetPodRunningTimeoutFlag(cmd) + if err != nil { + return cmdutil.UsageErrorf(cmd, err.Error()) + } + + o.Builder = f.NewBuilder + o.Resources = args + o.restClientGetter = f + + config, err := f.ToRESTConfig() + if err != nil { + return err + } + o.Config = config + + if o.CommandName == "" { + o.CommandName = cmd.CommandPath() + } + + return nil +} + +// Validate checks that the provided attach options are specified. +func (o *AttachOptions) Validate() error { + if len(o.Resources) == 0 { + return fmt.Errorf("at least 1 argument is required for attach") + } + if len(o.Resources) > 2 { + return fmt.Errorf("expected POD, TYPE/NAME, or TYPE NAME, (at most 2 arguments) saw %d: %v", len(o.Resources), o.Resources) + } + if o.GetPodTimeout <= 0 { + return fmt.Errorf("--pod-running-timeout must be higher than zero") + } + + return nil +} + +// Run executes a validated remote execution against a pod. +func (o *AttachOptions) Run() error { + if o.Pod == nil { + b := o.Builder(). + WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...). + NamespaceParam(o.Namespace).DefaultNamespace() + + switch len(o.Resources) { + case 1: + b.ResourceNames("pods", o.Resources[0]) + case 2: + b.ResourceNames(o.Resources[0], o.Resources[1]) + } + + obj, err := b.Do().Object() + if err != nil { + return err + } + + o.Pod, err = o.findAttachablePod(obj) + if err != nil { + return err + } + + if o.Pod.Status.Phase == corev1.PodSucceeded || o.Pod.Status.Phase == corev1.PodFailed { + return fmt.Errorf("cannot attach a container in a completed pod; current phase is %s", o.Pod.Status.Phase) + } + // TODO: convert this to a clean "wait" behavior + } + + // check for TTY + containerToAttach, err := o.containerToAttachTo(o.Pod) + if err != nil { + return fmt.Errorf("cannot attach to the container: %v", err) + } + if o.TTY && !containerToAttach.TTY { + o.TTY = false + if !o.Quiet && o.ErrOut != nil { + fmt.Fprintf(o.ErrOut, "error: Unable to use a TTY - container %s did not allocate one\n", containerToAttach.Name) + } + } else if !o.TTY && containerToAttach.TTY { + // the container was launched with a TTY, so we have to force a TTY here, otherwise you'll get + // an error "Unrecognized input header" + o.TTY = true + } + + // ensure we can recover the terminal while attached + t := o.SetupTTY() + + var sizeQueue remotecommand.TerminalSizeQueue + if t.Raw { + if size := t.GetSize(); size != nil { + // fake resizing +1 and then back to normal so that attach-detach-reattach will result in the + // screen being redrawn + sizePlusOne := *size + sizePlusOne.Width++ + sizePlusOne.Height++ + + // this call spawns a goroutine to monitor/update the terminal size + sizeQueue = t.MonitorSize(&sizePlusOne, size) + } + + o.DisableStderr = true + } + + if !o.Quiet { + fmt.Fprintln(o.ErrOut, "If you don't see a command prompt, try pressing enter.") + } + if err := t.Safe(o.AttachFunc(o, containerToAttach, t.Raw, sizeQueue)); err != nil { + return err + } + + if msg := o.reattachMessage(containerToAttach.Name, t.Raw); msg != "" { + fmt.Fprintln(o.Out, msg) + } + return nil +} + +func (o *AttachOptions) findAttachablePod(obj runtime.Object) (*corev1.Pod, error) { + attachablePod, err := o.AttachablePodFn(o.restClientGetter, obj, o.GetPodTimeout) + if err != nil { + return nil, err + } + + o.StreamOptions.PodName = attachablePod.Name + return attachablePod, nil +} + +// containerToAttach returns a reference to the container to attach to, given by name. +// use the kubectl.kubernetes.io/default-container annotation for selecting the container to be attached +// or the first container in the pod will be chosen If name is empty. +func (o *AttachOptions) containerToAttachTo(pod *corev1.Pod) (*corev1.Container, error) { + return podcmd.FindOrDefaultContainerByName(pod, o.ContainerName, o.Quiet, o.ErrOut) +} + +// GetContainerName returns the name of the container to attach to, with a fallback. +func (o *AttachOptions) GetContainerName(pod *corev1.Pod) (string, error) { + c, err := o.containerToAttachTo(pod) + if err != nil { + return "", err + } + return c.Name, nil +} + +// reattachMessage returns a message to print after attach has completed, or +// the empty string if no message should be printed. +func (o *AttachOptions) reattachMessage(containerName string, rawTTY bool) string { + if o.Quiet || !o.Stdin || !rawTTY || o.Pod.Spec.RestartPolicy != corev1.RestartPolicyAlways { + return "" + } + if _, path := podcmd.FindContainerByName(o.Pod, containerName); strings.HasPrefix(path, "spec.ephemeralContainers") { + return fmt.Sprintf("Session ended, the ephemeral container will not be restarted but may be reattached using '%s %s -c %s -i -t' if it is still running", o.CommandName, o.Pod.Name, containerName) + } + return fmt.Sprintf("Session ended, resume using '%s %s -c %s -i -t' command when the pod is running", o.CommandName, o.Pod.Name, containerName) +} diff --git a/vendor/k8s.io/kubectl/pkg/cmd/create/create.go b/vendor/k8s.io/kubectl/pkg/cmd/create/create.go new file mode 100644 index 000000000000..17b21c4e08d3 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/cmd/create/create.go @@ -0,0 +1,472 @@ +/* +Copyright 2014 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 create + +import ( + "context" + "fmt" + "io" + "net/url" + "runtime" + "strings" + + "github.com/spf13/cobra" + "k8s.io/klog/v2" + + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + kruntime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/genericiooptions" + "k8s.io/cli-runtime/pkg/printers" + "k8s.io/cli-runtime/pkg/resource" + "k8s.io/client-go/dynamic" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/cmd/util/editor" + "k8s.io/kubectl/pkg/generate" + "k8s.io/kubectl/pkg/rawhttp" + "k8s.io/kubectl/pkg/scheme" + "k8s.io/kubectl/pkg/util" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/templates" +) + +// CreateOptions is the commandline options for 'create' sub command +type CreateOptions struct { + PrintFlags *genericclioptions.PrintFlags + RecordFlags *genericclioptions.RecordFlags + + DryRunStrategy cmdutil.DryRunStrategy + + ValidationDirective string + + fieldManager string + + FilenameOptions resource.FilenameOptions + Selector string + EditBeforeCreate bool + Raw string + + Recorder genericclioptions.Recorder + PrintObj func(obj kruntime.Object) error + + genericiooptions.IOStreams +} + +var ( + createLong = templates.LongDesc(i18n.T(` + Create a resource from a file or from stdin. + + JSON and YAML formats are accepted.`)) + + createExample = templates.Examples(i18n.T(` + # Create a pod using the data in pod.json + kubectl create -f ./pod.json + + # Create a pod based on the JSON passed into stdin + cat pod.json | kubectl create -f - + + # Edit the data in registry.yaml in JSON then create the resource using the edited data + kubectl create -f registry.yaml --edit -o json`)) +) + +// NewCreateOptions returns an initialized CreateOptions instance +func NewCreateOptions(ioStreams genericiooptions.IOStreams) *CreateOptions { + return &CreateOptions{ + PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme), + RecordFlags: genericclioptions.NewRecordFlags(), + + Recorder: genericclioptions.NoopRecorder{}, + + IOStreams: ioStreams, + } +} + +// NewCmdCreate returns new initialized instance of create sub command +func NewCmdCreate(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + o := NewCreateOptions(ioStreams) + + cmd := &cobra.Command{ + Use: "create -f FILENAME", + DisableFlagsInUseLine: true, + Short: i18n.T("Create a resource from a file or from stdin"), + Long: createLong, + Example: createExample, + Run: func(cmd *cobra.Command, args []string) { + if cmdutil.IsFilenameSliceEmpty(o.FilenameOptions.Filenames, o.FilenameOptions.Kustomize) { + ioStreams.ErrOut.Write([]byte("Error: must specify one of -f and -k\n\n")) + defaultRunFunc := cmdutil.DefaultSubCommandRun(ioStreams.ErrOut) + defaultRunFunc(cmd, args) + return + } + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.RunCreate(f, cmd)) + }, + } + + // bind flag structs + o.RecordFlags.AddFlags(cmd) + + usage := "to use to create the resource" + cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage) + cmdutil.AddValidateFlags(cmd) + cmd.Flags().BoolVar(&o.EditBeforeCreate, "edit", o.EditBeforeCreate, "Edit the API resource before creating") + cmd.Flags().Bool("windows-line-endings", runtime.GOOS == "windows", + "Only relevant if --edit=true. Defaults to the line ending native to your platform.") + cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddDryRunFlag(cmd) + cmdutil.AddLabelSelectorFlagVar(cmd, &o.Selector) + cmd.Flags().StringVar(&o.Raw, "raw", o.Raw, "Raw URI to POST to the server. Uses the transport specified by the kubeconfig file.") + cmdutil.AddFieldManagerFlagVar(cmd, &o.fieldManager, "kubectl-create") + + o.PrintFlags.AddFlags(cmd) + + // create subcommands + cmd.AddCommand(NewCmdCreateNamespace(f, ioStreams)) + cmd.AddCommand(NewCmdCreateQuota(f, ioStreams)) + cmd.AddCommand(NewCmdCreateSecret(f, ioStreams)) + cmd.AddCommand(NewCmdCreateConfigMap(f, ioStreams)) + cmd.AddCommand(NewCmdCreateServiceAccount(f, ioStreams)) + cmd.AddCommand(NewCmdCreateService(f, ioStreams)) + cmd.AddCommand(NewCmdCreateDeployment(f, ioStreams)) + cmd.AddCommand(NewCmdCreateClusterRole(f, ioStreams)) + cmd.AddCommand(NewCmdCreateClusterRoleBinding(f, ioStreams)) + cmd.AddCommand(NewCmdCreateRole(f, ioStreams)) + cmd.AddCommand(NewCmdCreateRoleBinding(f, ioStreams)) + cmd.AddCommand(NewCmdCreatePodDisruptionBudget(f, ioStreams)) + cmd.AddCommand(NewCmdCreatePriorityClass(f, ioStreams)) + cmd.AddCommand(NewCmdCreateJob(f, ioStreams)) + cmd.AddCommand(NewCmdCreateCronJob(f, ioStreams)) + cmd.AddCommand(NewCmdCreateIngress(f, ioStreams)) + cmd.AddCommand(NewCmdCreateToken(f, ioStreams)) + return cmd +} + +// Validate makes sure there is no discrepency in command options +func (o *CreateOptions) Validate() error { + if len(o.Raw) > 0 { + if o.EditBeforeCreate { + return fmt.Errorf("--raw and --edit are mutually exclusive") + } + if len(o.FilenameOptions.Filenames) != 1 { + return fmt.Errorf("--raw can only use a single local file or stdin") + } + if strings.Index(o.FilenameOptions.Filenames[0], "http://") == 0 || strings.Index(o.FilenameOptions.Filenames[0], "https://") == 0 { + return fmt.Errorf("--raw cannot read from a url") + } + if o.FilenameOptions.Recursive { + return fmt.Errorf("--raw and --recursive are mutually exclusive") + } + if len(o.Selector) > 0 { + return fmt.Errorf("--raw and --selector (-l) are mutually exclusive") + } + if o.PrintFlags.OutputFormat != nil && len(*o.PrintFlags.OutputFormat) > 0 { + return fmt.Errorf("--raw and --output are mutually exclusive") + } + if _, err := url.ParseRequestURI(o.Raw); err != nil { + return fmt.Errorf("--raw must be a valid URL path: %v", err) + } + } + + return nil +} + +// Complete completes all the required options +func (o *CreateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { + if len(args) != 0 { + return cmdutil.UsageErrorf(cmd, "Unexpected args: %v", args) + } + var err error + o.RecordFlags.Complete(cmd) + o.Recorder, err = o.RecordFlags.ToRecorder() + if err != nil { + return err + } + + o.DryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd) + if err != nil { + return err + } + cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) + + o.ValidationDirective, err = cmdutil.GetValidationDirective(cmd) + if err != nil { + return err + } + + printer, err := o.PrintFlags.ToPrinter() + if err != nil { + return err + } + + o.PrintObj = func(obj kruntime.Object) error { + return printer.PrintObj(obj, o.Out) + } + + return nil +} + +// RunCreate performs the creation +func (o *CreateOptions) RunCreate(f cmdutil.Factory, cmd *cobra.Command) error { + // raw only makes sense for a single file resource multiple objects aren't likely to do what you want. + // the validator enforces this, so + if len(o.Raw) > 0 { + restClient, err := f.RESTClient() + if err != nil { + return err + } + return rawhttp.RawPost(restClient, o.IOStreams, o.Raw, o.FilenameOptions.Filenames[0]) + } + + if o.EditBeforeCreate { + return RunEditOnCreate(f, o.PrintFlags, o.RecordFlags, o.IOStreams, cmd, &o.FilenameOptions, o.fieldManager) + } + + schema, err := f.Validator(o.ValidationDirective) + if err != nil { + return err + } + + cmdNamespace, enforceNamespace, err := f.ToRawKubeConfigLoader().Namespace() + if err != nil { + return err + } + + r := f.NewBuilder(). + Unstructured(). + Schema(schema). + ContinueOnError(). + NamespaceParam(cmdNamespace).DefaultNamespace(). + FilenameParam(enforceNamespace, &o.FilenameOptions). + LabelSelectorParam(o.Selector). + Flatten(). + Do() + err = r.Err() + if err != nil { + return err + } + + count := 0 + err = r.Visit(func(info *resource.Info, err error) error { + if err != nil { + return err + } + if err := util.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info.Object, scheme.DefaultJSONEncoder()); err != nil { + return cmdutil.AddSourceToErr("creating", info.Source, err) + } + + if err := o.Recorder.Record(info.Object); err != nil { + klog.V(4).Infof("error recording current command: %v", err) + } + + if o.DryRunStrategy != cmdutil.DryRunClient { + obj, err := resource. + NewHelper(info.Client, info.Mapping). + DryRun(o.DryRunStrategy == cmdutil.DryRunServer). + WithFieldManager(o.fieldManager). + WithFieldValidation(o.ValidationDirective). + Create(info.Namespace, true, info.Object) + if err != nil { + return cmdutil.AddSourceToErr("creating", info.Source, err) + } + info.Refresh(obj, true) + } + + count++ + + return o.PrintObj(info.Object) + }) + if err != nil { + return err + } + if count == 0 { + return fmt.Errorf("no objects passed to create") + } + return nil +} + +// RunEditOnCreate performs edit on creation +func RunEditOnCreate(f cmdutil.Factory, printFlags *genericclioptions.PrintFlags, recordFlags *genericclioptions.RecordFlags, ioStreams genericiooptions.IOStreams, cmd *cobra.Command, options *resource.FilenameOptions, fieldManager string) error { + editOptions := editor.NewEditOptions(editor.EditBeforeCreateMode, ioStreams) + editOptions.FilenameOptions = *options + validationDirective, err := cmdutil.GetValidationDirective(cmd) + if err != nil { + return err + } + editOptions.ValidateOptions = cmdutil.ValidateOptions{ + ValidationDirective: string(validationDirective), + } + editOptions.PrintFlags = printFlags + editOptions.ApplyAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) + editOptions.RecordFlags = recordFlags + editOptions.FieldManager = "kubectl-create" + + err = editOptions.Complete(f, []string{}, cmd) + if err != nil { + return err + } + return editOptions.Run() +} + +// NameFromCommandArgs is a utility function for commands that assume the first argument is a resource name +func NameFromCommandArgs(cmd *cobra.Command, args []string) (string, error) { + argsLen := cmd.ArgsLenAtDash() + // ArgsLenAtDash returns -1 when -- was not specified + if argsLen == -1 { + argsLen = len(args) + } + if argsLen != 1 { + return "", cmdutil.UsageErrorf(cmd, "exactly one NAME is required, got %d", argsLen) + } + return args[0], nil +} + +// CreateSubcommandOptions is an options struct to support create subcommands +type CreateSubcommandOptions struct { + // PrintFlags holds options necessary for obtaining a printer + PrintFlags *genericclioptions.PrintFlags + // Name of resource being created + Name string + // StructuredGenerator is the resource generator for the object being created + StructuredGenerator generate.StructuredGenerator + DryRunStrategy cmdutil.DryRunStrategy + CreateAnnotation bool + FieldManager string + ValidationDirective string + + Namespace string + EnforceNamespace bool + + Mapper meta.RESTMapper + DynamicClient dynamic.Interface + + PrintObj printers.ResourcePrinterFunc + + genericiooptions.IOStreams +} + +// NewCreateSubcommandOptions returns initialized CreateSubcommandOptions +func NewCreateSubcommandOptions(ioStreams genericiooptions.IOStreams) *CreateSubcommandOptions { + return &CreateSubcommandOptions{ + PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme), + IOStreams: ioStreams, + } +} + +// Complete completes all the required options +func (o *CreateSubcommandOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string, generator generate.StructuredGenerator) error { + name, err := NameFromCommandArgs(cmd, args) + if err != nil { + return err + } + + o.Name = name + o.StructuredGenerator = generator + o.DryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd) + if err != nil { + return err + } + o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) + + cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) + printer, err := o.PrintFlags.ToPrinter() + if err != nil { + return err + } + + o.ValidationDirective, err = cmdutil.GetValidationDirective(cmd) + if err != nil { + return err + } + + o.PrintObj = func(obj kruntime.Object, out io.Writer) error { + return printer.PrintObj(obj, out) + } + + o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace() + if err != nil { + return err + } + + o.DynamicClient, err = f.DynamicClient() + if err != nil { + return err + } + + o.Mapper, err = f.ToRESTMapper() + if err != nil { + return err + } + + return nil +} + +// Run executes a create subcommand using the specified options +func (o *CreateSubcommandOptions) Run() error { + obj, err := o.StructuredGenerator.StructuredGenerate() + if err != nil { + return err + } + if err := util.CreateOrUpdateAnnotation(o.CreateAnnotation, obj, scheme.DefaultJSONEncoder()); err != nil { + return err + } + if o.DryRunStrategy != cmdutil.DryRunClient { + // create subcommands have compiled knowledge of things they create, so type them directly + gvks, _, err := scheme.Scheme.ObjectKinds(obj) + if err != nil { + return err + } + gvk := gvks[0] + mapping, err := o.Mapper.RESTMapping(schema.GroupKind{Group: gvk.Group, Kind: gvk.Kind}, gvk.Version) + if err != nil { + return err + } + + asUnstructured := &unstructured.Unstructured{} + if err := scheme.Scheme.Convert(obj, asUnstructured, nil); err != nil { + return err + } + if mapping.Scope.Name() == meta.RESTScopeNameRoot { + o.Namespace = "" + } + createOptions := metav1.CreateOptions{} + if o.FieldManager != "" { + createOptions.FieldManager = o.FieldManager + } + createOptions.FieldValidation = o.ValidationDirective + + if o.DryRunStrategy == cmdutil.DryRunServer { + createOptions.DryRun = []string{metav1.DryRunAll} + } + actualObject, err := o.DynamicClient.Resource(mapping.Resource).Namespace(o.Namespace).Create(context.TODO(), asUnstructured, createOptions) + if err != nil { + return err + } + + // ensure we pass a versioned object to the printer + obj = actualObject + } else { + if meta, err := meta.Accessor(obj); err == nil && o.EnforceNamespace { + meta.SetNamespace(o.Namespace) + } + } + + return o.PrintObj(obj, o.Out) +} diff --git a/vendor/k8s.io/kubectl/pkg/cmd/create/create_clusterrole.go b/vendor/k8s.io/kubectl/pkg/cmd/create/create_clusterrole.go new file mode 100644 index 000000000000..6b55eab3ecd3 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/cmd/create/create_clusterrole.go @@ -0,0 +1,227 @@ +/* +Copyright 2017 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 create + +import ( + "context" + "fmt" + "strings" + + "github.com/spf13/cobra" + + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/cli-runtime/pkg/genericiooptions" + cliflag "k8s.io/component-base/cli/flag" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/scheme" + "k8s.io/kubectl/pkg/util" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/templates" +) + +var ( + clusterRoleLong = templates.LongDesc(i18n.T(` + Create a cluster role.`)) + + clusterRoleExample = templates.Examples(i18n.T(` + # Create a cluster role named "pod-reader" that allows user to perform "get", "watch" and "list" on pods + kubectl create clusterrole pod-reader --verb=get,list,watch --resource=pods + + # Create a cluster role named "pod-reader" with ResourceName specified + kubectl create clusterrole pod-reader --verb=get --resource=pods --resource-name=readablepod --resource-name=anotherpod + + # Create a cluster role named "foo" with API Group specified + kubectl create clusterrole foo --verb=get,list,watch --resource=rs.apps + + # Create a cluster role named "foo" with SubResource specified + kubectl create clusterrole foo --verb=get,list,watch --resource=pods,pods/status + + # Create a cluster role name "foo" with NonResourceURL specified + kubectl create clusterrole "foo" --verb=get --non-resource-url=/logs/* + + # Create a cluster role name "monitoring" with AggregationRule specified + kubectl create clusterrole monitoring --aggregation-rule="rbac.example.com/aggregate-to-monitoring=true"`)) + + // Valid nonResource verb list for validation. + validNonResourceVerbs = []string{"*", "get", "post", "put", "delete", "patch", "head", "options"} +) + +// CreateClusterRoleOptions is returned by NewCmdCreateClusterRole +type CreateClusterRoleOptions struct { + *CreateRoleOptions + NonResourceURLs []string + AggregationRule map[string]string + FieldManager string +} + +// NewCmdCreateClusterRole initializes and returns new ClusterRoles command +func NewCmdCreateClusterRole(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + c := &CreateClusterRoleOptions{ + CreateRoleOptions: NewCreateRoleOptions(ioStreams), + AggregationRule: map[string]string{}, + } + cmd := &cobra.Command{ + Use: "clusterrole NAME --verb=verb --resource=resource.group [--resource-name=resourcename] [--dry-run=server|client|none]", + DisableFlagsInUseLine: true, + Short: i18n.T("Create a cluster role"), + Long: clusterRoleLong, + Example: clusterRoleExample, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(c.Complete(f, cmd, args)) + cmdutil.CheckErr(c.Validate()) + cmdutil.CheckErr(c.RunCreateRole()) + }, + } + + c.PrintFlags.AddFlags(cmd) + + cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddValidateFlags(cmd) + cmdutil.AddDryRunFlag(cmd) + cmd.Flags().StringSliceVar(&c.Verbs, "verb", c.Verbs, "Verb that applies to the resources contained in the rule") + cmd.Flags().StringSliceVar(&c.NonResourceURLs, "non-resource-url", c.NonResourceURLs, "A partial url that user should have access to.") + cmd.Flags().StringSlice("resource", []string{}, "Resource that the rule applies to") + cmd.Flags().StringArrayVar(&c.ResourceNames, "resource-name", c.ResourceNames, "Resource in the white list that the rule applies to, repeat this flag for multiple items") + cmd.Flags().Var(cliflag.NewMapStringString(&c.AggregationRule), "aggregation-rule", "An aggregation label selector for combining ClusterRoles.") + cmdutil.AddFieldManagerFlagVar(cmd, &c.FieldManager, "kubectl-create") + + return cmd +} + +// Complete completes all the required options +func (c *CreateClusterRoleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { + // Remove duplicate nonResourceURLs + nonResourceURLs := []string{} + for _, n := range c.NonResourceURLs { + if !arrayContains(nonResourceURLs, n) { + nonResourceURLs = append(nonResourceURLs, n) + } + } + c.NonResourceURLs = nonResourceURLs + + return c.CreateRoleOptions.Complete(f, cmd, args) +} + +// Validate makes sure there is no discrepency in CreateClusterRoleOptions +func (c *CreateClusterRoleOptions) Validate() error { + if c.Name == "" { + return fmt.Errorf("name must be specified") + } + + if len(c.AggregationRule) > 0 { + if len(c.NonResourceURLs) > 0 || len(c.Verbs) > 0 || len(c.Resources) > 0 || len(c.ResourceNames) > 0 { + return fmt.Errorf("aggregation rule must be specified without nonResourceURLs, verbs, resources or resourceNames") + } + return nil + } + + // validate verbs. + if len(c.Verbs) == 0 { + return fmt.Errorf("at least one verb must be specified") + } + + if len(c.Resources) == 0 && len(c.NonResourceURLs) == 0 { + return fmt.Errorf("one of resource or nonResourceURL must be specified") + } + + // validate resources + if len(c.Resources) > 0 { + for _, v := range c.Verbs { + if !arrayContains(validResourceVerbs, v) { + fmt.Fprintf(c.ErrOut, "Warning: '%s' is not a standard resource verb\n", v) + } + } + if err := c.validateResource(); err != nil { + return err + } + } + + //validate non-resource-url + if len(c.NonResourceURLs) > 0 { + for _, v := range c.Verbs { + if !arrayContains(validNonResourceVerbs, v) { + return fmt.Errorf("invalid verb: '%s' for nonResourceURL", v) + } + } + + for _, nonResourceURL := range c.NonResourceURLs { + if nonResourceURL == "*" { + continue + } + + if nonResourceURL == "" || !strings.HasPrefix(nonResourceURL, "/") { + return fmt.Errorf("nonResourceURL should start with /") + } + + if strings.ContainsRune(nonResourceURL[:len(nonResourceURL)-1], '*') { + return fmt.Errorf("nonResourceURL only supports wildcard matches when '*' is at the end") + } + } + } + + return nil + +} + +// RunCreateRole creates a new clusterRole +func (c *CreateClusterRoleOptions) RunCreateRole() error { + clusterRole := &rbacv1.ClusterRole{ + // this is ok because we know exactly how we want to be serialized + TypeMeta: metav1.TypeMeta{APIVersion: rbacv1.SchemeGroupVersion.String(), Kind: "ClusterRole"}, + } + clusterRole.Name = c.Name + + var err error + if len(c.AggregationRule) == 0 { + rules, err := generateResourcePolicyRules(c.Mapper, c.Verbs, c.Resources, c.ResourceNames, c.NonResourceURLs) + if err != nil { + return err + } + clusterRole.Rules = rules + } else { + clusterRole.AggregationRule = &rbacv1.AggregationRule{ + ClusterRoleSelectors: []metav1.LabelSelector{ + { + MatchLabels: c.AggregationRule, + }, + }, + } + } + + if err := util.CreateOrUpdateAnnotation(c.CreateAnnotation, clusterRole, scheme.DefaultJSONEncoder()); err != nil { + return err + } + + // Create ClusterRole. + if c.DryRunStrategy != cmdutil.DryRunClient { + createOptions := metav1.CreateOptions{} + if c.FieldManager != "" { + createOptions.FieldManager = c.FieldManager + } + createOptions.FieldValidation = c.ValidationDirective + if c.DryRunStrategy == cmdutil.DryRunServer { + createOptions.DryRun = []string{metav1.DryRunAll} + } + clusterRole, err = c.Client.ClusterRoles().Create(context.TODO(), clusterRole, createOptions) + if err != nil { + return err + } + } + + return c.PrintObj(clusterRole) +} diff --git a/vendor/k8s.io/kubectl/pkg/cmd/create/create_clusterrolebinding.go b/vendor/k8s.io/kubectl/pkg/cmd/create/create_clusterrolebinding.go new file mode 100644 index 000000000000..3b87019ac721 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/cmd/create/create_clusterrolebinding.go @@ -0,0 +1,228 @@ +/* +Copyright 2016 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 create + +import ( + "context" + "fmt" + "strings" + + "github.com/spf13/cobra" + + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/genericiooptions" + rbacclientv1 "k8s.io/client-go/kubernetes/typed/rbac/v1" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/scheme" + "k8s.io/kubectl/pkg/util" + "k8s.io/kubectl/pkg/util/completion" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/templates" +) + +var ( + clusterRoleBindingLong = templates.LongDesc(i18n.T(` + Create a cluster role binding for a particular cluster role.`)) + + clusterRoleBindingExample = templates.Examples(i18n.T(` + # Create a cluster role binding for user1, user2, and group1 using the cluster-admin cluster role + kubectl create clusterrolebinding cluster-admin --clusterrole=cluster-admin --user=user1 --user=user2 --group=group1`)) +) + +// ClusterRoleBindingOptions is returned by NewCmdCreateClusterRoleBinding +type ClusterRoleBindingOptions struct { + PrintFlags *genericclioptions.PrintFlags + PrintObj func(obj runtime.Object) error + + Name string + ClusterRole string + Users []string + Groups []string + ServiceAccounts []string + FieldManager string + CreateAnnotation bool + + Client rbacclientv1.RbacV1Interface + DryRunStrategy cmdutil.DryRunStrategy + ValidationDirective string + + genericiooptions.IOStreams +} + +// NewClusterRoleBindingOptions creates a new *ClusterRoleBindingOptions with sane defaults +func NewClusterRoleBindingOptions(ioStreams genericiooptions.IOStreams) *ClusterRoleBindingOptions { + return &ClusterRoleBindingOptions{ + Users: []string{}, + Groups: []string{}, + ServiceAccounts: []string{}, + PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme), + IOStreams: ioStreams, + } +} + +// NewCmdCreateClusterRoleBinding returns an initialized command instance of ClusterRoleBinding +func NewCmdCreateClusterRoleBinding(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + o := NewClusterRoleBindingOptions(ioStreams) + + cmd := &cobra.Command{ + Use: "clusterrolebinding NAME --clusterrole=NAME [--user=username] [--group=groupname] [--serviceaccount=namespace:serviceaccountname] [--dry-run=server|client|none]", + DisableFlagsInUseLine: true, + Short: i18n.T("Create a cluster role binding for a particular cluster role"), + Long: clusterRoleBindingLong, + Example: clusterRoleBindingExample, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Run()) + }, + } + + o.PrintFlags.AddFlags(cmd) + + cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddValidateFlags(cmd) + cmdutil.AddDryRunFlag(cmd) + cmd.Flags().StringVar(&o.ClusterRole, "clusterrole", "", i18n.T("ClusterRole this ClusterRoleBinding should reference")) + cmd.MarkFlagRequired("clusterrole") + cmd.Flags().StringArrayVar(&o.Users, "user", o.Users, "Usernames to bind to the clusterrole. The flag can be repeated to add multiple users.") + cmd.Flags().StringArrayVar(&o.Groups, "group", o.Groups, "Groups to bind to the clusterrole. The flag can be repeated to add multiple groups.") + cmd.Flags().StringArrayVar(&o.ServiceAccounts, "serviceaccount", o.ServiceAccounts, "Service accounts to bind to the clusterrole, in the format :. The flag can be repeated to add multiple service accounts.") + cmdutil.AddFieldManagerFlagVar(cmd, &o.FieldManager, "kubectl-create") + + // Completion for relevant flags + cmdutil.CheckErr(cmd.RegisterFlagCompletionFunc( + "clusterrole", + func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return completion.CompGetResource(f, "clusterrole", toComplete), cobra.ShellCompDirectiveNoFileComp + })) + + return cmd +} + +// Complete completes all the required options +func (o *ClusterRoleBindingOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { + var err error + o.Name, err = NameFromCommandArgs(cmd, args) + if err != nil { + return err + } + + cs, err := f.KubernetesClientSet() + if err != nil { + return err + } + o.Client = cs.RbacV1() + + o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) + + o.DryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd) + if err != nil { + return err + } + cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) + + printer, err := o.PrintFlags.ToPrinter() + if err != nil { + return err + } + o.PrintObj = func(obj runtime.Object) error { + return printer.PrintObj(obj, o.Out) + } + o.ValidationDirective, err = cmdutil.GetValidationDirective(cmd) + if err != nil { + return err + } + + return nil +} + +// Run calls the CreateSubcommandOptions.Run in ClusterRoleBindingOptions instance +func (o *ClusterRoleBindingOptions) Run() error { + clusterRoleBinding, err := o.createClusterRoleBinding() + if err != nil { + return err + } + + if err := util.CreateOrUpdateAnnotation(o.CreateAnnotation, clusterRoleBinding, scheme.DefaultJSONEncoder()); err != nil { + return err + } + + if o.DryRunStrategy != cmdutil.DryRunClient { + createOptions := metav1.CreateOptions{} + if o.FieldManager != "" { + createOptions.FieldManager = o.FieldManager + } + createOptions.FieldValidation = o.ValidationDirective + if o.DryRunStrategy == cmdutil.DryRunServer { + createOptions.DryRun = []string{metav1.DryRunAll} + } + var err error + clusterRoleBinding, err = o.Client.ClusterRoleBindings().Create(context.TODO(), clusterRoleBinding, createOptions) + if err != nil { + return fmt.Errorf("failed to create clusterrolebinding: %v", err) + } + } + + return o.PrintObj(clusterRoleBinding) +} + +func (o *ClusterRoleBindingOptions) createClusterRoleBinding() (*rbacv1.ClusterRoleBinding, error) { + clusterRoleBinding := &rbacv1.ClusterRoleBinding{ + TypeMeta: metav1.TypeMeta{APIVersion: rbacv1.SchemeGroupVersion.String(), Kind: "ClusterRoleBinding"}, + ObjectMeta: metav1.ObjectMeta{ + Name: o.Name, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: rbacv1.GroupName, + Kind: "ClusterRole", + Name: o.ClusterRole, + }, + } + + for _, user := range o.Users { + clusterRoleBinding.Subjects = append(clusterRoleBinding.Subjects, rbacv1.Subject{ + Kind: rbacv1.UserKind, + APIGroup: rbacv1.GroupName, + Name: user, + }) + } + + for _, group := range o.Groups { + clusterRoleBinding.Subjects = append(clusterRoleBinding.Subjects, rbacv1.Subject{ + Kind: rbacv1.GroupKind, + APIGroup: rbacv1.GroupName, + Name: group, + }) + } + + for _, sa := range o.ServiceAccounts { + tokens := strings.Split(sa, ":") + if len(tokens) != 2 || tokens[0] == "" || tokens[1] == "" { + return nil, fmt.Errorf("serviceaccount must be :") + } + clusterRoleBinding.Subjects = append(clusterRoleBinding.Subjects, rbacv1.Subject{ + Kind: rbacv1.ServiceAccountKind, + APIGroup: "", + Namespace: tokens[0], + Name: tokens[1], + }) + } + + return clusterRoleBinding, nil +} diff --git a/vendor/k8s.io/kubectl/pkg/cmd/create/create_configmap.go b/vendor/k8s.io/kubectl/pkg/cmd/create/create_configmap.go new file mode 100644 index 000000000000..988cbb1efc6e --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/cmd/create/create_configmap.go @@ -0,0 +1,414 @@ +/* +Copyright 2016 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 create + +import ( + "context" + "fmt" + "os" + "path" + "strings" + "unicode/utf8" + + "github.com/spf13/cobra" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/validation" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/genericiooptions" + corev1client "k8s.io/client-go/kubernetes/typed/core/v1" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/scheme" + "k8s.io/kubectl/pkg/util" + "k8s.io/kubectl/pkg/util/hash" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/templates" +) + +var ( + configMapLong = templates.LongDesc(i18n.T(` + Create a config map based on a file, directory, or specified literal value. + + A single config map may package one or more key/value pairs. + + When creating a config map based on a file, the key will default to the basename of the file, and the value will + default to the file content. If the basename is an invalid key, you may specify an alternate key. + + When creating a config map based on a directory, each file whose basename is a valid key in the directory will be + packaged into the config map. Any directory entries except regular files are ignored (e.g. subdirectories, + symlinks, devices, pipes, etc).`)) + + configMapExample = templates.Examples(i18n.T(` + # Create a new config map named my-config based on folder bar + kubectl create configmap my-config --from-file=path/to/bar + + # Create a new config map named my-config with specified keys instead of file basenames on disk + kubectl create configmap my-config --from-file=key1=/path/to/bar/file1.txt --from-file=key2=/path/to/bar/file2.txt + + # Create a new config map named my-config with key1=config1 and key2=config2 + kubectl create configmap my-config --from-literal=key1=config1 --from-literal=key2=config2 + + # Create a new config map named my-config from the key=value pairs in the file + kubectl create configmap my-config --from-file=path/to/bar + + # Create a new config map named my-config from an env file + kubectl create configmap my-config --from-env-file=path/to/foo.env --from-env-file=path/to/bar.env`)) +) + +// ConfigMapOptions holds properties for create configmap sub-command +type ConfigMapOptions struct { + // PrintFlags holds options necessary for obtaining a printer + PrintFlags *genericclioptions.PrintFlags + PrintObj func(obj runtime.Object) error + + // Name of configMap (required) + Name string + // Type of configMap (optional) + Type string + // FileSources to derive the configMap from (optional) + FileSources []string + // LiteralSources to derive the configMap from (optional) + LiteralSources []string + // EnvFileSources to derive the configMap from (optional) + EnvFileSources []string + // AppendHash; if true, derive a hash from the ConfigMap and append it to the name + AppendHash bool + + FieldManager string + CreateAnnotation bool + Namespace string + EnforceNamespace bool + + Client corev1client.CoreV1Interface + DryRunStrategy cmdutil.DryRunStrategy + ValidationDirective string + + genericiooptions.IOStreams +} + +// NewConfigMapOptions creates a new *ConfigMapOptions with default value +func NewConfigMapOptions(ioStreams genericiooptions.IOStreams) *ConfigMapOptions { + return &ConfigMapOptions{ + PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme), + IOStreams: ioStreams, + } +} + +// NewCmdCreateConfigMap creates the `create configmap` Cobra command +func NewCmdCreateConfigMap(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + o := NewConfigMapOptions(ioStreams) + + cmd := &cobra.Command{ + Use: "configmap NAME [--from-file=[key=]source] [--from-literal=key1=value1] [--dry-run=server|client|none]", + DisableFlagsInUseLine: true, + Aliases: []string{"cm"}, + Short: i18n.T("Create a config map from a local file, directory or literal value"), + Long: configMapLong, + Example: configMapExample, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.Run()) + }, + } + o.PrintFlags.AddFlags(cmd) + + cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddValidateFlags(cmd) + cmdutil.AddDryRunFlag(cmd) + + cmd.Flags().StringSliceVar(&o.FileSources, "from-file", o.FileSources, "Key file can be specified using its file path, in which case file basename will be used as configmap key, or optionally with a key and file path, in which case the given key will be used. Specifying a directory will iterate each named file in the directory whose basename is a valid configmap key.") + cmd.Flags().StringArrayVar(&o.LiteralSources, "from-literal", o.LiteralSources, "Specify a key and literal value to insert in configmap (i.e. mykey=somevalue)") + cmd.Flags().StringSliceVar(&o.EnvFileSources, "from-env-file", o.EnvFileSources, "Specify the path to a file to read lines of key=val pairs to create a configmap.") + cmd.Flags().BoolVar(&o.AppendHash, "append-hash", o.AppendHash, "Append a hash of the configmap to its name.") + + cmdutil.AddFieldManagerFlagVar(cmd, &o.FieldManager, "kubectl-create") + + return cmd +} + +// Complete loads data from the command line environment +func (o *ConfigMapOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { + var err error + o.Name, err = NameFromCommandArgs(cmd, args) + if err != nil { + return err + } + + restConfig, err := f.ToRESTConfig() + if err != nil { + return err + } + + o.Client, err = corev1client.NewForConfig(restConfig) + if err != nil { + return err + } + + o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) + + o.DryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd) + if err != nil { + return err + } + + o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace() + if err != nil { + return err + } + + cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) + printer, err := o.PrintFlags.ToPrinter() + if err != nil { + return err + } + o.PrintObj = func(obj runtime.Object) error { + return printer.PrintObj(obj, o.Out) + } + + o.ValidationDirective, err = cmdutil.GetValidationDirective(cmd) + if err != nil { + return err + } + + return nil +} + +// Validate checks if ConfigMapOptions has sufficient value to run +func (o *ConfigMapOptions) Validate() error { + if len(o.Name) == 0 { + return fmt.Errorf("name must be specified") + } + if len(o.EnvFileSources) > 0 && (len(o.FileSources) > 0 || len(o.LiteralSources) > 0) { + return fmt.Errorf("from-env-file cannot be combined with from-file or from-literal") + } + return nil +} + +// Run calls createConfigMap and filled in value for configMap object +func (o *ConfigMapOptions) Run() error { + configMap, err := o.createConfigMap() + if err != nil { + return err + } + if err := util.CreateOrUpdateAnnotation(o.CreateAnnotation, configMap, scheme.DefaultJSONEncoder()); err != nil { + return err + } + if o.DryRunStrategy != cmdutil.DryRunClient { + createOptions := metav1.CreateOptions{} + if o.FieldManager != "" { + createOptions.FieldManager = o.FieldManager + } + createOptions.FieldValidation = o.ValidationDirective + if o.DryRunStrategy == cmdutil.DryRunServer { + createOptions.DryRun = []string{metav1.DryRunAll} + } + configMap, err = o.Client.ConfigMaps(o.Namespace).Create(context.TODO(), configMap, createOptions) + if err != nil { + return fmt.Errorf("failed to create configmap: %v", err) + } + } + + return o.PrintObj(configMap) +} + +// createConfigMap fills in key value pair from the information given in +// ConfigMapOptions into *corev1.ConfigMap +func (o *ConfigMapOptions) createConfigMap() (*corev1.ConfigMap, error) { + namespace := "" + if o.EnforceNamespace { + namespace = o.Namespace + } + + configMap := &corev1.ConfigMap{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "ConfigMap", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: o.Name, + Namespace: namespace, + }, + } + configMap.Name = o.Name + configMap.Data = map[string]string{} + configMap.BinaryData = map[string][]byte{} + + if len(o.FileSources) > 0 { + if err := handleConfigMapFromFileSources(configMap, o.FileSources); err != nil { + return nil, err + } + } + if len(o.LiteralSources) > 0 { + if err := handleConfigMapFromLiteralSources(configMap, o.LiteralSources); err != nil { + return nil, err + } + } + if len(o.EnvFileSources) > 0 { + if err := handleConfigMapFromEnvFileSources(configMap, o.EnvFileSources); err != nil { + return nil, err + } + } + if o.AppendHash { + hash, err := hash.ConfigMapHash(configMap) + if err != nil { + return nil, err + } + configMap.Name = fmt.Sprintf("%s-%s", configMap.Name, hash) + } + + return configMap, nil +} + +// handleConfigMapFromLiteralSources adds the specified literal source +// information into the provided configMap. +func handleConfigMapFromLiteralSources(configMap *corev1.ConfigMap, literalSources []string) error { + for _, literalSource := range literalSources { + keyName, value, err := util.ParseLiteralSource(literalSource) + if err != nil { + return err + } + err = addKeyFromLiteralToConfigMap(configMap, keyName, value) + if err != nil { + return err + } + } + + return nil +} + +// handleConfigMapFromFileSources adds the specified file source information +// into the provided configMap +func handleConfigMapFromFileSources(configMap *corev1.ConfigMap, fileSources []string) error { + for _, fileSource := range fileSources { + keyName, filePath, err := util.ParseFileSource(fileSource) + if err != nil { + return err + } + info, err := os.Stat(filePath) + if err != nil { + switch err := err.(type) { + case *os.PathError: + return fmt.Errorf("error reading %s: %v", filePath, err.Err) + default: + return fmt.Errorf("error reading %s: %v", filePath, err) + } + + } + if info.IsDir() { + if strings.Contains(fileSource, "=") { + return fmt.Errorf("cannot give a key name for a directory path") + } + fileList, err := os.ReadDir(filePath) + if err != nil { + return fmt.Errorf("error listing files in %s: %v", filePath, err) + } + for _, item := range fileList { + itemPath := path.Join(filePath, item.Name()) + if item.Type().IsRegular() { + keyName = item.Name() + err = addKeyFromFileToConfigMap(configMap, keyName, itemPath) + if err != nil { + return err + } + } + } + } else { + if err := addKeyFromFileToConfigMap(configMap, keyName, filePath); err != nil { + return err + } + + } + } + return nil +} + +// handleConfigMapFromEnvFileSources adds the specified env file source information +// into the provided configMap +func handleConfigMapFromEnvFileSources(configMap *corev1.ConfigMap, envFileSources []string) error { + for _, envFileSource := range envFileSources { + info, err := os.Stat(envFileSource) + if err != nil { + switch err := err.(type) { + case *os.PathError: + return fmt.Errorf("error reading %s: %v", envFileSource, err.Err) + default: + return fmt.Errorf("error reading %s: %v", envFileSource, err) + } + } + if info.IsDir() { + return fmt.Errorf("env config file cannot be a directory") + } + err = cmdutil.AddFromEnvFile(envFileSource, func(key, value string) error { + return addKeyFromLiteralToConfigMap(configMap, key, value) + }) + if err != nil { + return err + } + } + + return nil +} + +// addKeyFromFileToConfigMap adds a key with the given name to a ConfigMap, populating +// the value with the content of the given file path, or returns an error. +func addKeyFromFileToConfigMap(configMap *corev1.ConfigMap, keyName, filePath string) error { + data, err := os.ReadFile(filePath) + if err != nil { + return err + } + if utf8.Valid(data) { + return addKeyFromLiteralToConfigMap(configMap, keyName, string(data)) + } + err = validateNewConfigMap(configMap, keyName) + if err != nil { + return err + } + configMap.BinaryData[keyName] = data + + return nil +} + +// addKeyFromLiteralToConfigMap adds the given key and data to the given config map, +// returning an error if the key is not valid or if the key already exists. +func addKeyFromLiteralToConfigMap(configMap *corev1.ConfigMap, keyName, data string) error { + err := validateNewConfigMap(configMap, keyName) + if err != nil { + return err + } + configMap.Data[keyName] = data + + return nil +} + +// validateNewConfigMap checks whether the keyname is valid +// Note, the rules for ConfigMap keys are the exact same as the ones for SecretKeys. +func validateNewConfigMap(configMap *corev1.ConfigMap, keyName string) error { + if errs := validation.IsConfigMapKey(keyName); len(errs) > 0 { + return fmt.Errorf("%q is not a valid key name for a ConfigMap: %s", keyName, strings.Join(errs, ",")) + } + if _, exists := configMap.Data[keyName]; exists { + return fmt.Errorf("cannot add key %q, another key by that name already exists in Data for ConfigMap %q", keyName, configMap.Name) + } + if _, exists := configMap.BinaryData[keyName]; exists { + return fmt.Errorf("cannot add key %q, another key by that name already exists in BinaryData for ConfigMap %q", keyName, configMap.Name) + } + + return nil +} diff --git a/vendor/k8s.io/kubectl/pkg/cmd/create/create_cronjob.go b/vendor/k8s.io/kubectl/pkg/cmd/create/create_cronjob.go new file mode 100644 index 000000000000..5c0821d9da6b --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/cmd/create/create_cronjob.go @@ -0,0 +1,226 @@ +/* +Copyright 2018 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 create + +import ( + "context" + "fmt" + + "github.com/spf13/cobra" + + batchv1 "k8s.io/api/batch/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/genericiooptions" + "k8s.io/cli-runtime/pkg/resource" + batchv1client "k8s.io/client-go/kubernetes/typed/batch/v1" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/scheme" + "k8s.io/kubectl/pkg/util" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/templates" +) + +var ( + cronjobLong = templates.LongDesc(i18n.T(` + Create a cron job with the specified name.`)) + + cronjobExample = templates.Examples(` + # Create a cron job + kubectl create cronjob my-job --image=busybox --schedule="*/1 * * * *" + + # Create a cron job with a command + kubectl create cronjob my-job --image=busybox --schedule="*/1 * * * *" -- date`) +) + +// CreateCronJobOptions is returned by NewCreateCronJobOptions +type CreateCronJobOptions struct { + PrintFlags *genericclioptions.PrintFlags + + PrintObj func(obj runtime.Object) error + + Name string + Image string + Schedule string + Command []string + Restart string + + Namespace string + EnforceNamespace bool + Client batchv1client.BatchV1Interface + DryRunStrategy cmdutil.DryRunStrategy + ValidationDirective string + Builder *resource.Builder + FieldManager string + CreateAnnotation bool + + genericiooptions.IOStreams +} + +// NewCreateCronJobOptions returns an initialized CreateCronJobOptions instance +func NewCreateCronJobOptions(ioStreams genericiooptions.IOStreams) *CreateCronJobOptions { + return &CreateCronJobOptions{ + PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme), + IOStreams: ioStreams, + } +} + +// NewCmdCreateCronJob is a command to create CronJobs. +func NewCmdCreateCronJob(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + o := NewCreateCronJobOptions(ioStreams) + cmd := &cobra.Command{ + Use: "cronjob NAME --image=image --schedule='0/5 * * * ?' -- [COMMAND] [args...]", + DisableFlagsInUseLine: false, + Aliases: []string{"cj"}, + Short: i18n.T("Create a cron job with the specified name"), + Long: cronjobLong, + Example: cronjobExample, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Run()) + }, + } + + o.PrintFlags.AddFlags(cmd) + + cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddValidateFlags(cmd) + cmdutil.AddDryRunFlag(cmd) + cmd.Flags().StringVar(&o.Image, "image", o.Image, "Image name to run.") + cmd.MarkFlagRequired("image") + cmd.Flags().StringVar(&o.Schedule, "schedule", o.Schedule, "A schedule in the Cron format the job should be run with.") + cmd.MarkFlagRequired("schedule") + cmd.Flags().StringVar(&o.Restart, "restart", o.Restart, "job's restart policy. supported values: OnFailure, Never") + cmdutil.AddFieldManagerFlagVar(cmd, &o.FieldManager, "kubectl-create") + + return cmd +} + +// Complete completes all the required options +func (o *CreateCronJobOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { + name, err := NameFromCommandArgs(cmd, args) + if err != nil { + return err + } + o.Name = name + if len(args) > 1 { + o.Command = args[1:] + } + if len(o.Restart) == 0 { + o.Restart = "OnFailure" + } + + clientConfig, err := f.ToRESTConfig() + if err != nil { + return err + } + o.Client, err = batchv1client.NewForConfig(clientConfig) + if err != nil { + return err + } + + o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace() + if err != nil { + return err + } + o.Builder = f.NewBuilder() + + o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) + + o.DryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd) + if err != nil { + return err + } + cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) + printer, err := o.PrintFlags.ToPrinter() + if err != nil { + return err + } + o.PrintObj = func(obj runtime.Object) error { + return printer.PrintObj(obj, o.Out) + } + + o.ValidationDirective, err = cmdutil.GetValidationDirective(cmd) + if err != nil { + return err + } + + return nil +} + +// Run performs the execution of 'create cronjob' sub command +func (o *CreateCronJobOptions) Run() error { + cronJob := o.createCronJob() + if err := util.CreateOrUpdateAnnotation(o.CreateAnnotation, cronJob, scheme.DefaultJSONEncoder()); err != nil { + return err + } + + if o.DryRunStrategy != cmdutil.DryRunClient { + createOptions := metav1.CreateOptions{} + if o.FieldManager != "" { + createOptions.FieldManager = o.FieldManager + } + createOptions.FieldValidation = o.ValidationDirective + if o.DryRunStrategy == cmdutil.DryRunServer { + createOptions.DryRun = []string{metav1.DryRunAll} + } + var err error + cronJob, err = o.Client.CronJobs(o.Namespace).Create(context.TODO(), cronJob, createOptions) + if err != nil { + return fmt.Errorf("failed to create cronjob: %v", err) + } + } + + return o.PrintObj(cronJob) +} + +func (o *CreateCronJobOptions) createCronJob() *batchv1.CronJob { + cronjob := &batchv1.CronJob{ + TypeMeta: metav1.TypeMeta{APIVersion: batchv1.SchemeGroupVersion.String(), Kind: "CronJob"}, + ObjectMeta: metav1.ObjectMeta{ + Name: o.Name, + }, + Spec: batchv1.CronJobSpec{ + Schedule: o.Schedule, + JobTemplate: batchv1.JobTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Name: o.Name, + }, + Spec: batchv1.JobSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: o.Name, + Image: o.Image, + Command: o.Command, + }, + }, + RestartPolicy: corev1.RestartPolicy(o.Restart), + }, + }, + }, + }, + }, + } + if o.EnforceNamespace { + cronjob.Namespace = o.Namespace + } + return cronjob +} diff --git a/vendor/k8s.io/kubectl/pkg/cmd/create/create_deployment.go b/vendor/k8s.io/kubectl/pkg/cmd/create/create_deployment.go new file mode 100644 index 000000000000..519c7fb6223a --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/cmd/create/create_deployment.go @@ -0,0 +1,278 @@ +/* +Copyright 2016 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 create + +import ( + "context" + "fmt" + "strings" + + "github.com/spf13/cobra" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + utilrand "k8s.io/apimachinery/pkg/util/rand" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/genericiooptions" + appsv1client "k8s.io/client-go/kubernetes/typed/apps/v1" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/scheme" + "k8s.io/kubectl/pkg/util" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/templates" +) + +var ( + deploymentLong = templates.LongDesc(i18n.T(` + Create a deployment with the specified name.`)) + + deploymentExample = templates.Examples(i18n.T(` + # Create a deployment named my-dep that runs the busybox image + kubectl create deployment my-dep --image=busybox + + # Create a deployment with a command + kubectl create deployment my-dep --image=busybox -- date + + # Create a deployment named my-dep that runs the nginx image with 3 replicas + kubectl create deployment my-dep --image=nginx --replicas=3 + + # Create a deployment named my-dep that runs the busybox image and expose port 5701 + kubectl create deployment my-dep --image=busybox --port=5701 + + # Create a deployment named my-dep that runs multiple containers + kubectl create deployment my-dep --image=busybox:latest --image=ubuntu:latest --image=nginx`)) +) + +// CreateDeploymentOptions is returned by NewCmdCreateDeployment +type CreateDeploymentOptions struct { + PrintFlags *genericclioptions.PrintFlags + + PrintObj func(obj runtime.Object) error + + Name string + Images []string + Port int32 + Replicas int32 + Command []string + Namespace string + EnforceNamespace bool + FieldManager string + CreateAnnotation bool + + Client appsv1client.AppsV1Interface + DryRunStrategy cmdutil.DryRunStrategy + ValidationDirective string + + genericiooptions.IOStreams +} + +// NewCreateDeploymentOptions returns an initialized CreateDeploymentOptions instance +func NewCreateDeploymentOptions(ioStreams genericiooptions.IOStreams) *CreateDeploymentOptions { + return &CreateDeploymentOptions{ + Port: -1, + Replicas: 1, + PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme), + IOStreams: ioStreams, + } +} + +// NewCmdCreateDeployment is a macro command to create a new deployment. +// This command is better known to users as `kubectl create deployment`. +func NewCmdCreateDeployment(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + o := NewCreateDeploymentOptions(ioStreams) + cmd := &cobra.Command{ + Use: "deployment NAME --image=image -- [COMMAND] [args...]", + DisableFlagsInUseLine: true, + Aliases: []string{"deploy"}, + Short: i18n.T("Create a deployment with the specified name"), + Long: deploymentLong, + Example: deploymentExample, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.Run()) + }, + } + + o.PrintFlags.AddFlags(cmd) + + cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddValidateFlags(cmd) + cmdutil.AddDryRunFlag(cmd) + cmd.Flags().StringSliceVar(&o.Images, "image", o.Images, "Image names to run. A deployment can have multiple images set for multi-container pod.") + cmd.MarkFlagRequired("image") + cmd.Flags().Int32Var(&o.Port, "port", o.Port, "The containerPort that this deployment exposes.") + cmd.Flags().Int32VarP(&o.Replicas, "replicas", "r", o.Replicas, "Number of replicas to create. Default is 1.") + cmdutil.AddFieldManagerFlagVar(cmd, &o.FieldManager, "kubectl-create") + + return cmd +} + +// Complete completes all the options +func (o *CreateDeploymentOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { + name, err := NameFromCommandArgs(cmd, args) + if err != nil { + return err + } + o.Name = name + if len(args) > 1 { + o.Command = args[1:] + } + + clientConfig, err := f.ToRESTConfig() + if err != nil { + return err + } + o.Client, err = appsv1client.NewForConfig(clientConfig) + if err != nil { + return err + } + + o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace() + if err != nil { + return err + } + + o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) + + o.DryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd) + if err != nil { + return err + } + cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) + + printer, err := o.PrintFlags.ToPrinter() + if err != nil { + return err + } + o.PrintObj = func(obj runtime.Object) error { + return printer.PrintObj(obj, o.Out) + } + + o.ValidationDirective, err = cmdutil.GetValidationDirective(cmd) + if err != nil { + return err + } + + return nil +} + +// Validate makes sure there is no discrepency in provided option values +func (o *CreateDeploymentOptions) Validate() error { + if len(o.Images) > 1 && len(o.Command) > 0 { + return fmt.Errorf("cannot specify multiple --image options and command") + } + return nil +} + +// Run performs the execution of 'create deployment' sub command +func (o *CreateDeploymentOptions) Run() error { + deploy := o.createDeployment() + + if err := util.CreateOrUpdateAnnotation(o.CreateAnnotation, deploy, scheme.DefaultJSONEncoder()); err != nil { + return err + } + + if o.DryRunStrategy != cmdutil.DryRunClient { + createOptions := metav1.CreateOptions{} + if o.FieldManager != "" { + createOptions.FieldManager = o.FieldManager + } + createOptions.FieldValidation = o.ValidationDirective + if o.DryRunStrategy == cmdutil.DryRunServer { + createOptions.DryRun = []string{metav1.DryRunAll} + } + var err error + deploy, err = o.Client.Deployments(o.Namespace).Create(context.TODO(), deploy, createOptions) + if err != nil { + return fmt.Errorf("failed to create deployment: %v", err) + } + } + + return o.PrintObj(deploy) +} + +func (o *CreateDeploymentOptions) createDeployment() *appsv1.Deployment { + labels := map[string]string{"app": o.Name} + selector := metav1.LabelSelector{MatchLabels: labels} + namespace := "" + if o.EnforceNamespace { + namespace = o.Namespace + } + + deploy := &appsv1.Deployment{ + TypeMeta: metav1.TypeMeta{APIVersion: appsv1.SchemeGroupVersion.String(), Kind: "Deployment"}, + ObjectMeta: metav1.ObjectMeta{ + Name: o.Name, + Labels: labels, + Namespace: namespace, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: &o.Replicas, + Selector: &selector, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: labels, + }, + Spec: o.buildPodSpec(), + }, + }, + } + + if o.Port >= 0 && len(deploy.Spec.Template.Spec.Containers) > 0 { + deploy.Spec.Template.Spec.Containers[0].Ports = []corev1.ContainerPort{{ContainerPort: o.Port}} + } + return deploy +} + +// buildPodSpec parses the image strings and assemble them into the Containers +// of a PodSpec. This is all you need to create the PodSpec for a deployment. +func (o *CreateDeploymentOptions) buildPodSpec() corev1.PodSpec { + podSpec := corev1.PodSpec{Containers: []corev1.Container{}} + for _, imageString := range o.Images { + // Retain just the image name + imageSplit := strings.Split(imageString, "/") + name := imageSplit[len(imageSplit)-1] + // Remove any tag or hash + if strings.Contains(name, ":") { + name = strings.Split(name, ":")[0] + } + if strings.Contains(name, "@") { + name = strings.Split(name, "@")[0] + } + name = sanitizeAndUniquify(name) + podSpec.Containers = append(podSpec.Containers, corev1.Container{ + Name: name, + Image: imageString, + Command: o.Command, + }) + } + return podSpec +} + +// sanitizeAndUniquify replaces characters like "." or "_" into "-" to follow DNS1123 rules. +// Then add random suffix to make it uniquified. +func sanitizeAndUniquify(name string) string { + if strings.ContainsAny(name, "_.") { + name = strings.Replace(name, "_", "-", -1) + name = strings.Replace(name, ".", "-", -1) + name = fmt.Sprintf("%s-%s", name, utilrand.String(5)) + } + return name +} diff --git a/vendor/k8s.io/kubectl/pkg/cmd/create/create_ingress.go b/vendor/k8s.io/kubectl/pkg/cmd/create/create_ingress.go new file mode 100644 index 000000000000..d71048cdcb9f --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/cmd/create/create_ingress.go @@ -0,0 +1,458 @@ +/* +Copyright 2020 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 create + +import ( + "context" + "fmt" + "regexp" + "strings" + + "github.com/spf13/cobra" + + networkingv1 "k8s.io/api/networking/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/genericiooptions" + networkingv1client "k8s.io/client-go/kubernetes/typed/networking/v1" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/scheme" + "k8s.io/kubectl/pkg/util" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/templates" +) + +var ( + // Explaining the Regex below: + // ^(?P[\w\*\-\.]*) -> Indicates the host - 0-N characters of letters, number, underscore, '-', '.' and '*' + // (?P/.*) -> Indicates the path and MUST start with '/' - / + 0-N characters + // Separator from host/path to svcname:svcport -> "=" + // (?P[\w\-]+) -> Service Name (letters, numbers, '-') -> 1-N characters + // Separator from svcname to svcport -> ":" + // (?P[\w\-]+) -> Service Port (letters, numbers, '-') -> 1-N characters + regexHostPathSvc = `^(?P[\w\*\-\.]*)(?P/.*)=(?P[\w\-]+):(?P[\w\-]+)` + + // This Regex is optional -> (....)? + // (?Ptls) -> Verify if the argument after "," is 'tls' + // Optional Separator from tls to the secret name -> "=?" + // (?P[\w\-]+)? -> Optional secret name after the separator -> 1-N characters + regexTLS = `(,(?Ptls)=?(?P[\w\-]+)?)?` + + // The validation Regex is the concatenation of hostPathSvc validation regex + // and the TLS validation regex + ruleRegex = regexHostPathSvc + regexTLS + + ingressLong = templates.LongDesc(i18n.T(` + Create an ingress with the specified name.`)) + + ingressExample = templates.Examples(i18n.T(` + # Create a single ingress called 'simple' that directs requests to foo.com/bar to svc + # svc1:8080 with a TLS secret "my-cert" + kubectl create ingress simple --rule="foo.com/bar=svc1:8080,tls=my-cert" + + # Create a catch all ingress of "/path" pointing to service svc:port and Ingress Class as "otheringress" + kubectl create ingress catch-all --class=otheringress --rule="/path=svc:port" + + # Create an ingress with two annotations: ingress.annotation1 and ingress.annotations2 + kubectl create ingress annotated --class=default --rule="foo.com/bar=svc:port" \ + --annotation ingress.annotation1=foo \ + --annotation ingress.annotation2=bla + + # Create an ingress with the same host and multiple paths + kubectl create ingress multipath --class=default \ + --rule="foo.com/=svc:port" \ + --rule="foo.com/admin/=svcadmin:portadmin" + + # Create an ingress with multiple hosts and the pathType as Prefix + kubectl create ingress ingress1 --class=default \ + --rule="foo.com/path*=svc:8080" \ + --rule="bar.com/admin*=svc2:http" + + # Create an ingress with TLS enabled using the default ingress certificate and different path types + kubectl create ingress ingtls --class=default \ + --rule="foo.com/=svc:https,tls" \ + --rule="foo.com/path/subpath*=othersvc:8080" + + # Create an ingress with TLS enabled using a specific secret and pathType as Prefix + kubectl create ingress ingsecret --class=default \ + --rule="foo.com/*=svc:8080,tls=secret1" + + # Create an ingress with a default backend + kubectl create ingress ingdefault --class=default \ + --default-backend=defaultsvc:http \ + --rule="foo.com/*=svc:8080,tls=secret1" + + `)) +) + +// CreateIngressOptions is returned by NewCmdCreateIngress +type CreateIngressOptions struct { + PrintFlags *genericclioptions.PrintFlags + + PrintObj func(obj runtime.Object) error + + Name string + IngressClass string + Rules []string + Annotations []string + DefaultBackend string + Namespace string + EnforceNamespace bool + CreateAnnotation bool + + Client networkingv1client.NetworkingV1Interface + DryRunStrategy cmdutil.DryRunStrategy + ValidationDirective string + + FieldManager string + + genericiooptions.IOStreams +} + +// NewCreateIngressOptions creates the CreateIngressOptions to be used later +func NewCreateIngressOptions(ioStreams genericiooptions.IOStreams) *CreateIngressOptions { + return &CreateIngressOptions{ + PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme), + IOStreams: ioStreams, + } +} + +// NewCmdCreateIngress is a macro command to create a new ingress. +// This command is better known to users as `kubectl create ingress`. +func NewCmdCreateIngress(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + o := NewCreateIngressOptions(ioStreams) + + cmd := &cobra.Command{ + Use: "ingress NAME --rule=host/path=service:port[,tls[=secret]] ", + DisableFlagsInUseLine: true, + Aliases: []string{"ing"}, + Short: i18n.T("Create an ingress with the specified name"), + Long: ingressLong, + Example: ingressExample, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.Run()) + }, + } + + o.PrintFlags.AddFlags(cmd) + + cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddValidateFlags(cmd) + cmdutil.AddDryRunFlag(cmd) + cmd.Flags().StringVar(&o.IngressClass, "class", o.IngressClass, "Ingress Class to be used") + cmd.Flags().StringArrayVar(&o.Rules, "rule", o.Rules, "Rule in format host/path=service:port[,tls=secretname]. Paths containing the leading character '*' are considered pathType=Prefix. tls argument is optional.") + cmd.Flags().StringVar(&o.DefaultBackend, "default-backend", o.DefaultBackend, "Default service for backend, in format of svcname:port") + cmd.Flags().StringArrayVar(&o.Annotations, "annotation", o.Annotations, "Annotation to insert in the ingress object, in the format annotation=value") + cmdutil.AddFieldManagerFlagVar(cmd, &o.FieldManager, "kubectl-create") + + return cmd +} + +// Complete completes all the options +func (o *CreateIngressOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { + name, err := NameFromCommandArgs(cmd, args) + if err != nil { + return err + } + o.Name = name + + clientConfig, err := f.ToRESTConfig() + if err != nil { + return err + } + o.Client, err = networkingv1client.NewForConfig(clientConfig) + if err != nil { + return err + } + + o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace() + if err != nil { + return err + } + + o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) + + o.DryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd) + if err != nil { + return err + } + cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) + + printer, err := o.PrintFlags.ToPrinter() + if err != nil { + return err + } + o.PrintObj = func(obj runtime.Object) error { + return printer.PrintObj(obj, o.Out) + } + + o.ValidationDirective, err = cmdutil.GetValidationDirective(cmd) + return err +} + +// Validate validates the Ingress object to be created +func (o *CreateIngressOptions) Validate() error { + if len(o.DefaultBackend) == 0 && len(o.Rules) == 0 { + return fmt.Errorf("not enough information provided: every ingress has to either specify a default-backend (which catches all traffic) or a list of rules (which catch specific paths)") + } + + rulevalidation, err := regexp.Compile(ruleRegex) + if err != nil { + return fmt.Errorf("failed to compile the regex") + } + + for _, rule := range o.Rules { + if match := rulevalidation.MatchString(rule); !match { + return fmt.Errorf("rule %s is invalid and should be in format host/path=svcname:svcport[,tls[=secret]]", rule) + } + } + + for _, annotation := range o.Annotations { + if an := strings.SplitN(annotation, "=", 2); len(an) != 2 { + return fmt.Errorf("annotation %s is invalid and should be in format key=[value]", annotation) + } + } + + if len(o.DefaultBackend) > 0 && len(strings.Split(o.DefaultBackend, ":")) != 2 { + return fmt.Errorf("default-backend should be in format servicename:serviceport") + } + + return nil +} + +// Run performs the execution of 'create ingress' sub command +func (o *CreateIngressOptions) Run() error { + ingress := o.createIngress() + + if err := util.CreateOrUpdateAnnotation(o.CreateAnnotation, ingress, scheme.DefaultJSONEncoder()); err != nil { + return err + } + + if o.DryRunStrategy != cmdutil.DryRunClient { + createOptions := metav1.CreateOptions{} + if o.FieldManager != "" { + createOptions.FieldManager = o.FieldManager + } + createOptions.FieldValidation = o.ValidationDirective + if o.DryRunStrategy == cmdutil.DryRunServer { + createOptions.DryRun = []string{metav1.DryRunAll} + } + var err error + ingress, err = o.Client.Ingresses(o.Namespace).Create(context.TODO(), ingress, createOptions) + if err != nil { + return fmt.Errorf("failed to create ingress: %v", err) + } + } + return o.PrintObj(ingress) +} + +func (o *CreateIngressOptions) createIngress() *networkingv1.Ingress { + namespace := "" + if o.EnforceNamespace { + namespace = o.Namespace + } + + annotations := o.buildAnnotations() + spec := o.buildIngressSpec() + + ingress := &networkingv1.Ingress{ + TypeMeta: metav1.TypeMeta{APIVersion: networkingv1.SchemeGroupVersion.String(), Kind: "Ingress"}, + ObjectMeta: metav1.ObjectMeta{ + Name: o.Name, + Namespace: namespace, + Annotations: annotations, + }, + Spec: spec, + } + return ingress +} + +func (o *CreateIngressOptions) buildAnnotations() map[string]string { + + var annotations = make(map[string]string) + + for _, annotation := range o.Annotations { + an := strings.SplitN(annotation, "=", 2) + annotations[an[0]] = an[1] + } + return annotations +} + +// buildIngressSpec builds the .spec from the diverse arguments passed to kubectl +func (o *CreateIngressOptions) buildIngressSpec() networkingv1.IngressSpec { + var ingressSpec networkingv1.IngressSpec + + if len(o.IngressClass) > 0 { + ingressSpec.IngressClassName = &o.IngressClass + } + + if len(o.DefaultBackend) > 0 { + defaultbackend := buildIngressBackendSvc(o.DefaultBackend) + ingressSpec.DefaultBackend = &defaultbackend + } + ingressSpec.TLS = o.buildTLSRules() + ingressSpec.Rules = o.buildIngressRules() + + return ingressSpec +} + +func (o *CreateIngressOptions) buildTLSRules() []networkingv1.IngressTLS { + hostAlreadyPresent := make(map[string]struct{}) + + ingressTLSs := []networkingv1.IngressTLS{} + var secret string + + for _, rule := range o.Rules { + tls := strings.Split(rule, ",") + + if len(tls) == 2 { + ingressTLS := networkingv1.IngressTLS{} + host := strings.SplitN(rule, "/", 2)[0] + secret = "" + secretName := strings.Split(tls[1], "=") + + if len(secretName) > 1 { + secret = secretName[1] + } + + idxSecret := getIndexSecret(secret, ingressTLSs) + // We accept the same host into TLS secrets only once + if _, ok := hostAlreadyPresent[host]; !ok { + if idxSecret > -1 { + ingressTLSs[idxSecret].Hosts = append(ingressTLSs[idxSecret].Hosts, host) + hostAlreadyPresent[host] = struct{}{} + continue + } + if host != "" { + ingressTLS.Hosts = append(ingressTLS.Hosts, host) + } + if secret != "" { + ingressTLS.SecretName = secret + } + if len(ingressTLS.SecretName) > 0 || len(ingressTLS.Hosts) > 0 { + ingressTLSs = append(ingressTLSs, ingressTLS) + } + hostAlreadyPresent[host] = struct{}{} + } + } + } + return ingressTLSs +} + +// buildIngressRules builds the .spec.rules for an ingress object. +func (o *CreateIngressOptions) buildIngressRules() []networkingv1.IngressRule { + ingressRules := []networkingv1.IngressRule{} + + for _, rule := range o.Rules { + removeTLS := strings.Split(rule, ",")[0] + hostSplit := strings.SplitN(removeTLS, "/", 2) + host := hostSplit[0] + ingressPath := buildHTTPIngressPath(hostSplit[1]) + ingressRule := networkingv1.IngressRule{} + + if host != "" { + ingressRule.Host = host + } + + idxHost := getIndexHost(ingressRule.Host, ingressRules) + if idxHost > -1 { + ingressRules[idxHost].IngressRuleValue.HTTP.Paths = append(ingressRules[idxHost].IngressRuleValue.HTTP.Paths, ingressPath) + continue + } + + ingressRule.IngressRuleValue = networkingv1.IngressRuleValue{ + HTTP: &networkingv1.HTTPIngressRuleValue{ + Paths: []networkingv1.HTTPIngressPath{ + ingressPath, + }, + }, + } + ingressRules = append(ingressRules, ingressRule) + } + return ingressRules +} + +func buildHTTPIngressPath(pathsvc string) networkingv1.HTTPIngressPath { + pathsvcsplit := strings.Split(pathsvc, "=") + path := "/" + pathsvcsplit[0] + service := pathsvcsplit[1] + + var pathType networkingv1.PathType + pathType = "Exact" + + // If * in the End, turn pathType=Prefix but remove the * from the end + if path[len(path)-1:] == "*" { + pathType = "Prefix" + path = path[0 : len(path)-1] + } + + httpIngressPath := networkingv1.HTTPIngressPath{ + Path: path, + PathType: &pathType, + Backend: buildIngressBackendSvc(service), + } + return httpIngressPath +} + +func buildIngressBackendSvc(service string) networkingv1.IngressBackend { + svcname := strings.Split(service, ":")[0] + svcport := strings.Split(service, ":")[1] + + ingressBackend := networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: svcname, + Port: parseServiceBackendPort(svcport), + }, + } + return ingressBackend +} + +func parseServiceBackendPort(port string) networkingv1.ServiceBackendPort { + var backendPort networkingv1.ServiceBackendPort + portIntOrStr := intstr.Parse(port) + + if portIntOrStr.Type == intstr.Int { + backendPort.Number = portIntOrStr.IntVal + } + + if portIntOrStr.Type == intstr.String { + backendPort.Name = portIntOrStr.StrVal + } + return backendPort +} + +func getIndexHost(host string, rules []networkingv1.IngressRule) int { + for index, v := range rules { + if v.Host == host { + return index + } + } + return -1 +} + +func getIndexSecret(secretname string, tls []networkingv1.IngressTLS) int { + for index, v := range tls { + if v.SecretName == secretname { + return index + } + } + return -1 +} diff --git a/vendor/k8s.io/kubectl/pkg/cmd/create/create_job.go b/vendor/k8s.io/kubectl/pkg/cmd/create/create_job.go new file mode 100644 index 000000000000..811720d4f126 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/cmd/create/create_job.go @@ -0,0 +1,287 @@ +/* +Copyright 2018 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 create + +import ( + "context" + "fmt" + + "github.com/spf13/cobra" + + batchv1 "k8s.io/api/batch/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/genericiooptions" + "k8s.io/cli-runtime/pkg/resource" + batchv1client "k8s.io/client-go/kubernetes/typed/batch/v1" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/scheme" + "k8s.io/kubectl/pkg/util" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/templates" + "k8s.io/utils/ptr" +) + +var ( + jobLong = templates.LongDesc(i18n.T(` + Create a job with the specified name.`)) + + jobExample = templates.Examples(i18n.T(` + # Create a job + kubectl create job my-job --image=busybox + + # Create a job with a command + kubectl create job my-job --image=busybox -- date + + # Create a job from a cron job named "a-cronjob" + kubectl create job test-job --from=cronjob/a-cronjob`)) +) + +// CreateJobOptions is the command line options for 'create job' +type CreateJobOptions struct { + PrintFlags *genericclioptions.PrintFlags + + PrintObj func(obj runtime.Object) error + + Name string + Image string + From string + Command []string + + Namespace string + EnforceNamespace bool + Client batchv1client.BatchV1Interface + DryRunStrategy cmdutil.DryRunStrategy + ValidationDirective string + Builder *resource.Builder + FieldManager string + CreateAnnotation bool + + genericiooptions.IOStreams +} + +// NewCreateJobOptions initializes and returns new CreateJobOptions instance +func NewCreateJobOptions(ioStreams genericiooptions.IOStreams) *CreateJobOptions { + return &CreateJobOptions{ + PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme), + IOStreams: ioStreams, + } +} + +// NewCmdCreateJob is a command to ease creating Jobs from CronJobs. +func NewCmdCreateJob(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + o := NewCreateJobOptions(ioStreams) + cmd := &cobra.Command{ + Use: "job NAME --image=image [--from=cronjob/name] -- [COMMAND] [args...]", + DisableFlagsInUseLine: true, + Short: i18n.T("Create a job with the specified name"), + Long: jobLong, + Example: jobExample, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.Run()) + }, + } + + o.PrintFlags.AddFlags(cmd) + + cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddValidateFlags(cmd) + cmdutil.AddDryRunFlag(cmd) + cmd.Flags().StringVar(&o.Image, "image", o.Image, "Image name to run.") + cmd.Flags().StringVar(&o.From, "from", o.From, "The name of the resource to create a Job from (only cronjob is supported).") + cmdutil.AddFieldManagerFlagVar(cmd, &o.FieldManager, "kubectl-create") + return cmd +} + +// Complete completes all the required options +func (o *CreateJobOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { + name, err := NameFromCommandArgs(cmd, args) + if err != nil { + return err + } + o.Name = name + if len(args) > 1 { + o.Command = args[1:] + } + + clientConfig, err := f.ToRESTConfig() + if err != nil { + return err + } + o.Client, err = batchv1client.NewForConfig(clientConfig) + if err != nil { + return err + } + + o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) + + o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace() + if err != nil { + return err + } + o.Builder = f.NewBuilder() + + o.DryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd) + if err != nil { + return err + } + cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) + printer, err := o.PrintFlags.ToPrinter() + if err != nil { + return err + } + o.PrintObj = func(obj runtime.Object) error { + return printer.PrintObj(obj, o.Out) + } + + o.ValidationDirective, err = cmdutil.GetValidationDirective(cmd) + if err != nil { + return err + } + + return nil +} + +// Validate makes sure provided values and valid Job options +func (o *CreateJobOptions) Validate() error { + if (len(o.Image) == 0 && len(o.From) == 0) || (len(o.Image) != 0 && len(o.From) != 0) { + return fmt.Errorf("either --image or --from must be specified") + } + if o.Command != nil && len(o.Command) != 0 && len(o.From) != 0 { + return fmt.Errorf("cannot specify --from and command") + } + return nil +} + +// Run performs the execution of 'create job' sub command +func (o *CreateJobOptions) Run() error { + var job *batchv1.Job + if len(o.Image) > 0 { + job = o.createJob() + } else { + infos, err := o.Builder. + WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...). + NamespaceParam(o.Namespace).DefaultNamespace(). + ResourceTypeOrNameArgs(false, o.From). + Flatten(). + Latest(). + Do(). + Infos() + if err != nil { + return err + } + if len(infos) != 1 { + return fmt.Errorf("from must be an existing cronjob") + } + + switch obj := infos[0].Object.(type) { + case *batchv1.CronJob: + job = o.createJobFromCronJob(obj) + default: + return fmt.Errorf("unknown object type %T", obj) + } + } + + if err := util.CreateOrUpdateAnnotation(o.CreateAnnotation, job, scheme.DefaultJSONEncoder()); err != nil { + return err + } + + if o.DryRunStrategy != cmdutil.DryRunClient { + createOptions := metav1.CreateOptions{} + if o.FieldManager != "" { + createOptions.FieldManager = o.FieldManager + } + createOptions.FieldValidation = o.ValidationDirective + if o.DryRunStrategy == cmdutil.DryRunServer { + createOptions.DryRun = []string{metav1.DryRunAll} + } + var err error + job, err = o.Client.Jobs(o.Namespace).Create(context.TODO(), job, createOptions) + if err != nil { + return fmt.Errorf("failed to create job: %v", err) + } + } + + return o.PrintObj(job) +} + +func (o *CreateJobOptions) createJob() *batchv1.Job { + job := &batchv1.Job{ + // this is ok because we know exactly how we want to be serialized + TypeMeta: metav1.TypeMeta{APIVersion: batchv1.SchemeGroupVersion.String(), Kind: "Job"}, + ObjectMeta: metav1.ObjectMeta{ + Name: o.Name, + }, + Spec: batchv1.JobSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: o.Name, + Image: o.Image, + Command: o.Command, + }, + }, + RestartPolicy: corev1.RestartPolicyNever, + }, + }, + }, + } + if o.EnforceNamespace { + job.Namespace = o.Namespace + } + return job +} + +func (o *CreateJobOptions) createJobFromCronJob(cronJob *batchv1.CronJob) *batchv1.Job { + annotations := make(map[string]string) + annotations["cronjob.kubernetes.io/instantiate"] = "manual" + for k, v := range cronJob.Spec.JobTemplate.Annotations { + annotations[k] = v + } + + job := &batchv1.Job{ + // this is ok because we know exactly how we want to be serialized + TypeMeta: metav1.TypeMeta{APIVersion: batchv1.SchemeGroupVersion.String(), Kind: "Job"}, + ObjectMeta: metav1.ObjectMeta{ + Name: o.Name, + Annotations: annotations, + Labels: cronJob.Spec.JobTemplate.Labels, + OwnerReferences: []metav1.OwnerReference{ + { + // we are not using metav1.NewControllerRef because it + // sets BlockOwnerDeletion to true which additionally mandates + // cronjobs/finalizer role and not backwards-compatible. + APIVersion: batchv1.SchemeGroupVersion.String(), + Kind: "CronJob", + Name: cronJob.GetName(), + UID: cronJob.GetUID(), + Controller: ptr.To(true), + }, + }, + }, + Spec: cronJob.Spec.JobTemplate.Spec, + } + if o.EnforceNamespace { + job.Namespace = o.Namespace + } + return job +} diff --git a/vendor/k8s.io/kubectl/pkg/cmd/create/create_namespace.go b/vendor/k8s.io/kubectl/pkg/cmd/create/create_namespace.go new file mode 100644 index 000000000000..047e973fa894 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/cmd/create/create_namespace.go @@ -0,0 +1,179 @@ +/* +Copyright 2015 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 create + +import ( + "context" + "fmt" + + "github.com/spf13/cobra" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "k8s.io/apimachinery/pkg/runtime" + coreclient "k8s.io/client-go/kubernetes/typed/core/v1" + "k8s.io/kubectl/pkg/scheme" + "k8s.io/kubectl/pkg/util" + + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/genericiooptions" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/templates" +) + +var ( + namespaceLong = templates.LongDesc(i18n.T(` + Create a namespace with the specified name.`)) + + namespaceExample = templates.Examples(i18n.T(` + # Create a new namespace named my-namespace + kubectl create namespace my-namespace`)) +) + +// NamespaceOptions is the options for 'create namespace' sub command +type NamespaceOptions struct { + // PrintFlags holds options necessary for obtaining a printer + PrintFlags *genericclioptions.PrintFlags + // Name of resource being created + Name string + + DryRunStrategy cmdutil.DryRunStrategy + ValidationDirective string + CreateAnnotation bool + FieldManager string + + Client *coreclient.CoreV1Client + + PrintObj func(obj runtime.Object) error + + genericiooptions.IOStreams +} + +// NewNamespaceOptions creates a new *NamespaceOptions with sane defaults +func NewNamespaceOptions(ioStreams genericiooptions.IOStreams) *NamespaceOptions { + return &NamespaceOptions{ + PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme), + IOStreams: ioStreams, + } +} + +// NewCmdCreateNamespace is a macro command to create a new namespace +func NewCmdCreateNamespace(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + + o := NewNamespaceOptions(ioStreams) + + cmd := &cobra.Command{ + Use: "namespace NAME [--dry-run=server|client|none]", + DisableFlagsInUseLine: true, + Aliases: []string{"ns"}, + Short: i18n.T("Create a namespace with the specified name"), + Long: namespaceLong, + Example: namespaceExample, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.Run()) + }, + } + + o.PrintFlags.AddFlags(cmd) + + cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddValidateFlags(cmd) + cmdutil.AddDryRunFlag(cmd) + cmdutil.AddFieldManagerFlagVar(cmd, &o.FieldManager, "kubectl-create") + + return cmd +} + +// Complete completes all the required options +func (o *NamespaceOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { + name, err := NameFromCommandArgs(cmd, args) + if err != nil { + return err + } + + restConfig, err := f.ToRESTConfig() + if err != nil { + return err + } + o.Client, err = coreclient.NewForConfig(restConfig) + if err != nil { + return err + } + + o.Name = name + o.DryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd) + if err != nil { + return err + } + o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) + cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) + printer, err := o.PrintFlags.ToPrinter() + if err != nil { + return err + } + o.PrintObj = func(obj runtime.Object) error { + return printer.PrintObj(obj, o.Out) + } + + o.ValidationDirective, err = cmdutil.GetValidationDirective(cmd) + return err +} + +// Run calls the CreateSubcommandOptions.Run in NamespaceOpts instance +func (o *NamespaceOptions) Run() error { + namespace := o.createNamespace() + if err := util.CreateOrUpdateAnnotation(o.CreateAnnotation, namespace, scheme.DefaultJSONEncoder()); err != nil { + return err + } + + if o.DryRunStrategy != cmdutil.DryRunClient { + createOptions := metav1.CreateOptions{} + if o.FieldManager != "" { + createOptions.FieldManager = o.FieldManager + } + createOptions.FieldValidation = o.ValidationDirective + if o.DryRunStrategy == cmdutil.DryRunServer { + createOptions.DryRun = []string{metav1.DryRunAll} + } + var err error + namespace, err = o.Client.Namespaces().Create(context.TODO(), namespace, createOptions) + if err != nil { + return err + } + } + return o.PrintObj(namespace) +} + +// createNamespace outputs a namespace object using the configured fields +func (o *NamespaceOptions) createNamespace() *corev1.Namespace { + namespace := &corev1.Namespace{ + TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String(), Kind: "Namespace"}, + ObjectMeta: metav1.ObjectMeta{Name: o.Name}, + } + return namespace +} + +// Validate validates required fields are set to support structured generation +func (o *NamespaceOptions) Validate() error { + if len(o.Name) == 0 { + return fmt.Errorf("name must be specified") + } + return nil +} diff --git a/vendor/k8s.io/kubectl/pkg/cmd/create/create_pdb.go b/vendor/k8s.io/kubectl/pkg/cmd/create/create_pdb.go new file mode 100644 index 000000000000..0023e748106d --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/cmd/create/create_pdb.go @@ -0,0 +1,261 @@ +/* +Copyright 2016 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 create + +import ( + "context" + "fmt" + "regexp" + + "github.com/spf13/cobra" + + policyv1 "k8s.io/api/policy/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/genericiooptions" + policyv1client "k8s.io/client-go/kubernetes/typed/policy/v1" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/scheme" + "k8s.io/kubectl/pkg/util" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/templates" +) + +var ( + pdbLong = templates.LongDesc(i18n.T(` + Create a pod disruption budget with the specified name, selector, and desired minimum available pods.`)) + + pdbExample = templates.Examples(i18n.T(` + # Create a pod disruption budget named my-pdb that will select all pods with the app=rails label + # and require at least one of them being available at any point in time + kubectl create poddisruptionbudget my-pdb --selector=app=rails --min-available=1 + + # Create a pod disruption budget named my-pdb that will select all pods with the app=nginx label + # and require at least half of the pods selected to be available at any point in time + kubectl create pdb my-pdb --selector=app=nginx --min-available=50%`)) +) + +// PodDisruptionBudgetOpts holds the command-line options for poddisruptionbudget sub command +type PodDisruptionBudgetOpts struct { + // PrintFlags holds options necessary for obtaining a printer + PrintFlags *genericclioptions.PrintFlags + PrintObj func(obj runtime.Object) error + // Name of resource being created + Name string + + MinAvailable string + MaxUnavailable string + + // A label selector to use for this budget + Selector string + CreateAnnotation bool + FieldManager string + Namespace string + EnforceNamespace bool + + Client *policyv1client.PolicyV1Client + DryRunStrategy cmdutil.DryRunStrategy + ValidationDirective string + + genericiooptions.IOStreams +} + +// NewPodDisruptionBudgetOpts creates a new *PodDisruptionBudgetOpts with sane defaults +func NewPodDisruptionBudgetOpts(ioStreams genericiooptions.IOStreams) *PodDisruptionBudgetOpts { + return &PodDisruptionBudgetOpts{ + PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme), + IOStreams: ioStreams, + } +} + +// NewCmdCreatePodDisruptionBudget is a macro command to create a new pod disruption budget. +func NewCmdCreatePodDisruptionBudget(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + o := NewPodDisruptionBudgetOpts(ioStreams) + + cmd := &cobra.Command{ + Use: "poddisruptionbudget NAME --selector=SELECTOR --min-available=N [--dry-run=server|client|none]", + DisableFlagsInUseLine: true, + Aliases: []string{"pdb"}, + Short: i18n.T("Create a pod disruption budget with the specified name"), + Long: pdbLong, + Example: pdbExample, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.Run()) + }, + } + + o.PrintFlags.AddFlags(cmd) + + cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddValidateFlags(cmd) + cmdutil.AddDryRunFlag(cmd) + + cmd.Flags().StringVar(&o.MinAvailable, "min-available", o.MinAvailable, i18n.T("The minimum number or percentage of available pods this budget requires.")) + cmd.Flags().StringVar(&o.MaxUnavailable, "max-unavailable", o.MaxUnavailable, i18n.T("The maximum number or percentage of unavailable pods this budget requires.")) + cmd.Flags().StringVar(&o.Selector, "selector", o.Selector, i18n.T("A label selector to use for this budget. Only equality-based selector requirements are supported.")) + cmdutil.AddFieldManagerFlagVar(cmd, &o.FieldManager, "kubectl-create") + return cmd +} + +// Complete completes all the required options +func (o *PodDisruptionBudgetOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { + var err error + o.Name, err = NameFromCommandArgs(cmd, args) + if err != nil { + return err + } + + restConfig, err := f.ToRESTConfig() + if err != nil { + return err + } + o.Client, err = policyv1client.NewForConfig(restConfig) + if err != nil { + return err + } + + o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) + + o.DryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd) + if err != nil { + return err + } + + o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace() + if err != nil { + return err + } + + cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) + + printer, err := o.PrintFlags.ToPrinter() + if err != nil { + return err + } + + o.PrintObj = func(obj runtime.Object) error { + return printer.PrintObj(obj, o.Out) + } + + o.ValidationDirective, err = cmdutil.GetValidationDirective(cmd) + if err != nil { + return err + } + + return nil +} + +// Validate checks to the PodDisruptionBudgetOpts to see if there is sufficient information run the command +func (o *PodDisruptionBudgetOpts) Validate() error { + if len(o.Name) == 0 { + return fmt.Errorf("name must be specified") + } + + if len(o.Selector) == 0 { + return fmt.Errorf("a selector must be specified") + } + + if len(o.MaxUnavailable) == 0 && len(o.MinAvailable) == 0 { + return fmt.Errorf("one of min-available or max-unavailable must be specified") + } + + if len(o.MaxUnavailable) > 0 && len(o.MinAvailable) > 0 { + return fmt.Errorf("min-available and max-unavailable cannot be both specified") + } + + // The following regex matches the following values: + // 10, 20, 30%, 50% (number and percentage) + // but not 10Gb, 20Mb + re := regexp.MustCompile(`^[0-9]+%?$`) + + switch { + case len(o.MinAvailable) > 0 && !re.MatchString(o.MinAvailable): + return fmt.Errorf("invalid format specified for min-available") + case len(o.MaxUnavailable) > 0 && !re.MatchString(o.MaxUnavailable): + return fmt.Errorf("invalid format specified for max-unavailable") + } + + return nil +} + +// Run calls the CreateSubcommandOptions.Run in PodDisruptionBudgetOpts instance +func (o *PodDisruptionBudgetOpts) Run() error { + podDisruptionBudget, err := o.createPodDisruptionBudgets() + if err != nil { + return err + } + + if err := util.CreateOrUpdateAnnotation(o.CreateAnnotation, podDisruptionBudget, scheme.DefaultJSONEncoder()); err != nil { + return err + } + + if o.DryRunStrategy != cmdutil.DryRunClient { + createOptions := metav1.CreateOptions{} + if o.FieldManager != "" { + createOptions.FieldManager = o.FieldManager + } + createOptions.FieldValidation = o.ValidationDirective + if o.DryRunStrategy == cmdutil.DryRunServer { + createOptions.DryRun = []string{metav1.DryRunAll} + } + podDisruptionBudget, err = o.Client.PodDisruptionBudgets(o.Namespace).Create(context.TODO(), podDisruptionBudget, createOptions) + if err != nil { + return fmt.Errorf("failed to create poddisruptionbudgets: %v", err) + } + } + return o.PrintObj(podDisruptionBudget) +} + +func (o *PodDisruptionBudgetOpts) createPodDisruptionBudgets() (*policyv1.PodDisruptionBudget, error) { + namespace := "" + if o.EnforceNamespace { + namespace = o.Namespace + } + + podDisruptionBudget := &policyv1.PodDisruptionBudget{ + TypeMeta: metav1.TypeMeta{ + APIVersion: policyv1.SchemeGroupVersion.String(), + Kind: "PodDisruptionBudget", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: o.Name, + Namespace: namespace, + }, + } + + selector, err := metav1.ParseToLabelSelector(o.Selector) + if err != nil { + return nil, err + } + + podDisruptionBudget.Spec.Selector = selector + + switch { + case len(o.MinAvailable) > 0: + minAvailable := intstr.Parse(o.MinAvailable) + podDisruptionBudget.Spec.MinAvailable = &minAvailable + case len(o.MaxUnavailable) > 0: + maxUnavailable := intstr.Parse(o.MaxUnavailable) + podDisruptionBudget.Spec.MaxUnavailable = &maxUnavailable + } + + return podDisruptionBudget, nil +} diff --git a/vendor/k8s.io/kubectl/pkg/cmd/create/create_priorityclass.go b/vendor/k8s.io/kubectl/pkg/cmd/create/create_priorityclass.go new file mode 100644 index 000000000000..fe1cd51fccb3 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/cmd/create/create_priorityclass.go @@ -0,0 +1,198 @@ +/* +Copyright 2017 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 create + +import ( + "context" + "fmt" + + "github.com/spf13/cobra" + + corev1 "k8s.io/api/core/v1" + schedulingv1 "k8s.io/api/scheduling/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/genericiooptions" + schedulingv1client "k8s.io/client-go/kubernetes/typed/scheduling/v1" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/scheme" + "k8s.io/kubectl/pkg/util" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/templates" +) + +var ( + pcLong = templates.LongDesc(i18n.T(` + Create a priority class with the specified name, value, globalDefault and description.`)) + + pcExample = templates.Examples(i18n.T(` + # Create a priority class named high-priority + kubectl create priorityclass high-priority --value=1000 --description="high priority" + + # Create a priority class named default-priority that is considered as the global default priority + kubectl create priorityclass default-priority --value=1000 --global-default=true --description="default priority" + + # Create a priority class named high-priority that cannot preempt pods with lower priority + kubectl create priorityclass high-priority --value=1000 --description="high priority" --preemption-policy="Never"`)) +) + +// PriorityClassOptions holds the options for 'create priorityclass' sub command +type PriorityClassOptions struct { + PrintFlags *genericclioptions.PrintFlags + PrintObj func(obj runtime.Object) error + + Name string + Value int32 + GlobalDefault bool + Description string + PreemptionPolicy string + FieldManager string + CreateAnnotation bool + + Client *schedulingv1client.SchedulingV1Client + DryRunStrategy cmdutil.DryRunStrategy + ValidationDirective string + + genericiooptions.IOStreams +} + +// NewPriorityClassOptions returns an initialized PriorityClassOptions instance +func NewPriorityClassOptions(ioStreams genericiooptions.IOStreams) *PriorityClassOptions { + return &PriorityClassOptions{ + Value: 0, + PreemptionPolicy: "PreemptLowerPriority", + PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme), + IOStreams: ioStreams, + } +} + +// NewCmdCreatePriorityClass is a macro command to create a new priorityClass. +func NewCmdCreatePriorityClass(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + o := NewPriorityClassOptions(ioStreams) + + cmd := &cobra.Command{ + Use: "priorityclass NAME --value=VALUE --global-default=BOOL [--dry-run=server|client|none]", + DisableFlagsInUseLine: true, + Aliases: []string{"pc"}, + Short: i18n.T("Create a priority class with the specified name"), + Long: pcLong, + Example: pcExample, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Run()) + }, + } + + o.PrintFlags.AddFlags(cmd) + + cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddValidateFlags(cmd) + cmdutil.AddDryRunFlag(cmd) + cmd.Flags().Int32Var(&o.Value, "value", o.Value, i18n.T("the value of this priority class.")) + cmd.Flags().BoolVar(&o.GlobalDefault, "global-default", o.GlobalDefault, i18n.T("global-default specifies whether this PriorityClass should be considered as the default priority.")) + cmd.Flags().StringVar(&o.Description, "description", o.Description, i18n.T("description is an arbitrary string that usually provides guidelines on when this priority class should be used.")) + cmd.Flags().StringVar(&o.PreemptionPolicy, "preemption-policy", o.PreemptionPolicy, i18n.T("preemption-policy is the policy for preempting pods with lower priority.")) + cmdutil.AddFieldManagerFlagVar(cmd, &o.FieldManager, "kubectl-create") + return cmd +} + +// Complete completes all the required options +func (o *PriorityClassOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { + var err error + o.Name, err = NameFromCommandArgs(cmd, args) + if err != nil { + return err + } + + restConfig, err := f.ToRESTConfig() + if err != nil { + return err + } + o.Client, err = schedulingv1client.NewForConfig(restConfig) + if err != nil { + return err + } + + o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) + + o.DryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd) + if err != nil { + return err + } + cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) + + printer, err := o.PrintFlags.ToPrinter() + if err != nil { + return err + } + o.PrintObj = func(obj runtime.Object) error { + return printer.PrintObj(obj, o.Out) + } + + o.ValidationDirective, err = cmdutil.GetValidationDirective(cmd) + if err != nil { + return err + } + + return nil +} + +// Run calls the CreateSubcommandOptions.Run in the PriorityClassOptions instance +func (o *PriorityClassOptions) Run() error { + priorityClass, err := o.createPriorityClass() + if err != nil { + return err + } + + if err := util.CreateOrUpdateAnnotation(o.CreateAnnotation, priorityClass, scheme.DefaultJSONEncoder()); err != nil { + return err + } + + if o.DryRunStrategy != cmdutil.DryRunClient { + createOptions := metav1.CreateOptions{} + if o.FieldManager != "" { + createOptions.FieldManager = o.FieldManager + } + createOptions.FieldValidation = o.ValidationDirective + if o.DryRunStrategy == cmdutil.DryRunServer { + createOptions.DryRun = []string{metav1.DryRunAll} + } + var err error + priorityClass, err = o.Client.PriorityClasses().Create(context.TODO(), priorityClass, createOptions) + if err != nil { + return fmt.Errorf("failed to create priorityclass: %v", err) + } + } + + return o.PrintObj(priorityClass) +} + +func (o *PriorityClassOptions) createPriorityClass() (*schedulingv1.PriorityClass, error) { + preemptionPolicy := corev1.PreemptionPolicy(o.PreemptionPolicy) + return &schedulingv1.PriorityClass{ + // this is ok because we know exactly how we want to be serialized + TypeMeta: metav1.TypeMeta{APIVersion: schedulingv1.SchemeGroupVersion.String(), Kind: "PriorityClass"}, + ObjectMeta: metav1.ObjectMeta{ + Name: o.Name, + }, + Value: o.Value, + GlobalDefault: o.GlobalDefault, + Description: o.Description, + PreemptionPolicy: &preemptionPolicy, + }, nil +} diff --git a/vendor/k8s.io/kubectl/pkg/cmd/create/create_quota.go b/vendor/k8s.io/kubectl/pkg/cmd/create/create_quota.go new file mode 100644 index 000000000000..d3966274709b --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/cmd/create/create_quota.go @@ -0,0 +1,268 @@ +/* +Copyright 2016 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 create + +import ( + "context" + "fmt" + "strings" + + "github.com/spf13/cobra" + + corev1 "k8s.io/api/core/v1" + resourceapi "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/genericiooptions" + coreclient "k8s.io/client-go/kubernetes/typed/core/v1" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/scheme" + "k8s.io/kubectl/pkg/util" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/templates" +) + +var ( + quotaLong = templates.LongDesc(i18n.T(` + Create a resource quota with the specified name, hard limits, and optional scopes.`)) + + quotaExample = templates.Examples(i18n.T(` + # Create a new resource quota named my-quota + kubectl create quota my-quota --hard=cpu=1,memory=1G,pods=2,services=3,replicationcontrollers=2,resourcequotas=1,secrets=5,persistentvolumeclaims=10 + + # Create a new resource quota named best-effort + kubectl create quota best-effort --hard=pods=100 --scopes=BestEffort`)) +) + +// QuotaOpts holds the command-line options for 'create quota' sub command +type QuotaOpts struct { + // PrintFlags holds options necessary for obtaining a printer + PrintFlags *genericclioptions.PrintFlags + PrintObj func(obj runtime.Object) error + // The name of a quota object. + Name string + // The hard resource limit string before parsing. + Hard string + // The scopes of a quota object before parsing. + Scopes string + CreateAnnotation bool + FieldManager string + Namespace string + EnforceNamespace bool + + Client *coreclient.CoreV1Client + DryRunStrategy cmdutil.DryRunStrategy + ValidationDirective string + + genericiooptions.IOStreams +} + +// NewQuotaOpts creates a new *QuotaOpts with sane defaults +func NewQuotaOpts(ioStreams genericiooptions.IOStreams) *QuotaOpts { + return &QuotaOpts{ + PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme), + IOStreams: ioStreams, + } +} + +// NewCmdCreateQuota is a macro command to create a new quota +func NewCmdCreateQuota(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + o := NewQuotaOpts(ioStreams) + + cmd := &cobra.Command{ + Use: "quota NAME [--hard=key1=value1,key2=value2] [--scopes=Scope1,Scope2] [--dry-run=server|client|none]", + DisableFlagsInUseLine: true, + Aliases: []string{"resourcequota"}, + Short: i18n.T("Create a quota with the specified name"), + Long: quotaLong, + Example: quotaExample, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.Run()) + }, + } + + o.PrintFlags.AddFlags(cmd) + + cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddValidateFlags(cmd) + cmdutil.AddDryRunFlag(cmd) + cmd.Flags().StringVar(&o.Hard, "hard", o.Hard, i18n.T("A comma-delimited set of resource=quantity pairs that define a hard limit.")) + cmd.Flags().StringVar(&o.Scopes, "scopes", o.Scopes, i18n.T("A comma-delimited set of quota scopes that must all match each object tracked by the quota.")) + cmdutil.AddFieldManagerFlagVar(cmd, &o.FieldManager, "kubectl-create") + return cmd +} + +// Complete completes all the required options +func (o *QuotaOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { + var err error + o.Name, err = NameFromCommandArgs(cmd, args) + if err != nil { + return err + } + + restConfig, err := f.ToRESTConfig() + if err != nil { + return err + } + o.Client, err = coreclient.NewForConfig(restConfig) + if err != nil { + return err + } + + o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) + + o.DryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd) + if err != nil { + return err + } + + o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace() + if err != nil { + return err + } + + cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) + + printer, err := o.PrintFlags.ToPrinter() + if err != nil { + return err + } + + o.PrintObj = func(obj runtime.Object) error { + return printer.PrintObj(obj, o.Out) + } + + o.ValidationDirective, err = cmdutil.GetValidationDirective(cmd) + if err != nil { + return err + } + + return nil +} + +// Validate checks to the QuotaOpts to see if there is sufficient information run the command. +func (o *QuotaOpts) Validate() error { + if len(o.Name) == 0 { + return fmt.Errorf("name must be specified") + } + return nil +} + +// Run does the work +func (o *QuotaOpts) Run() error { + resourceQuota, err := o.createQuota() + if err != nil { + return err + } + + if err := util.CreateOrUpdateAnnotation(o.CreateAnnotation, resourceQuota, scheme.DefaultJSONEncoder()); err != nil { + return err + } + + if o.DryRunStrategy != cmdutil.DryRunClient { + createOptions := metav1.CreateOptions{} + if o.FieldManager != "" { + createOptions.FieldManager = o.FieldManager + } + createOptions.FieldValidation = o.ValidationDirective + if o.DryRunStrategy == cmdutil.DryRunServer { + createOptions.DryRun = []string{metav1.DryRunAll} + } + resourceQuota, err = o.Client.ResourceQuotas(o.Namespace).Create(context.TODO(), resourceQuota, createOptions) + if err != nil { + return fmt.Errorf("failed to create quota: %v", err) + } + } + return o.PrintObj(resourceQuota) +} + +func (o *QuotaOpts) createQuota() (*corev1.ResourceQuota, error) { + namespace := "" + if o.EnforceNamespace { + namespace = o.Namespace + } + resourceQuota := &corev1.ResourceQuota{ + TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String(), Kind: "ResourceQuota"}, + ObjectMeta: metav1.ObjectMeta{ + Name: o.Name, + Namespace: namespace, + }, + } + + resourceList, err := populateResourceListV1(o.Hard) + if err != nil { + return nil, err + } + + scopes, err := parseScopes(o.Scopes) + if err != nil { + return nil, err + } + + resourceQuota.Spec.Hard = resourceList + resourceQuota.Spec.Scopes = scopes + + return resourceQuota, nil +} + +// populateResourceListV1 takes strings of form =,= +// and returns ResourceList. +func populateResourceListV1(spec string) (corev1.ResourceList, error) { + // empty input gets a nil response to preserve generator test expected behaviors + if spec == "" { + return nil, nil + } + + result := corev1.ResourceList{} + resourceStatements := strings.Split(spec, ",") + for _, resourceStatement := range resourceStatements { + parts := strings.Split(resourceStatement, "=") + if len(parts) != 2 { + return nil, fmt.Errorf("Invalid argument syntax %v, expected =", resourceStatement) + } + resourceName := corev1.ResourceName(parts[0]) + resourceQuantity, err := resourceapi.ParseQuantity(parts[1]) + if err != nil { + return nil, err + } + result[resourceName] = resourceQuantity + } + return result, nil +} + +func parseScopes(spec string) ([]corev1.ResourceQuotaScope, error) { + // empty input gets a nil response to preserve test expected behaviors + if spec == "" { + return nil, nil + } + + scopes := strings.Split(spec, ",") + result := make([]corev1.ResourceQuotaScope, 0, len(scopes)) + for _, scope := range scopes { + // intentionally do not verify the scope against the valid scope list. This is done by the apiserver anyway. + + if scope == "" { + return nil, fmt.Errorf("invalid resource quota scope \"\"") + } + + result = append(result, corev1.ResourceQuotaScope(scope)) + } + return result, nil +} diff --git a/vendor/k8s.io/kubectl/pkg/cmd/create/create_role.go b/vendor/k8s.io/kubectl/pkg/cmd/create/create_role.go new file mode 100644 index 000000000000..822ed11e7043 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/cmd/create/create_role.go @@ -0,0 +1,445 @@ +/* +Copyright 2017 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 create + +import ( + "context" + "fmt" + "strings" + + "github.com/spf13/cobra" + + rbacv1 "k8s.io/api/rbac/v1" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/genericiooptions" + clientgorbacv1 "k8s.io/client-go/kubernetes/typed/rbac/v1" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/scheme" + "k8s.io/kubectl/pkg/util" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/templates" +) + +var ( + roleLong = templates.LongDesc(i18n.T(` + Create a role with single rule.`)) + + roleExample = templates.Examples(i18n.T(` + # Create a role named "pod-reader" that allows user to perform "get", "watch" and "list" on pods + kubectl create role pod-reader --verb=get --verb=list --verb=watch --resource=pods + + # Create a role named "pod-reader" with ResourceName specified + kubectl create role pod-reader --verb=get --resource=pods --resource-name=readablepod --resource-name=anotherpod + + # Create a role named "foo" with API Group specified + kubectl create role foo --verb=get,list,watch --resource=rs.apps + + # Create a role named "foo" with SubResource specified + kubectl create role foo --verb=get,list,watch --resource=pods,pods/status`)) + + // Valid resource verb list for validation. + validResourceVerbs = []string{"*", "get", "delete", "list", "create", "update", "patch", "watch", "proxy", "deletecollection", "use", "bind", "escalate", "impersonate"} + + // Specialized verbs and GroupResources + specialVerbs = map[string][]schema.GroupResource{ + "use": { + { + Group: "policy", + Resource: "podsecuritypolicies", + }, + { + Group: "extensions", + Resource: "podsecuritypolicies", + }, + }, + "bind": { + { + Group: "rbac.authorization.k8s.io", + Resource: "roles", + }, + { + Group: "rbac.authorization.k8s.io", + Resource: "clusterroles", + }, + }, + "escalate": { + { + Group: "rbac.authorization.k8s.io", + Resource: "roles", + }, + { + Group: "rbac.authorization.k8s.io", + Resource: "clusterroles", + }, + }, + "impersonate": { + { + Group: "", + Resource: "users", + }, + { + Group: "", + Resource: "serviceaccounts", + }, + { + Group: "", + Resource: "groups", + }, + { + Group: "authentication.k8s.io", + Resource: "userextras", + }, + }, + } +) + +// AddSpecialVerb allows the addition of items to the `specialVerbs` map for non-k8s native resources. +func AddSpecialVerb(verb string, gr schema.GroupResource) { + resources, ok := specialVerbs[verb] + if !ok { + resources = make([]schema.GroupResource, 1) + } + resources = append(resources, gr) + specialVerbs[verb] = resources +} + +// ResourceOptions holds the related options for '--resource' option +type ResourceOptions struct { + Group string + Resource string + SubResource string +} + +// CreateRoleOptions holds the options for 'create role' sub command +type CreateRoleOptions struct { + PrintFlags *genericclioptions.PrintFlags + + Name string + Verbs []string + Resources []ResourceOptions + ResourceNames []string + + DryRunStrategy cmdutil.DryRunStrategy + ValidationDirective string + OutputFormat string + Namespace string + EnforceNamespace bool + Client clientgorbacv1.RbacV1Interface + Mapper meta.RESTMapper + PrintObj func(obj runtime.Object) error + FieldManager string + CreateAnnotation bool + + genericiooptions.IOStreams +} + +// NewCreateRoleOptions returns an initialized CreateRoleOptions instance +func NewCreateRoleOptions(ioStreams genericiooptions.IOStreams) *CreateRoleOptions { + return &CreateRoleOptions{ + PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme), + + IOStreams: ioStreams, + } +} + +// NewCmdCreateRole returnns an initialized Command instance for 'create role' sub command +func NewCmdCreateRole(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + o := NewCreateRoleOptions(ioStreams) + + cmd := &cobra.Command{ + Use: "role NAME --verb=verb --resource=resource.group/subresource [--resource-name=resourcename] [--dry-run=server|client|none]", + DisableFlagsInUseLine: true, + Short: i18n.T("Create a role with single rule"), + Long: roleLong, + Example: roleExample, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.RunCreateRole()) + }, + } + + o.PrintFlags.AddFlags(cmd) + + cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddValidateFlags(cmd) + cmdutil.AddDryRunFlag(cmd) + cmd.Flags().StringSliceVar(&o.Verbs, "verb", o.Verbs, "Verb that applies to the resources contained in the rule") + cmd.Flags().StringSlice("resource", []string{}, "Resource that the rule applies to") + cmd.Flags().StringArrayVar(&o.ResourceNames, "resource-name", o.ResourceNames, "Resource in the white list that the rule applies to, repeat this flag for multiple items") + cmdutil.AddFieldManagerFlagVar(cmd, &o.FieldManager, "kubectl-create") + return cmd +} + +// Complete completes all the required options +func (o *CreateRoleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { + name, err := NameFromCommandArgs(cmd, args) + if err != nil { + return err + } + o.Name = name + + // Remove duplicate verbs. + verbs := []string{} + for _, v := range o.Verbs { + // VerbAll respresents all kinds of verbs. + if v == "*" { + verbs = []string{"*"} + break + } + if !arrayContains(verbs, v) { + verbs = append(verbs, v) + } + } + o.Verbs = verbs + + // Support resource.group pattern. If no API Group specified, use "" as core API Group. + // e.g. --resource=pods,deployments.extensions + resources := cmdutil.GetFlagStringSlice(cmd, "resource") + for _, r := range resources { + sections := strings.SplitN(r, "/", 2) + + resource := &ResourceOptions{} + if len(sections) == 2 { + resource.SubResource = sections[1] + } + + parts := strings.SplitN(sections[0], ".", 2) + if len(parts) == 2 { + resource.Group = parts[1] + } + resource.Resource = parts[0] + + if resource.Resource == "*" && len(parts) == 1 && len(sections) == 1 { + o.Resources = []ResourceOptions{*resource} + break + } + + o.Resources = append(o.Resources, *resource) + } + + // Remove duplicate resource names. + resourceNames := []string{} + for _, n := range o.ResourceNames { + if !arrayContains(resourceNames, n) { + resourceNames = append(resourceNames, n) + } + } + o.ResourceNames = resourceNames + + // Complete other options for Run. + o.Mapper, err = f.ToRESTMapper() + if err != nil { + return err + } + + o.DryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd) + if err != nil { + return err + } + o.OutputFormat = cmdutil.GetFlagString(cmd, "output") + o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) + + cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) + printer, err := o.PrintFlags.ToPrinter() + if err != nil { + return err + } + o.PrintObj = func(obj runtime.Object) error { + return printer.PrintObj(obj, o.Out) + } + + o.ValidationDirective, err = cmdutil.GetValidationDirective(cmd) + if err != nil { + return err + } + + o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace() + if err != nil { + return err + } + + clientset, err := f.KubernetesClientSet() + if err != nil { + return err + } + o.Client = clientset.RbacV1() + + return nil +} + +// Validate makes sure there is no discrepency in provided option values +func (o *CreateRoleOptions) Validate() error { + if o.Name == "" { + return fmt.Errorf("name must be specified") + } + + // validate verbs. + if len(o.Verbs) == 0 { + return fmt.Errorf("at least one verb must be specified") + } + + for _, v := range o.Verbs { + if !arrayContains(validResourceVerbs, v) { + fmt.Fprintf(o.ErrOut, "Warning: '%s' is not a standard resource verb\n", v) + } + } + + // validate resources. + if len(o.Resources) == 0 { + return fmt.Errorf("at least one resource must be specified") + } + + return o.validateResource() +} + +func (o *CreateRoleOptions) validateResource() error { + for _, r := range o.Resources { + if len(r.Resource) == 0 { + return fmt.Errorf("resource must be specified if apiGroup/subresource specified") + } + if r.Resource == "*" { + return nil + } + + resource := schema.GroupVersionResource{Resource: r.Resource, Group: r.Group} + groupVersionResource, err := o.Mapper.ResourceFor(schema.GroupVersionResource{Resource: r.Resource, Group: r.Group}) + if err == nil { + resource = groupVersionResource + } + + for _, v := range o.Verbs { + if groupResources, ok := specialVerbs[v]; ok { + match := false + for _, extra := range groupResources { + if resource.Resource == extra.Resource && resource.Group == extra.Group { + match = true + err = nil + break + } + } + if !match { + return fmt.Errorf("can not perform '%s' on '%s' in group '%s'", v, resource.Resource, resource.Group) + } + } + } + + if err != nil { + return err + } + } + return nil +} + +// RunCreateRole performs the execution of 'create role' sub command +func (o *CreateRoleOptions) RunCreateRole() error { + role := &rbacv1.Role{ + // this is ok because we know exactly how we want to be serialized + TypeMeta: metav1.TypeMeta{APIVersion: rbacv1.SchemeGroupVersion.String(), Kind: "Role"}, + } + role.Name = o.Name + rules, err := generateResourcePolicyRules(o.Mapper, o.Verbs, o.Resources, o.ResourceNames, []string{}) + if err != nil { + return err + } + role.Rules = rules + if o.EnforceNamespace { + role.Namespace = o.Namespace + } + + if err := util.CreateOrUpdateAnnotation(o.CreateAnnotation, role, scheme.DefaultJSONEncoder()); err != nil { + return err + } + + // Create role. + if o.DryRunStrategy != cmdutil.DryRunClient { + createOptions := metav1.CreateOptions{} + if o.FieldManager != "" { + createOptions.FieldManager = o.FieldManager + } + createOptions.FieldValidation = o.ValidationDirective + if o.DryRunStrategy == cmdutil.DryRunServer { + createOptions.DryRun = []string{metav1.DryRunAll} + } + role, err = o.Client.Roles(o.Namespace).Create(context.TODO(), role, createOptions) + if err != nil { + return err + } + } + + return o.PrintObj(role) +} + +func arrayContains(s []string, e string) bool { + for _, a := range s { + if a == e { + return true + } + } + return false +} + +func generateResourcePolicyRules(mapper meta.RESTMapper, verbs []string, resources []ResourceOptions, resourceNames []string, nonResourceURLs []string) ([]rbacv1.PolicyRule, error) { + // groupResourceMapping is a apigroup-resource map. The key of this map is api group, while the value + // is a string array of resources under this api group. + // E.g. groupResourceMapping = {"extensions": ["replicasets", "deployments"], "batch":["jobs"]} + groupResourceMapping := map[string][]string{} + + // This loop does the following work: + // 1. Constructs groupResourceMapping based on input resources. + // 2. Prevents pointing to non-existent resources. + // 3. Transfers resource short name to long name. E.g. rs.extensions is transferred to replicasets.extensions + for _, r := range resources { + resource := schema.GroupVersionResource{Resource: r.Resource, Group: r.Group} + groupVersionResource, err := mapper.ResourceFor(schema.GroupVersionResource{Resource: r.Resource, Group: r.Group}) + if err == nil { + resource = groupVersionResource + } + + if len(r.SubResource) > 0 { + resource.Resource = resource.Resource + "/" + r.SubResource + } + if !arrayContains(groupResourceMapping[resource.Group], resource.Resource) { + groupResourceMapping[resource.Group] = append(groupResourceMapping[resource.Group], resource.Resource) + } + } + + // Create separate rule for each of the api group. + rules := []rbacv1.PolicyRule{} + for _, g := range sets.StringKeySet(groupResourceMapping).List() { + rule := rbacv1.PolicyRule{} + rule.Verbs = verbs + rule.Resources = groupResourceMapping[g] + rule.APIGroups = []string{g} + rule.ResourceNames = resourceNames + rules = append(rules, rule) + } + + if len(nonResourceURLs) > 0 { + rule := rbacv1.PolicyRule{} + rule.Verbs = verbs + rule.NonResourceURLs = nonResourceURLs + rules = append(rules, rule) + } + + return rules, nil +} diff --git a/vendor/k8s.io/kubectl/pkg/cmd/create/create_rolebinding.go b/vendor/k8s.io/kubectl/pkg/cmd/create/create_rolebinding.go new file mode 100644 index 000000000000..237a54422bfa --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/cmd/create/create_rolebinding.go @@ -0,0 +1,251 @@ +/* +Copyright 2016 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 create + +import ( + "context" + "fmt" + "strings" + + "github.com/spf13/cobra" + + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/genericiooptions" + rbacclientv1 "k8s.io/client-go/kubernetes/typed/rbac/v1" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/scheme" + "k8s.io/kubectl/pkg/util" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/templates" +) + +var ( + roleBindingLong = templates.LongDesc(i18n.T(` + Create a role binding for a particular role or cluster role.`)) + + roleBindingExample = templates.Examples(i18n.T(` + # Create a role binding for user1, user2, and group1 using the admin cluster role + kubectl create rolebinding admin --clusterrole=admin --user=user1 --user=user2 --group=group1 + + # Create a role binding for serviceaccount monitoring:sa-dev using the admin role + kubectl create rolebinding admin-binding --role=admin --serviceaccount=monitoring:sa-dev`)) +) + +// RoleBindingOptions holds the options for 'create rolebinding' sub command +type RoleBindingOptions struct { + PrintFlags *genericclioptions.PrintFlags + PrintObj func(obj runtime.Object) error + + Name string + Namespace string + EnforceNamespace bool + ClusterRole string + Role string + Users []string + Groups []string + ServiceAccounts []string + FieldManager string + CreateAnnotation bool + + Client rbacclientv1.RbacV1Interface + DryRunStrategy cmdutil.DryRunStrategy + ValidationDirective string + + genericiooptions.IOStreams +} + +// NewRoleBindingOptions creates a new *RoleBindingOptions with sane defaults +func NewRoleBindingOptions(ioStreams genericiooptions.IOStreams) *RoleBindingOptions { + return &RoleBindingOptions{ + Users: []string{}, + Groups: []string{}, + ServiceAccounts: []string{}, + PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme), + IOStreams: ioStreams, + } +} + +// NewCmdCreateRoleBinding returns an initialized Command instance for 'create rolebinding' sub command +func NewCmdCreateRoleBinding(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + o := NewRoleBindingOptions(ioStreams) + + cmd := &cobra.Command{ + Use: "rolebinding NAME --clusterrole=NAME|--role=NAME [--user=username] [--group=groupname] [--serviceaccount=namespace:serviceaccountname] [--dry-run=server|client|none]", + DisableFlagsInUseLine: true, + Short: i18n.T("Create a role binding for a particular role or cluster role"), + Long: roleBindingLong, + Example: roleBindingExample, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.Run()) + }, + } + + o.PrintFlags.AddFlags(cmd) + + cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddValidateFlags(cmd) + cmdutil.AddDryRunFlag(cmd) + cmd.Flags().StringVar(&o.ClusterRole, "clusterrole", "", i18n.T("ClusterRole this RoleBinding should reference")) + cmd.Flags().StringVar(&o.Role, "role", "", i18n.T("Role this RoleBinding should reference")) + cmd.Flags().StringArrayVar(&o.Users, "user", o.Users, "Usernames to bind to the role. The flag can be repeated to add multiple users.") + cmd.Flags().StringArrayVar(&o.Groups, "group", o.Groups, "Groups to bind to the role. The flag can be repeated to add multiple groups.") + cmd.Flags().StringArrayVar(&o.ServiceAccounts, "serviceaccount", o.ServiceAccounts, "Service accounts to bind to the role, in the format :. The flag can be repeated to add multiple service accounts.") + cmdutil.AddFieldManagerFlagVar(cmd, &o.FieldManager, "kubectl-create") + return cmd +} + +// Complete completes all the required options +func (o *RoleBindingOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { + var err error + o.Name, err = NameFromCommandArgs(cmd, args) + if err != nil { + return err + } + clientConfig, err := f.ToRESTConfig() + if err != nil { + return err + } + o.Client, err = rbacclientv1.NewForConfig(clientConfig) + if err != nil { + return err + } + + o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace() + if err != nil { + return err + } + + o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) + o.DryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd) + if err != nil { + return err + } + cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) + printer, err := o.PrintFlags.ToPrinter() + if err != nil { + return err + } + o.PrintObj = func(obj runtime.Object) error { + return printer.PrintObj(obj, o.Out) + } + + o.ValidationDirective, err = cmdutil.GetValidationDirective(cmd) + return err +} + +// Validate validates required fields are set +func (o *RoleBindingOptions) Validate() error { + if len(o.Name) == 0 { + return fmt.Errorf("name must be specified") + } + if (len(o.ClusterRole) == 0) == (len(o.Role) == 0) { + return fmt.Errorf("exactly one of clusterrole or role must be specified") + } + return nil +} + +// Run performs the execution of 'create rolebinding' sub command +func (o *RoleBindingOptions) Run() error { + roleBinding, err := o.createRoleBinding() + if err != nil { + return err + } + if err := util.CreateOrUpdateAnnotation(o.CreateAnnotation, roleBinding, scheme.DefaultJSONEncoder()); err != nil { + return err + } + + if o.DryRunStrategy != cmdutil.DryRunClient { + createOptions := metav1.CreateOptions{} + if o.FieldManager != "" { + createOptions.FieldManager = o.FieldManager + } + createOptions.FieldValidation = o.ValidationDirective + if o.DryRunStrategy == cmdutil.DryRunServer { + createOptions.DryRun = []string{metav1.DryRunAll} + } + roleBinding, err = o.Client.RoleBindings(o.Namespace).Create(context.TODO(), roleBinding, createOptions) + if err != nil { + return fmt.Errorf("failed to create rolebinding: %v", err) + } + } + return o.PrintObj(roleBinding) +} + +func (o *RoleBindingOptions) createRoleBinding() (*rbacv1.RoleBinding, error) { + namespace := "" + if o.EnforceNamespace { + namespace = o.Namespace + } + + roleBinding := &rbacv1.RoleBinding{ + TypeMeta: metav1.TypeMeta{APIVersion: rbacv1.SchemeGroupVersion.String(), Kind: "RoleBinding"}, + ObjectMeta: metav1.ObjectMeta{ + Name: o.Name, + Namespace: namespace, + }, + } + + switch { + case len(o.Role) > 0: + roleBinding.RoleRef = rbacv1.RoleRef{ + APIGroup: rbacv1.GroupName, + Kind: "Role", + Name: o.Role, + } + case len(o.ClusterRole) > 0: + roleBinding.RoleRef = rbacv1.RoleRef{ + APIGroup: rbacv1.GroupName, + Kind: "ClusterRole", + Name: o.ClusterRole, + } + } + + for _, user := range o.Users { + roleBinding.Subjects = append(roleBinding.Subjects, rbacv1.Subject{ + Kind: rbacv1.UserKind, + APIGroup: rbacv1.GroupName, + Name: user, + }) + } + + for _, group := range o.Groups { + roleBinding.Subjects = append(roleBinding.Subjects, rbacv1.Subject{ + Kind: rbacv1.GroupKind, + APIGroup: rbacv1.GroupName, + Name: group, + }) + } + + for _, sa := range o.ServiceAccounts { + tokens := strings.Split(sa, ":") + if len(tokens) != 2 || tokens[0] == "" || tokens[1] == "" { + return nil, fmt.Errorf("serviceaccount must be :") + } + roleBinding.Subjects = append(roleBinding.Subjects, rbacv1.Subject{ + Kind: rbacv1.ServiceAccountKind, + APIGroup: "", + Namespace: tokens[0], + Name: tokens[1], + }) + } + return roleBinding, nil +} diff --git a/vendor/k8s.io/kubectl/pkg/cmd/create/create_secret.go b/vendor/k8s.io/kubectl/pkg/cmd/create/create_secret.go new file mode 100644 index 000000000000..b9bb191f9f5c --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/cmd/create/create_secret.go @@ -0,0 +1,421 @@ +/* +Copyright 2015 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 create + +import ( + "context" + "fmt" + "os" + "path" + "strings" + + "github.com/spf13/cobra" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/validation" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/genericiooptions" + corev1client "k8s.io/client-go/kubernetes/typed/core/v1" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/scheme" + "k8s.io/kubectl/pkg/util" + "k8s.io/kubectl/pkg/util/hash" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/templates" +) + +// NewCmdCreateSecret groups subcommands to create various types of secrets. +// This is the entry point of create_secret.go which will be called by create.go +func NewCmdCreateSecret(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + cmd := &cobra.Command{ + Use: "secret (docker-registry | generic | tls)", + DisableFlagsInUseLine: true, + Short: i18n.T("Create a secret using a specified subcommand"), + Long: secretLong, + Run: cmdutil.DefaultSubCommandRun(ioStreams.ErrOut), + } + cmd.AddCommand(NewCmdCreateSecretDockerRegistry(f, ioStreams)) + cmd.AddCommand(NewCmdCreateSecretTLS(f, ioStreams)) + cmd.AddCommand(NewCmdCreateSecretGeneric(f, ioStreams)) + + return cmd +} + +var ( + secretLong = templates.LongDesc(i18n.T(` + Create a secret with specified type. + + A docker-registry type secret is for accessing a container registry. + + A generic type secret indicate an Opaque secret type. + + A tls type secret holds TLS certificate and its associated key.`)) + + secretForGenericLong = templates.LongDesc(i18n.T(` + Create a secret based on a file, directory, or specified literal value. + + A single secret may package one or more key/value pairs. + + When creating a secret based on a file, the key will default to the basename of the file, and the value will + default to the file content. If the basename is an invalid key or you wish to chose your own, you may specify + an alternate key. + + When creating a secret based on a directory, each file whose basename is a valid key in the directory will be + packaged into the secret. Any directory entries except regular files are ignored (e.g. subdirectories, + symlinks, devices, pipes, etc).`)) + + secretForGenericExample = templates.Examples(i18n.T(` + # Create a new secret named my-secret with keys for each file in folder bar + kubectl create secret generic my-secret --from-file=path/to/bar + + # Create a new secret named my-secret with specified keys instead of names on disk + kubectl create secret generic my-secret --from-file=ssh-privatekey=path/to/id_rsa --from-file=ssh-publickey=path/to/id_rsa.pub + + # Create a new secret named my-secret with key1=supersecret and key2=topsecret + kubectl create secret generic my-secret --from-literal=key1=supersecret --from-literal=key2=topsecret + + # Create a new secret named my-secret using a combination of a file and a literal + kubectl create secret generic my-secret --from-file=ssh-privatekey=path/to/id_rsa --from-literal=passphrase=topsecret + + # Create a new secret named my-secret from env files + kubectl create secret generic my-secret --from-env-file=path/to/foo.env --from-env-file=path/to/bar.env`)) +) + +// CreateSecretOptions holds the options for 'create secret' sub command +type CreateSecretOptions struct { + // PrintFlags holds options necessary for obtaining a printer + PrintFlags *genericclioptions.PrintFlags + PrintObj func(obj runtime.Object) error + + // Name of secret (required) + Name string + // Type of secret (optional) + Type string + // FileSources to derive the secret from (optional) + FileSources []string + // LiteralSources to derive the secret from (optional) + LiteralSources []string + // EnvFileSources to derive the secret from (optional) + EnvFileSources []string + // AppendHash; if true, derive a hash from the Secret data and type and append it to the name + AppendHash bool + + FieldManager string + CreateAnnotation bool + Namespace string + EnforceNamespace bool + + Client corev1client.CoreV1Interface + DryRunStrategy cmdutil.DryRunStrategy + ValidationDirective string + + genericiooptions.IOStreams +} + +// NewSecretOptions creates a new *CreateSecretOptions with default value +func NewSecretOptions(ioStreams genericiooptions.IOStreams) *CreateSecretOptions { + return &CreateSecretOptions{ + PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme), + IOStreams: ioStreams, + } +} + +// NewCmdCreateSecretGeneric is a command to create generic secrets from files, directories, or literal values +func NewCmdCreateSecretGeneric(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + o := NewSecretOptions(ioStreams) + + cmd := &cobra.Command{ + Use: "generic NAME [--type=string] [--from-file=[key=]source] [--from-literal=key1=value1] [--dry-run=server|client|none]", + DisableFlagsInUseLine: true, + Short: i18n.T("Create a secret from a local file, directory, or literal value"), + Long: secretForGenericLong, + Example: secretForGenericExample, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.Run()) + }, + } + o.PrintFlags.AddFlags(cmd) + + cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddValidateFlags(cmd) + cmdutil.AddDryRunFlag(cmd) + + cmd.Flags().StringSliceVar(&o.FileSources, "from-file", o.FileSources, "Key files can be specified using their file path, in which case a default name will be given to them, or optionally with a name and file path, in which case the given name will be used. Specifying a directory will iterate each named file in the directory that is a valid secret key.") + cmd.Flags().StringArrayVar(&o.LiteralSources, "from-literal", o.LiteralSources, "Specify a key and literal value to insert in secret (i.e. mykey=somevalue)") + cmd.Flags().StringSliceVar(&o.EnvFileSources, "from-env-file", o.EnvFileSources, "Specify the path to a file to read lines of key=val pairs to create a secret.") + cmd.Flags().StringVar(&o.Type, "type", o.Type, i18n.T("The type of secret to create")) + cmd.Flags().BoolVar(&o.AppendHash, "append-hash", o.AppendHash, "Append a hash of the secret to its name.") + + cmdutil.AddFieldManagerFlagVar(cmd, &o.FieldManager, "kubectl-create") + + return cmd +} + +// Complete loads data from the command line environment +func (o *CreateSecretOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { + var err error + o.Name, err = NameFromCommandArgs(cmd, args) + if err != nil { + return err + } + + restConfig, err := f.ToRESTConfig() + if err != nil { + return err + } + + o.Client, err = corev1client.NewForConfig(restConfig) + if err != nil { + return err + } + + o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) + + o.DryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd) + if err != nil { + return err + } + + o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace() + if err != nil { + return err + } + + cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) + printer, err := o.PrintFlags.ToPrinter() + if err != nil { + return err + } + + o.PrintObj = func(obj runtime.Object) error { + return printer.PrintObj(obj, o.Out) + } + + o.ValidationDirective, err = cmdutil.GetValidationDirective(cmd) + if err != nil { + return err + } + + return nil +} + +// Validate checks if CreateSecretOptions has sufficient value to run +func (o *CreateSecretOptions) Validate() error { + if len(o.Name) == 0 { + return fmt.Errorf("name must be specified") + } + if len(o.EnvFileSources) > 0 && (len(o.FileSources) > 0 || len(o.LiteralSources) > 0) { + return fmt.Errorf("from-env-file cannot be combined with from-file or from-literal") + } + return nil +} + +// Run calls createSecret which will create secret based on CreateSecretOptions +// and makes an API call to the server +func (o *CreateSecretOptions) Run() error { + secret, err := o.createSecret() + if err != nil { + return err + } + err = util.CreateOrUpdateAnnotation(o.CreateAnnotation, secret, scheme.DefaultJSONEncoder()) + if err != nil { + return err + } + if o.DryRunStrategy != cmdutil.DryRunClient { + createOptions := metav1.CreateOptions{} + if o.FieldManager != "" { + createOptions.FieldManager = o.FieldManager + } + createOptions.FieldValidation = o.ValidationDirective + if o.DryRunStrategy == cmdutil.DryRunServer { + createOptions.DryRun = []string{metav1.DryRunAll} + } + secret, err = o.Client.Secrets(o.Namespace).Create(context.TODO(), secret, createOptions) + if err != nil { + return fmt.Errorf("failed to create secret %v", err) + } + } + + return o.PrintObj(secret) +} + +// createSecret fills in key value pair from the information given in +// CreateSecretOptions into *corev1.Secret +func (o *CreateSecretOptions) createSecret() (*corev1.Secret, error) { + namespace := "" + if o.EnforceNamespace { + namespace = o.Namespace + } + secret := newSecretObj(o.Name, namespace, corev1.SecretType(o.Type)) + if len(o.LiteralSources) > 0 { + if err := handleSecretFromLiteralSources(secret, o.LiteralSources); err != nil { + return nil, err + } + } + if len(o.FileSources) > 0 { + if err := handleSecretFromFileSources(secret, o.FileSources); err != nil { + return nil, err + } + } + if len(o.EnvFileSources) > 0 { + if err := handleSecretFromEnvFileSources(secret, o.EnvFileSources); err != nil { + return nil, err + } + } + if o.AppendHash { + hash, err := hash.SecretHash(secret) + if err != nil { + return nil, err + } + secret.Name = fmt.Sprintf("%s-%s", secret.Name, hash) + } + + return secret, nil +} + +// newSecretObj will create a new Secret Object given name, namespace and secretType +func newSecretObj(name, namespace string, secretType corev1.SecretType) *corev1.Secret { + return &corev1.Secret{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "Secret", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Type: secretType, + Data: map[string][]byte{}, + } +} + +// handleSecretFromLiteralSources adds the specified literal source +// information into the provided secret +func handleSecretFromLiteralSources(secret *corev1.Secret, literalSources []string) error { + for _, literalSource := range literalSources { + keyName, value, err := util.ParseLiteralSource(literalSource) + if err != nil { + return err + } + if err = addKeyFromLiteralToSecret(secret, keyName, []byte(value)); err != nil { + return err + } + } + + return nil +} + +// handleSecretFromFileSources adds the specified file source information into the provided secret +func handleSecretFromFileSources(secret *corev1.Secret, fileSources []string) error { + for _, fileSource := range fileSources { + keyName, filePath, err := util.ParseFileSource(fileSource) + if err != nil { + return err + } + fileInfo, err := os.Stat(filePath) + if err != nil { + switch err := err.(type) { + case *os.PathError: + return fmt.Errorf("error reading %s: %v", filePath, err.Err) + default: + return fmt.Errorf("error reading %s: %v", filePath, err) + } + } + // if the filePath is a directory + if fileInfo.IsDir() { + if strings.Contains(fileSource, "=") { + return fmt.Errorf("cannot give a key name for a directory path") + } + fileList, err := os.ReadDir(filePath) + if err != nil { + return fmt.Errorf("error listing files in %s: %v", filePath, err) + } + for _, item := range fileList { + itemPath := path.Join(filePath, item.Name()) + if item.Type().IsRegular() { + keyName = item.Name() + if err := addKeyFromFileToSecret(secret, keyName, itemPath); err != nil { + return err + } + } + } + // if the filepath is a file + } else { + if err := addKeyFromFileToSecret(secret, keyName, filePath); err != nil { + return err + } + } + + } + + return nil +} + +// handleSecretFromEnvFileSources adds the specified env files source information +// into the provided secret +func handleSecretFromEnvFileSources(secret *corev1.Secret, envFileSources []string) error { + for _, envFileSource := range envFileSources { + info, err := os.Stat(envFileSource) + if err != nil { + switch err := err.(type) { + case *os.PathError: + return fmt.Errorf("error reading %s: %v", envFileSource, err.Err) + default: + return fmt.Errorf("error reading %s: %v", envFileSource, err) + } + } + if info.IsDir() { + return fmt.Errorf("env secret file cannot be a directory") + } + err = cmdutil.AddFromEnvFile(envFileSource, func(key, value string) error { + return addKeyFromLiteralToSecret(secret, key, []byte(value)) + }) + if err != nil { + return err + } + } + + return nil +} + +// addKeyFromFileToSecret adds a key with the given name to a Secret, populating +// the value with the content of the given file path, or returns an error. +func addKeyFromFileToSecret(secret *corev1.Secret, keyName, filePath string) error { + data, err := os.ReadFile(filePath) + if err != nil { + return err + } + return addKeyFromLiteralToSecret(secret, keyName, data) +} + +// addKeyFromLiteralToSecret adds the given key and data to the given secret, +// returning an error if the key is not valid or if the key already exists. +func addKeyFromLiteralToSecret(secret *corev1.Secret, keyName string, data []byte) error { + if errs := validation.IsConfigMapKey(keyName); len(errs) != 0 { + return fmt.Errorf("%q is not valid key name for a Secret %s", keyName, strings.Join(errs, ";")) + } + if _, entryExists := secret.Data[keyName]; entryExists { + return fmt.Errorf("cannot add key %s, another key by that name already exists", keyName) + } + secret.Data[keyName] = data + + return nil +} diff --git a/vendor/k8s.io/kubectl/pkg/cmd/create/create_secret_docker.go b/vendor/k8s.io/kubectl/pkg/cmd/create/create_secret_docker.go new file mode 100644 index 000000000000..d8acc90d4a99 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/cmd/create/create_secret_docker.go @@ -0,0 +1,298 @@ +/* +Copyright 2021 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 create + +import ( + "context" + "encoding/base64" + "encoding/json" + "fmt" + + "github.com/spf13/cobra" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/genericiooptions" + corev1client "k8s.io/client-go/kubernetes/typed/core/v1" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/scheme" + "k8s.io/kubectl/pkg/util" + "k8s.io/kubectl/pkg/util/hash" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/templates" +) + +var ( + secretForDockerRegistryLong = templates.LongDesc(i18n.T(` + Create a new secret for use with Docker registries. + + Dockercfg secrets are used to authenticate against Docker registries. + + When using the Docker command line to push images, you can authenticate to a given registry by running: + '$ docker login DOCKER_REGISTRY_SERVER --username=DOCKER_USER --password=DOCKER_PASSWORD --email=DOCKER_EMAIL'. + + That produces a ~/.dockercfg file that is used by subsequent 'docker push' and 'docker pull' commands to + authenticate to the registry. The email address is optional. + + When creating applications, you may have a Docker registry that requires authentication. In order for the + nodes to pull images on your behalf, they must have the credentials. You can provide this information + by creating a dockercfg secret and attaching it to your service account.`)) + + secretForDockerRegistryExample = templates.Examples(i18n.T(` + # If you do not already have a .dockercfg file, create a dockercfg secret directly + kubectl create secret docker-registry my-secret --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL + + # Create a new secret named my-secret from ~/.docker/config.json + kubectl create secret docker-registry my-secret --from-file=.dockerconfigjson=path/to/.docker/config.json`)) +) + +// DockerConfigJSON represents a local docker auth config file +// for pulling images. +type DockerConfigJSON struct { + Auths DockerConfig `json:"auths" datapolicy:"token"` + // +optional + HttpHeaders map[string]string `json:"HttpHeaders,omitempty" datapolicy:"token"` +} + +// DockerConfig represents the config file used by the docker CLI. +// This config that represents the credentials that should be used +// when pulling images from specific image repositories. +type DockerConfig map[string]DockerConfigEntry + +// DockerConfigEntry holds the user information that grant the access to docker registry +type DockerConfigEntry struct { + Username string `json:"username,omitempty"` + Password string `json:"password,omitempty" datapolicy:"password"` + Email string `json:"email,omitempty"` + Auth string `json:"auth,omitempty" datapolicy:"token"` +} + +// CreateSecretDockerRegistryOptions holds the options for 'create secret docker-registry' sub command +type CreateSecretDockerRegistryOptions struct { + // PrintFlags holds options necessary for obtaining a printer + PrintFlags *genericclioptions.PrintFlags + PrintObj func(obj runtime.Object) error + + // Name of secret (required) + Name string + // FileSources to derive the secret from (optional) + FileSources []string + // Username for registry (required) + Username string + // Email for registry (optional) + Email string + // Password for registry (required) + Password string `datapolicy:"password"` + // Server for registry (required) + Server string + // AppendHash; if true, derive a hash from the Secret and append it to the name + AppendHash bool + + FieldManager string + CreateAnnotation bool + Namespace string + EnforceNamespace bool + + Client corev1client.CoreV1Interface + DryRunStrategy cmdutil.DryRunStrategy + ValidationDirective string + + genericiooptions.IOStreams +} + +// NewSecretDockerRegistryOptions creates a new *CreateSecretDockerRegistryOptions with default value +func NewSecretDockerRegistryOptions(ioStreams genericiooptions.IOStreams) *CreateSecretDockerRegistryOptions { + return &CreateSecretDockerRegistryOptions{ + Server: "https://index.docker.io/v1/", + PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme), + IOStreams: ioStreams, + } +} + +// NewCmdCreateSecretDockerRegistry is a macro command for creating secrets to work with Docker registries +func NewCmdCreateSecretDockerRegistry(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + o := NewSecretDockerRegistryOptions(ioStreams) + + cmd := &cobra.Command{ + Use: "docker-registry NAME --docker-username=user --docker-password=password --docker-email=email [--docker-server=string] [--from-file=[key=]source] [--dry-run=server|client|none]", + DisableFlagsInUseLine: true, + Short: i18n.T("Create a secret for use with a Docker registry"), + Long: secretForDockerRegistryLong, + Example: secretForDockerRegistryExample, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.Run()) + }, + } + + o.PrintFlags.AddFlags(cmd) + + cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddValidateFlags(cmd) + cmdutil.AddDryRunFlag(cmd) + + cmd.Flags().StringVar(&o.Username, "docker-username", o.Username, i18n.T("Username for Docker registry authentication")) + cmd.Flags().StringVar(&o.Password, "docker-password", o.Password, i18n.T("Password for Docker registry authentication")) + cmd.Flags().StringVar(&o.Email, "docker-email", o.Email, i18n.T("Email for Docker registry")) + cmd.Flags().StringVar(&o.Server, "docker-server", o.Server, i18n.T("Server location for Docker registry")) + cmd.Flags().BoolVar(&o.AppendHash, "append-hash", o.AppendHash, "Append a hash of the secret to its name.") + cmd.Flags().StringSliceVar(&o.FileSources, "from-file", o.FileSources, "Key files can be specified using their file path, in which case a default name will be given to them, or optionally with a name and file path, in which case the given name will be used. Specifying a directory will iterate each named file in the directory that is a valid secret key.") + + cmdutil.AddFieldManagerFlagVar(cmd, &o.FieldManager, "kubectl-create") + + return cmd +} + +// Complete loads data from the command line environment +func (o *CreateSecretDockerRegistryOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { + var err error + o.Name, err = NameFromCommandArgs(cmd, args) + if err != nil { + return err + } + + restConfig, err := f.ToRESTConfig() + if err != nil { + return err + } + + o.Client, err = corev1client.NewForConfig(restConfig) + if err != nil { + return err + } + + o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) + + o.DryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd) + if err != nil { + return err + } + + o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace() + if err != nil { + return err + } + + cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) + printer, err := o.PrintFlags.ToPrinter() + if err != nil { + return err + } + + o.PrintObj = func(obj runtime.Object) error { + return printer.PrintObj(obj, o.Out) + } + + o.ValidationDirective, err = cmdutil.GetValidationDirective(cmd) + if err != nil { + return err + } + + return nil +} + +// Validate checks if CreateSecretDockerRegistryOptions has sufficient value to run +func (o *CreateSecretDockerRegistryOptions) Validate() error { + if len(o.Name) == 0 { + return fmt.Errorf("name must be specified") + } + if len(o.FileSources) == 0 && (len(o.Username) == 0 || len(o.Password) == 0 || len(o.Server) == 0) { + return fmt.Errorf("either --from-file or the combination of --docker-username, --docker-password and --docker-server is required") + } + return nil +} + +// Run calls createSecretDockerRegistry which will create secretDockerRegistry based on CreateSecretDockerRegistryOptions +// and makes an API call to the server +func (o *CreateSecretDockerRegistryOptions) Run() error { + secretDockerRegistry, err := o.createSecretDockerRegistry() + if err != nil { + return err + } + err = util.CreateOrUpdateAnnotation(o.CreateAnnotation, secretDockerRegistry, scheme.DefaultJSONEncoder()) + if err != nil { + return err + } + if o.DryRunStrategy != cmdutil.DryRunClient { + createOptions := metav1.CreateOptions{} + if o.FieldManager != "" { + createOptions.FieldManager = o.FieldManager + } + createOptions.FieldValidation = o.ValidationDirective + if o.DryRunStrategy == cmdutil.DryRunServer { + createOptions.DryRun = []string{metav1.DryRunAll} + } + secretDockerRegistry, err = o.Client.Secrets(o.Namespace).Create(context.TODO(), secretDockerRegistry, createOptions) + if err != nil { + return fmt.Errorf("failed to create secret %v", err) + } + } + + return o.PrintObj(secretDockerRegistry) +} + +// createSecretDockerRegistry fills in key value pair from the information given in +// CreateSecretDockerRegistryOptions into *corev1.Secret +func (o *CreateSecretDockerRegistryOptions) createSecretDockerRegistry() (*corev1.Secret, error) { + namespace := "" + if o.EnforceNamespace { + namespace = o.Namespace + } + secretDockerRegistry := newSecretObj(o.Name, namespace, corev1.SecretTypeDockerConfigJson) + if len(o.FileSources) > 0 { + if err := handleSecretFromFileSources(secretDockerRegistry, o.FileSources); err != nil { + return nil, err + } + } else { + dockerConfigJSONContent, err := handleDockerCfgJSONContent(o.Username, o.Password, o.Email, o.Server) + if err != nil { + return nil, err + } + secretDockerRegistry.Data[corev1.DockerConfigJsonKey] = dockerConfigJSONContent + } + if o.AppendHash { + hash, err := hash.SecretHash(secretDockerRegistry) + if err != nil { + return nil, err + } + secretDockerRegistry.Name = fmt.Sprintf("%s-%s", secretDockerRegistry.Name, hash) + } + return secretDockerRegistry, nil +} + +// handleDockerCfgJSONContent serializes a ~/.docker/config.json file +func handleDockerCfgJSONContent(username, password, email, server string) ([]byte, error) { + dockerConfigAuth := DockerConfigEntry{ + Username: username, + Password: password, + Email: email, + Auth: encodeDockerConfigFieldAuth(username, password), + } + dockerConfigJSON := DockerConfigJSON{ + Auths: map[string]DockerConfigEntry{server: dockerConfigAuth}, + } + + return json.Marshal(dockerConfigJSON) +} + +// encodeDockerConfigFieldAuth returns base64 encoding of the username and password string +func encodeDockerConfigFieldAuth(username, password string) string { + fieldValue := username + ":" + password + return base64.StdEncoding.EncodeToString([]byte(fieldValue)) +} diff --git a/vendor/k8s.io/kubectl/pkg/cmd/create/create_secret_tls.go b/vendor/k8s.io/kubectl/pkg/cmd/create/create_secret_tls.go new file mode 100644 index 000000000000..a23e4ca62e15 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/cmd/create/create_secret_tls.go @@ -0,0 +1,249 @@ +/* +Copyright 2021 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 create + +import ( + "context" + "crypto/tls" + "fmt" + "os" + + "github.com/spf13/cobra" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/genericiooptions" + corev1client "k8s.io/client-go/kubernetes/typed/core/v1" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/scheme" + "k8s.io/kubectl/pkg/util" + "k8s.io/kubectl/pkg/util/hash" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/templates" +) + +var ( + secretForTLSLong = templates.LongDesc(i18n.T(` + Create a TLS secret from the given public/private key pair. + + The public/private key pair must exist beforehand. The public key certificate must be .PEM encoded and match + the given private key.`)) + + secretForTLSExample = templates.Examples(i18n.T(` + # Create a new TLS secret named tls-secret with the given key pair + kubectl create secret tls tls-secret --cert=path/to/tls.crt --key=path/to/tls.key`)) +) + +// CreateSecretTLSOptions holds the options for 'create secret tls' sub command +type CreateSecretTLSOptions struct { + // PrintFlags holds options necessary for obtaining a printer + PrintFlags *genericclioptions.PrintFlags + PrintObj func(obj runtime.Object) error + + // Name is the name of this TLS secret. + Name string + // Key is the path to the user's private key. + Key string + // Cert is the path to the user's public key certificate. + Cert string + // AppendHash; if true, derive a hash from the Secret and append it to the name + AppendHash bool + + FieldManager string + CreateAnnotation bool + Namespace string + EnforceNamespace bool + + Client corev1client.CoreV1Interface + DryRunStrategy cmdutil.DryRunStrategy + ValidationDirective string + + genericiooptions.IOStreams +} + +// NewSecretTLSOptions creates a new *CreateSecretTLSOptions with default value +func NewSecretTLSOptions(ioStrems genericiooptions.IOStreams) *CreateSecretTLSOptions { + return &CreateSecretTLSOptions{ + PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme), + IOStreams: ioStrems, + } +} + +// NewCmdCreateSecretTLS is a macro command for creating secrets to work with TLS client or server +func NewCmdCreateSecretTLS(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + o := NewSecretTLSOptions(ioStreams) + + cmd := &cobra.Command{ + Use: "tls NAME --cert=path/to/cert/file --key=path/to/key/file [--dry-run=server|client|none]", + DisableFlagsInUseLine: true, + Short: i18n.T("Create a TLS secret"), + Long: secretForTLSLong, + Example: secretForTLSExample, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.Run()) + }, + } + + o.PrintFlags.AddFlags(cmd) + + cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddValidateFlags(cmd) + cmdutil.AddDryRunFlag(cmd) + + cmd.Flags().StringVar(&o.Cert, "cert", o.Cert, i18n.T("Path to PEM encoded public key certificate.")) + cmd.Flags().StringVar(&o.Key, "key", o.Key, i18n.T("Path to private key associated with given certificate.")) + cmd.Flags().BoolVar(&o.AppendHash, "append-hash", o.AppendHash, "Append a hash of the secret to its name.") + + cmdutil.AddFieldManagerFlagVar(cmd, &o.FieldManager, "kubectl-create") + + return cmd +} + +// Complete loads data from the command line environment +func (o *CreateSecretTLSOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { + var err error + o.Name, err = NameFromCommandArgs(cmd, args) + if err != nil { + return err + } + + restConfig, err := f.ToRESTConfig() + if err != nil { + return err + } + + o.Client, err = corev1client.NewForConfig(restConfig) + if err != nil { + return err + } + + o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) + + o.DryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd) + if err != nil { + return err + } + + o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace() + if err != nil { + return err + } + + cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) + printer, err := o.PrintFlags.ToPrinter() + if err != nil { + return err + } + + o.PrintObj = func(obj runtime.Object) error { + return printer.PrintObj(obj, o.Out) + } + + o.ValidationDirective, err = cmdutil.GetValidationDirective(cmd) + if err != nil { + return err + } + + return nil +} + +// Validate checks if CreateSecretTLSOptions hass sufficient value to run +func (o *CreateSecretTLSOptions) Validate() error { + // TODO: This is not strictly necessary. We can generate a self signed cert + // if no key/cert is given. The only requirement is that we either get both + // or none. See test/e2e/ingress_utils for self signed cert generation. + if len(o.Key) == 0 || len(o.Cert) == 0 { + return fmt.Errorf("key and cert must be specified") + } + return nil +} + +// Run calls createSecretTLS which will create secretTLS based on CreateSecretTLSOptions +// and makes an API call to the server +func (o *CreateSecretTLSOptions) Run() error { + secretTLS, err := o.createSecretTLS() + if err != nil { + return err + } + err = util.CreateOrUpdateAnnotation(o.CreateAnnotation, secretTLS, scheme.DefaultJSONEncoder()) + if err != nil { + return err + } + if o.DryRunStrategy != cmdutil.DryRunClient { + createOptions := metav1.CreateOptions{} + if o.FieldManager != "" { + createOptions.FieldManager = o.FieldManager + } + createOptions.FieldValidation = o.ValidationDirective + if o.DryRunStrategy == cmdutil.DryRunServer { + createOptions.DryRun = []string{metav1.DryRunAll} + } + secretTLS, err = o.Client.Secrets(o.Namespace).Create(context.TODO(), secretTLS, createOptions) + if err != nil { + return fmt.Errorf("failed to create secret %v", err) + } + } + return o.PrintObj(secretTLS) +} + +// createSecretTLS fills in key value pair from the information given in +// CreateSecretTLSOptions into *corev1.Secret +func (o *CreateSecretTLSOptions) createSecretTLS() (*corev1.Secret, error) { + namespace := "" + if o.EnforceNamespace { + namespace = o.Namespace + } + tlsCert, err := readFile(o.Cert) + if err != nil { + return nil, err + } + tlsKey, err := readFile(o.Key) + if err != nil { + return nil, err + } + if _, err := tls.X509KeyPair(tlsCert, tlsKey); err != nil { + return nil, err + } + // TODO: Add more validation. + // 1. If the certificate contains intermediates, it is a valid chain. + // 2. Format etc. + + secretTLS := newSecretObj(o.Name, namespace, corev1.SecretTypeTLS) + secretTLS.Data[corev1.TLSCertKey] = []byte(tlsCert) + secretTLS.Data[corev1.TLSPrivateKeyKey] = []byte(tlsKey) + if o.AppendHash { + hash, err := hash.SecretHash(secretTLS) + if err != nil { + return nil, err + } + secretTLS.Name = fmt.Sprintf("%s-%s", secretTLS.Name, hash) + } + + return secretTLS, nil +} + +// readFile just reads a file into a byte array. +func readFile(file string) ([]byte, error) { + b, err := os.ReadFile(file) + if err != nil { + return []byte{}, fmt.Errorf("Cannot read file %v, %v", file, err) + } + return b, nil +} diff --git a/vendor/k8s.io/kubectl/pkg/cmd/create/create_service.go b/vendor/k8s.io/kubectl/pkg/cmd/create/create_service.go new file mode 100644 index 000000000000..54b164b351b8 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/cmd/create/create_service.go @@ -0,0 +1,412 @@ +/* +Copyright 2016 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 create + +import ( + "context" + "fmt" + "strconv" + "strings" + + "github.com/spf13/cobra" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/apimachinery/pkg/util/validation" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/genericiooptions" + corev1client "k8s.io/client-go/kubernetes/typed/core/v1" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/scheme" + "k8s.io/kubectl/pkg/util" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/templates" + utilsnet "k8s.io/utils/net" +) + +// NewCmdCreateService is a macro command to create a new service +func NewCmdCreateService(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + cmd := &cobra.Command{ + Use: "service", + Aliases: []string{"svc"}, + Short: i18n.T("Create a service using a specified subcommand"), + Long: i18n.T("Create a service using a specified subcommand."), + Run: cmdutil.DefaultSubCommandRun(ioStreams.ErrOut), + } + cmd.AddCommand(NewCmdCreateServiceClusterIP(f, ioStreams)) + cmd.AddCommand(NewCmdCreateServiceNodePort(f, ioStreams)) + cmd.AddCommand(NewCmdCreateServiceLoadBalancer(f, ioStreams)) + cmd.AddCommand(NewCmdCreateServiceExternalName(f, ioStreams)) + + return cmd +} + +// ServiceOptions holds the options for 'create service' sub command +type ServiceOptions struct { + PrintFlags *genericclioptions.PrintFlags + PrintObj func(obj runtime.Object) error + + Name string + TCP []string + Type corev1.ServiceType + ClusterIP string + NodePort int + ExternalName string + + FieldManager string + CreateAnnotation bool + Namespace string + EnforceNamespace bool + + Client corev1client.CoreV1Interface + DryRunStrategy cmdutil.DryRunStrategy + ValidationDirective string + genericiooptions.IOStreams +} + +// NewServiceOptions creates a ServiceOptions struct +func NewServiceOptions(ioStreams genericiooptions.IOStreams, serviceType corev1.ServiceType) *ServiceOptions { + return &ServiceOptions{ + PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme), + IOStreams: ioStreams, + Type: serviceType, + } +} + +// Complete completes all the required options +func (o *ServiceOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { + name, err := NameFromCommandArgs(cmd, args) + if err != nil { + return err + } + o.Name = name + + clientConfig, err := f.ToRESTConfig() + if err != nil { + return err + } + o.Client, err = corev1client.NewForConfig(clientConfig) + if err != nil { + return err + } + + o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace() + if err != nil { + return err + } + + o.DryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd) + if err != nil { + return err + } + cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) + + printer, err := o.PrintFlags.ToPrinter() + if err != nil { + return err + } + + o.PrintObj = func(obj runtime.Object) error { + return printer.PrintObj(obj, o.Out) + } + + o.ValidationDirective, err = cmdutil.GetValidationDirective(cmd) + if err != nil { + return err + } + + return nil +} + +// Validate if the options are valid +func (o *ServiceOptions) Validate() error { + if o.ClusterIP == corev1.ClusterIPNone && o.Type != corev1.ServiceTypeClusterIP { + return fmt.Errorf("ClusterIP=None can only be used with ClusterIP service type") + } + if o.ClusterIP != corev1.ClusterIPNone && len(o.TCP) == 0 && o.Type != corev1.ServiceTypeExternalName { + return fmt.Errorf("at least one tcp port specifier must be provided") + } + if o.Type == corev1.ServiceTypeExternalName { + if errs := validation.IsDNS1123Subdomain(o.ExternalName); len(errs) != 0 { + return fmt.Errorf("invalid service external name %s", o.ExternalName) + } + } + return nil +} + +func (o *ServiceOptions) createService() (*corev1.Service, error) { + ports := []corev1.ServicePort{} + for _, tcpString := range o.TCP { + port, targetPort, err := parsePorts(tcpString) + if err != nil { + return nil, err + } + + portName := strings.Replace(tcpString, ":", "-", -1) + ports = append(ports, corev1.ServicePort{ + Name: portName, + Port: port, + TargetPort: targetPort, + Protocol: corev1.Protocol("TCP"), + NodePort: int32(o.NodePort), + }) + } + + // setup default label and selector + labels := map[string]string{} + labels["app"] = o.Name + selector := map[string]string{} + selector["app"] = o.Name + + namespace := "" + if o.EnforceNamespace { + namespace = o.Namespace + } + + service := corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: o.Name, + Labels: labels, + Namespace: namespace, + }, + Spec: corev1.ServiceSpec{ + Type: o.Type, + Selector: selector, + Ports: ports, + ExternalName: o.ExternalName, + }, + } + if len(o.ClusterIP) > 0 { + service.Spec.ClusterIP = o.ClusterIP + } + return &service, nil +} + +// Run the service command +func (o *ServiceOptions) Run() error { + service, err := o.createService() + if err != nil { + return err + } + + if err := util.CreateOrUpdateAnnotation(o.CreateAnnotation, service, scheme.DefaultJSONEncoder()); err != nil { + return err + } + + if o.DryRunStrategy != cmdutil.DryRunClient { + createOptions := metav1.CreateOptions{} + if o.FieldManager != "" { + createOptions.FieldManager = o.FieldManager + } + createOptions.FieldValidation = o.ValidationDirective + if o.DryRunStrategy == cmdutil.DryRunServer { + createOptions.DryRun = []string{metav1.DryRunAll} + } + var err error + service, err = o.Client.Services(o.Namespace).Create(context.TODO(), service, createOptions) + if err != nil { + return fmt.Errorf("failed to create %s service: %v", o.Type, err) + } + } + return o.PrintObj(service) +} + +var ( + serviceClusterIPLong = templates.LongDesc(i18n.T(` + Create a ClusterIP service with the specified name.`)) + + serviceClusterIPExample = templates.Examples(i18n.T(` + # Create a new ClusterIP service named my-cs + kubectl create service clusterip my-cs --tcp=5678:8080 + + # Create a new ClusterIP service named my-cs (in headless mode) + kubectl create service clusterip my-cs --clusterip="None"`)) +) + +// NewCmdCreateServiceClusterIP is a command to create a ClusterIP service +func NewCmdCreateServiceClusterIP(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + o := NewServiceOptions(ioStreams, corev1.ServiceTypeClusterIP) + + cmd := &cobra.Command{ + Use: "clusterip NAME [--tcp=:] [--dry-run=server|client|none]", + DisableFlagsInUseLine: true, + Short: i18n.T("Create a ClusterIP service"), + Long: serviceClusterIPLong, + Example: serviceClusterIPExample, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.Run()) + }, + } + + o.PrintFlags.AddFlags(cmd) + + cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddValidateFlags(cmd) + cmd.Flags().StringSliceVar(&o.TCP, "tcp", o.TCP, "Port pairs can be specified as ':'.") + cmd.Flags().StringVar(&o.ClusterIP, "clusterip", o.ClusterIP, i18n.T("Assign your own ClusterIP or set to 'None' for a 'headless' service (no loadbalancing).")) + cmdutil.AddFieldManagerFlagVar(cmd, &o.FieldManager, "kubectl-create") + cmdutil.AddDryRunFlag(cmd) + + return cmd +} + +var ( + serviceNodePortLong = templates.LongDesc(i18n.T(` + Create a NodePort service with the specified name.`)) + + serviceNodePortExample = templates.Examples(i18n.T(` + # Create a new NodePort service named my-ns + kubectl create service nodeport my-ns --tcp=5678:8080`)) +) + +// NewCmdCreateServiceNodePort is a macro command for creating a NodePort service +func NewCmdCreateServiceNodePort(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + o := NewServiceOptions(ioStreams, corev1.ServiceTypeNodePort) + + cmd := &cobra.Command{ + Use: "nodeport NAME [--tcp=port:targetPort] [--dry-run=server|client|none]", + DisableFlagsInUseLine: true, + Short: i18n.T("Create a NodePort service"), + Long: serviceNodePortLong, + Example: serviceNodePortExample, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.Run()) + }, + } + + o.PrintFlags.AddFlags(cmd) + + cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddValidateFlags(cmd) + cmd.Flags().IntVar(&o.NodePort, "node-port", o.NodePort, "Port used to expose the service on each node in a cluster.") + cmdutil.AddFieldManagerFlagVar(cmd, &o.FieldManager, "kubectl-create") + cmd.Flags().StringSliceVar(&o.TCP, "tcp", o.TCP, "Port pairs can be specified as ':'.") + cmdutil.AddDryRunFlag(cmd) + return cmd +} + +var ( + serviceLoadBalancerLong = templates.LongDesc(i18n.T(` + Create a LoadBalancer service with the specified name.`)) + + serviceLoadBalancerExample = templates.Examples(i18n.T(` + # Create a new LoadBalancer service named my-lbs + kubectl create service loadbalancer my-lbs --tcp=5678:8080`)) +) + +// NewCmdCreateServiceLoadBalancer is a macro command for creating a LoadBalancer service +func NewCmdCreateServiceLoadBalancer(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + o := NewServiceOptions(ioStreams, corev1.ServiceTypeLoadBalancer) + + cmd := &cobra.Command{ + Use: "loadbalancer NAME [--tcp=port:targetPort] [--dry-run=server|client|none]", + DisableFlagsInUseLine: true, + Short: i18n.T("Create a LoadBalancer service"), + Long: serviceLoadBalancerLong, + Example: serviceLoadBalancerExample, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.Run()) + }, + } + + o.PrintFlags.AddFlags(cmd) + + cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddValidateFlags(cmd) + cmd.Flags().StringSliceVar(&o.TCP, "tcp", o.TCP, "Port pairs can be specified as ':'.") + cmdutil.AddFieldManagerFlagVar(cmd, &o.FieldManager, "kubectl-create") + cmdutil.AddDryRunFlag(cmd) + return cmd +} + +var ( + serviceExternalNameLong = templates.LongDesc(i18n.T(` + Create an ExternalName service with the specified name. + + ExternalName service references to an external DNS address instead of + only pods, which will allow application authors to reference services + that exist off platform, on other clusters, or locally.`)) + + serviceExternalNameExample = templates.Examples(i18n.T(` + # Create a new ExternalName service named my-ns + kubectl create service externalname my-ns --external-name bar.com`)) +) + +// NewCmdCreateServiceExternalName is a macro command for creating an ExternalName service +func NewCmdCreateServiceExternalName(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + o := NewServiceOptions(ioStreams, corev1.ServiceTypeExternalName) + + cmd := &cobra.Command{ + Use: "externalname NAME --external-name external.name [--dry-run=server|client|none]", + DisableFlagsInUseLine: true, + Short: i18n.T("Create an ExternalName service"), + Long: serviceExternalNameLong, + Example: serviceExternalNameExample, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.Run()) + }, + } + + o.PrintFlags.AddFlags(cmd) + + cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddValidateFlags(cmd) + cmd.Flags().StringSliceVar(&o.TCP, "tcp", o.TCP, "Port pairs can be specified as ':'.") + cmd.Flags().StringVar(&o.ExternalName, "external-name", o.ExternalName, i18n.T("External name of service")) + cmd.MarkFlagRequired("external-name") + cmdutil.AddFieldManagerFlagVar(cmd, &o.FieldManager, "kubectl-create") + cmdutil.AddDryRunFlag(cmd) + return cmd +} + +func parsePorts(portString string) (int32, intstr.IntOrString, error) { + portStringSlice := strings.Split(portString, ":") + + port, err := utilsnet.ParsePort(portStringSlice[0], true) + if err != nil { + return 0, intstr.FromInt32(0), err + } + + if len(portStringSlice) == 1 { + port32 := int32(port) + return port32, intstr.FromInt32(port32), nil + } + + var targetPort intstr.IntOrString + if portNum, err := strconv.Atoi(portStringSlice[1]); err != nil { + if errs := validation.IsValidPortName(portStringSlice[1]); len(errs) != 0 { + return 0, intstr.FromInt32(0), fmt.Errorf(strings.Join(errs, ",")) + } + targetPort = intstr.FromString(portStringSlice[1]) + } else { + if errs := validation.IsValidPortNum(portNum); len(errs) != 0 { + return 0, intstr.FromInt32(0), fmt.Errorf(strings.Join(errs, ",")) + } + targetPort = intstr.FromInt32(int32(portNum)) + } + return int32(port), targetPort, nil +} diff --git a/vendor/k8s.io/kubectl/pkg/cmd/create/create_serviceaccount.go b/vendor/k8s.io/kubectl/pkg/cmd/create/create_serviceaccount.go new file mode 100644 index 000000000000..da2e6a332d73 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/cmd/create/create_serviceaccount.go @@ -0,0 +1,202 @@ +/* +Copyright 2016 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 create + +import ( + "context" + "fmt" + + "github.com/spf13/cobra" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/genericiooptions" + coreclient "k8s.io/client-go/kubernetes/typed/core/v1" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/scheme" + "k8s.io/kubectl/pkg/util" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/templates" +) + +var ( + serviceAccountLong = templates.LongDesc(i18n.T(` + Create a service account with the specified name.`)) + + serviceAccountExample = templates.Examples(i18n.T(` + # Create a new service account named my-service-account + kubectl create serviceaccount my-service-account`)) +) + +// ServiceAccountOpts holds the options for 'create serviceaccount' sub command +type ServiceAccountOpts struct { + // PrintFlags holds options necessary for obtaining a printer + PrintFlags *genericclioptions.PrintFlags + PrintObj func(obj runtime.Object) error + // Name of resource being created + Name string + DryRunStrategy cmdutil.DryRunStrategy + ValidationDirective string + CreateAnnotation bool + FieldManager string + + Namespace string + EnforceNamespace bool + + Mapper meta.RESTMapper + Client *coreclient.CoreV1Client + + genericiooptions.IOStreams +} + +// NewServiceAccountOpts creates a new *ServiceAccountOpts with sane defaults +func NewServiceAccountOpts(ioStreams genericiooptions.IOStreams) *ServiceAccountOpts { + return &ServiceAccountOpts{ + PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme), + IOStreams: ioStreams, + } +} + +// NewCmdCreateServiceAccount is a macro command to create a new service account +func NewCmdCreateServiceAccount(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + o := NewServiceAccountOpts(ioStreams) + + cmd := &cobra.Command{ + Use: "serviceaccount NAME [--dry-run=server|client|none]", + DisableFlagsInUseLine: true, + Aliases: []string{"sa"}, + Short: i18n.T("Create a service account with the specified name"), + Long: serviceAccountLong, + Example: serviceAccountExample, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.Run()) + }, + } + + o.PrintFlags.AddFlags(cmd) + + cmdutil.AddApplyAnnotationFlags(cmd) + cmdutil.AddValidateFlags(cmd) + cmdutil.AddDryRunFlag(cmd) + cmdutil.AddFieldManagerFlagVar(cmd, &o.FieldManager, "kubectl-create") + return cmd +} + +// Complete completes all the required options +func (o *ServiceAccountOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { + var err error + o.Name, err = NameFromCommandArgs(cmd, args) + if err != nil { + return err + } + + restConfig, err := f.ToRESTConfig() + if err != nil { + return err + } + o.Client, err = coreclient.NewForConfig(restConfig) + if err != nil { + return err + } + + o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) + + o.DryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd) + if err != nil { + return err + } + + o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace() + if err != nil { + return err + } + + cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) + + printer, err := o.PrintFlags.ToPrinter() + if err != nil { + return err + } + + o.PrintObj = func(obj runtime.Object) error { + return printer.PrintObj(obj, o.Out) + } + + o.ValidationDirective, err = cmdutil.GetValidationDirective(cmd) + if err != nil { + return err + } + + return nil +} + +// Validate checks ServiceAccountOpts to see if there is sufficient information run the command. +func (o *ServiceAccountOpts) Validate() error { + if len(o.Name) == 0 { + return fmt.Errorf("name must be specified") + } + return nil +} + +// Run makes the api call to the server +func (o *ServiceAccountOpts) Run() error { + serviceAccount, err := o.createServiceAccount() + if err != nil { + return err + } + + if err := util.CreateOrUpdateAnnotation(o.CreateAnnotation, serviceAccount, scheme.DefaultJSONEncoder()); err != nil { + return err + } + + if o.DryRunStrategy != cmdutil.DryRunClient { + createOptions := metav1.CreateOptions{} + if o.FieldManager != "" { + createOptions.FieldManager = o.FieldManager + } + createOptions.FieldValidation = o.ValidationDirective + if o.DryRunStrategy == cmdutil.DryRunServer { + createOptions.DryRun = []string{metav1.DryRunAll} + } + serviceAccount, err = o.Client.ServiceAccounts(o.Namespace).Create(context.TODO(), serviceAccount, createOptions) + if err != nil { + return fmt.Errorf("failed to create serviceaccount: %v", err) + } + } + return o.PrintObj(serviceAccount) +} + +func (o *ServiceAccountOpts) createServiceAccount() (*corev1.ServiceAccount, error) { + namespace := "" + if o.EnforceNamespace { + namespace = o.Namespace + } + serviceAccount := &corev1.ServiceAccount{ + TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String(), Kind: "ServiceAccount"}, + ObjectMeta: metav1.ObjectMeta{ + Name: o.Name, + Namespace: namespace, + }, + } + serviceAccount.Name = o.Name + return serviceAccount, nil +} diff --git a/vendor/k8s.io/kubectl/pkg/cmd/create/create_token.go b/vendor/k8s.io/kubectl/pkg/cmd/create/create_token.go new file mode 100644 index 000000000000..adfd5964dc9b --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/cmd/create/create_token.go @@ -0,0 +1,282 @@ +/* +Copyright 2022 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 create + +import ( + "context" + "fmt" + "os" + "strings" + "time" + + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + authenticationv1 "k8s.io/api/authentication/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/genericiooptions" + corev1client "k8s.io/client-go/kubernetes/typed/core/v1" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/scheme" + "k8s.io/kubectl/pkg/util/completion" + "k8s.io/kubectl/pkg/util/templates" + "k8s.io/kubectl/pkg/util/term" + "k8s.io/utils/pointer" +) + +// TokenOptions is the data required to perform a token request operation. +type TokenOptions struct { + // PrintFlags holds options necessary for obtaining a printer + PrintFlags *genericclioptions.PrintFlags + PrintObj func(obj runtime.Object) error + + // Flags hold the parsed CLI flags. + Flags *pflag.FlagSet + + // Name and namespace of service account to create a token for + Name string + Namespace string + + // BoundObjectKind is the kind of object to bind the token to. Optional. Can be Pod or Secret. + BoundObjectKind string + // BoundObjectName is the name of the object to bind the token to. Required if BoundObjectKind is set. + BoundObjectName string + // BoundObjectUID is the uid of the object to bind the token to. If unset, defaults to the current uid of the bound object. + BoundObjectUID string + + // Audiences indicate the valid audiences for the requested token. If unset, defaults to the Kubernetes API server audiences. + Audiences []string + + // Duration is the requested token lifetime. Optional. + Duration time.Duration + + // CoreClient is the API client used to request the token. Required. + CoreClient corev1client.CoreV1Interface + + // IOStreams are the output streams for the operation. Required. + genericiooptions.IOStreams +} + +var ( + tokenLong = templates.LongDesc(`Request a service account token.`) + + tokenExample = templates.Examples(` + # Request a token to authenticate to the kube-apiserver as the service account "myapp" in the current namespace + kubectl create token myapp + + # Request a token for a service account in a custom namespace + kubectl create token myapp --namespace myns + + # Request a token with a custom expiration + kubectl create token myapp --duration 10m + + # Request a token with a custom audience + kubectl create token myapp --audience https://example.com + + # Request a token bound to an instance of a Secret object + kubectl create token myapp --bound-object-kind Secret --bound-object-name mysecret + + # Request a token bound to an instance of a Secret object with a specific UID + kubectl create token myapp --bound-object-kind Secret --bound-object-name mysecret --bound-object-uid 0d4691ed-659b-4935-a832-355f77ee47cc +`) +) + +func boundObjectKindToAPIVersions() map[string]string { + kinds := map[string]string{ + "Pod": "v1", + "Secret": "v1", + } + if os.Getenv("KUBECTL_NODE_BOUND_TOKENS") == "true" { + kinds["Node"] = "v1" + } + return kinds +} + +func NewTokenOpts(ioStreams genericiooptions.IOStreams) *TokenOptions { + return &TokenOptions{ + PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme), + IOStreams: ioStreams, + } +} + +// NewCmdCreateToken returns an initialized Command for 'create token' sub command +func NewCmdCreateToken(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + o := NewTokenOpts(ioStreams) + + cmd := &cobra.Command{ + Use: "token SERVICE_ACCOUNT_NAME", + DisableFlagsInUseLine: true, + Short: "Request a service account token", + Long: tokenLong, + Example: tokenExample, + ValidArgsFunction: completion.ResourceNameCompletionFunc(f, "serviceaccount"), + Run: func(cmd *cobra.Command, args []string) { + if err := o.Complete(f, cmd, args); err != nil { + cmdutil.CheckErr(err) + return + } + if err := o.Validate(); err != nil { + cmdutil.CheckErr(err) + return + } + if err := o.Run(); err != nil { + cmdutil.CheckErr(err) + return + } + }, + } + + o.PrintFlags.AddFlags(cmd) + + cmd.Flags().StringArrayVar(&o.Audiences, "audience", o.Audiences, "Audience of the requested token. If unset, defaults to requesting a token for use with the Kubernetes API server. May be repeated to request a token valid for multiple audiences.") + + cmd.Flags().DurationVar(&o.Duration, "duration", o.Duration, "Requested lifetime of the issued token. If not set or if set to 0, the lifetime will be determined by the server automatically. The server may return a token with a longer or shorter lifetime.") + + cmd.Flags().StringVar(&o.BoundObjectKind, "bound-object-kind", o.BoundObjectKind, "Kind of an object to bind the token to. "+ + "Supported kinds are "+strings.Join(sets.StringKeySet(boundObjectKindToAPIVersions()).List(), ", ")+". "+ + "If set, --bound-object-name must be provided.") + cmd.Flags().StringVar(&o.BoundObjectName, "bound-object-name", o.BoundObjectName, "Name of an object to bind the token to. "+ + "The token will expire when the object is deleted. "+ + "Requires --bound-object-kind.") + cmd.Flags().StringVar(&o.BoundObjectUID, "bound-object-uid", o.BoundObjectUID, "UID of an object to bind the token to. "+ + "Requires --bound-object-kind and --bound-object-name. "+ + "If unset, the UID of the existing object is used.") + + o.Flags = cmd.Flags() + + return cmd +} + +// Complete completes all the required options +func (o *TokenOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { + var err error + + o.Name, err = NameFromCommandArgs(cmd, args) + if err != nil { + return err + } + + o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace() + if err != nil { + return err + } + + client, err := f.KubernetesClientSet() + if err != nil { + return err + } + o.CoreClient = client.CoreV1() + + printer, err := o.PrintFlags.ToPrinter() + if err != nil { + return err + } + + o.PrintObj = func(obj runtime.Object) error { + return printer.PrintObj(obj, o.Out) + } + + return nil +} + +// Validate makes sure provided values for TokenOptions are valid +func (o *TokenOptions) Validate() error { + if o.CoreClient == nil { + return fmt.Errorf("no client provided") + } + if len(o.Name) == 0 { + return fmt.Errorf("service account name is required") + } + if len(o.Namespace) == 0 { + return fmt.Errorf("--namespace is required") + } + if o.Duration < 0 { + return fmt.Errorf("--duration must be greater than or equal to 0") + } + if o.Duration%time.Second != 0 { + return fmt.Errorf("--duration cannot be expressed in units less than seconds") + } + for _, aud := range o.Audiences { + if len(aud) == 0 { + return fmt.Errorf("--audience must not be an empty string") + } + } + + if len(o.BoundObjectKind) == 0 { + if len(o.BoundObjectName) > 0 { + return fmt.Errorf("--bound-object-name can only be set if --bound-object-kind is provided") + } + if len(o.BoundObjectUID) > 0 { + return fmt.Errorf("--bound-object-uid can only be set if --bound-object-kind is provided") + } + } else { + if _, ok := boundObjectKindToAPIVersions()[o.BoundObjectKind]; !ok { + return fmt.Errorf("supported --bound-object-kind values are %s", strings.Join(sets.StringKeySet(boundObjectKindToAPIVersions()).List(), ", ")) + } + if len(o.BoundObjectName) == 0 { + return fmt.Errorf("--bound-object-name is required if --bound-object-kind is provided") + } + } + + return nil +} + +// Run requests a token +func (o *TokenOptions) Run() error { + request := &authenticationv1.TokenRequest{ + Spec: authenticationv1.TokenRequestSpec{ + Audiences: o.Audiences, + }, + } + if o.Duration > 0 { + request.Spec.ExpirationSeconds = pointer.Int64(int64(o.Duration / time.Second)) + } + if len(o.BoundObjectKind) > 0 { + request.Spec.BoundObjectRef = &authenticationv1.BoundObjectReference{ + Kind: o.BoundObjectKind, + APIVersion: boundObjectKindToAPIVersions()[o.BoundObjectKind], + Name: o.BoundObjectName, + UID: types.UID(o.BoundObjectUID), + } + } + + response, err := o.CoreClient.ServiceAccounts(o.Namespace).CreateToken(context.TODO(), o.Name, request, metav1.CreateOptions{}) + if err != nil { + return fmt.Errorf("failed to create token: %v", err) + } + if len(response.Status.Token) == 0 { + return fmt.Errorf("failed to create token: no token in server response") + } + + if o.PrintFlags.OutputFlagSpecified() { + return o.PrintObj(response) + } + + if term.IsTerminal(o.Out) { + // include a newline when printing interactively + fmt.Fprintf(o.Out, "%s\n", response.Status.Token) + } else { + // otherwise just print the token + fmt.Fprintf(o.Out, "%s", response.Status.Token) + } + + return nil +} diff --git a/vendor/k8s.io/kubectl/pkg/cmd/edit/edit.go b/vendor/k8s.io/kubectl/pkg/cmd/edit/edit.go new file mode 100644 index 000000000000..2e9228324a48 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/cmd/edit/edit.go @@ -0,0 +1,108 @@ +/* +Copyright 2015 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 edit + +import ( + "github.com/spf13/cobra" + + "k8s.io/cli-runtime/pkg/genericiooptions" + + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/cmd/util/editor" + "k8s.io/kubectl/pkg/util/completion" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/templates" +) + +var ( + editLong = templates.LongDesc(i18n.T(` + Edit a resource from the default editor. + + The edit command allows you to directly edit any API resource you can retrieve via the + command-line tools. It will open the editor defined by your KUBE_EDITOR, or EDITOR + environment variables, or fall back to 'vi' for Linux or 'notepad' for Windows. + When attempting to open the editor, it will first attempt to use the shell + that has been defined in the 'SHELL' environment variable. If this is not defined, + the default shell will be used, which is '/bin/bash' for Linux or 'cmd' for Windows. + + You can edit multiple objects, although changes are applied one at a time. The command + accepts file names as well as command-line arguments, although the files you point to must + be previously saved versions of resources. + + Editing is done with the API version used to fetch the resource. + To edit using a specific API version, fully-qualify the resource, version, and group. + + The default format is YAML. To edit in JSON, specify "-o json". + + The flag --windows-line-endings can be used to force Windows line endings, + otherwise the default for your operating system will be used. + + In the event an error occurs while updating, a temporary file will be created on disk + that contains your unapplied changes. The most common error when updating a resource + is another editor changing the resource on the server. When this occurs, you will have + to apply your changes to the newer version of the resource, or update your temporary + saved copy to include the latest resource version.`)) + + editExample = templates.Examples(i18n.T(` + # Edit the service named 'registry' + kubectl edit svc/registry + + # Use an alternative editor + KUBE_EDITOR="nano" kubectl edit svc/registry + + # Edit the job 'myjob' in JSON using the v1 API format + kubectl edit job.v1.batch/myjob -o json + + # Edit the deployment 'mydeployment' in YAML and save the modified config in its annotation + kubectl edit deployment/mydeployment -o yaml --save-config + + # Edit the 'status' subresource for the 'mydeployment' deployment + kubectl edit deployment mydeployment --subresource='status'`)) +) + +// NewCmdEdit creates the `edit` command +func NewCmdEdit(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + o := editor.NewEditOptions(editor.NormalEditMode, ioStreams) + cmd := &cobra.Command{ + Use: "edit (RESOURCE/NAME | -f FILENAME)", + DisableFlagsInUseLine: true, + Short: i18n.T("Edit a resource on the server"), + Long: editLong, + Example: editExample, + ValidArgsFunction: completion.ResourceTypeAndNameCompletionFunc(f), + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, args, cmd)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.Run()) + }, + } + + // bind flag structs + o.RecordFlags.AddFlags(cmd) + o.PrintFlags.AddFlags(cmd) + + usage := "to use to edit the resource" + cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage) + cmdutil.AddValidateFlags(cmd) + cmd.Flags().BoolVarP(&o.OutputPatch, "output-patch", "", o.OutputPatch, "Output the patch if the resource is edited.") + cmd.Flags().BoolVar(&o.WindowsLineEndings, "windows-line-endings", o.WindowsLineEndings, + "Defaults to the line ending native to your platform.") + cmdutil.AddFieldManagerFlagVar(cmd, &o.FieldManager, "kubectl-edit") + cmdutil.AddApplyAnnotationVarFlags(cmd, &o.ApplyAnnotation) + cmdutil.AddSubresourceFlags(cmd, &o.Subresource, "If specified, edit will operate on the subresource of the requested object.", editor.SupportedSubresources...) + return cmd +} diff --git a/vendor/k8s.io/kubectl/pkg/cmd/explain/explain.go b/vendor/k8s.io/kubectl/pkg/cmd/explain/explain.go new file mode 100644 index 000000000000..1cde900601b2 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/cmd/explain/explain.go @@ -0,0 +1,234 @@ +/* +Copyright 2014 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 explain + +import ( + "fmt" + + "github.com/spf13/cobra" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/cli-runtime/pkg/genericiooptions" + openapiclient "k8s.io/client-go/openapi" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/explain" + openapiv3explain "k8s.io/kubectl/pkg/explain/v2" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/openapi" + "k8s.io/kubectl/pkg/util/templates" +) + +var ( + explainLong = templates.LongDesc(i18n.T(` + Describe fields and structure of various resources. + + This command describes the fields associated with each supported API resource. + Fields are identified via a simple JSONPath identifier: + + .[.] + + Information about each field is retrieved from the server in OpenAPI format.`)) + + explainExamples = templates.Examples(i18n.T(` + # Get the documentation of the resource and its fields + kubectl explain pods + + # Get all the fields in the resource + kubectl explain pods --recursive + + # Get the explanation for deployment in supported api versions + kubectl explain deployments --api-version=apps/v1 + + # Get the documentation of a specific field of a resource + kubectl explain pods.spec.containers + + # Get the documentation of resources in different format + kubectl explain deployment --output=plaintext-openapiv2`)) + + plaintextTemplateName = "plaintext" + plaintextOpenAPIV2TemplateName = "plaintext-openapiv2" +) + +type ExplainOptions struct { + genericiooptions.IOStreams + + CmdParent string + APIVersion string + Recursive bool + + args []string + + Mapper meta.RESTMapper + openAPIGetter openapi.OpenAPIResourcesGetter + + // Name of the template to use with the openapiv3 template renderer. + OutputFormat string + + // Client capable of fetching openapi documents from the user's cluster + OpenAPIV3Client openapiclient.Client +} + +func NewExplainOptions(parent string, streams genericiooptions.IOStreams) *ExplainOptions { + return &ExplainOptions{ + IOStreams: streams, + CmdParent: parent, + OutputFormat: plaintextTemplateName, + } +} + +// NewCmdExplain returns a cobra command for swagger docs +func NewCmdExplain(parent string, f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { + o := NewExplainOptions(parent, streams) + + cmd := &cobra.Command{ + Use: "explain TYPE [--recursive=FALSE|TRUE] [--api-version=api-version-group] [--output=plaintext|plaintext-openapiv2]", + DisableFlagsInUseLine: true, + Short: i18n.T("Get documentation for a resource"), + Long: explainLong + "\n\n" + cmdutil.SuggestAPIResources(parent), + Example: explainExamples, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.Run()) + }, + } + cmd.Flags().BoolVar(&o.Recursive, "recursive", o.Recursive, "When true, print the name of all the fields recursively. Otherwise, print the available fields with their description.") + cmd.Flags().StringVar(&o.APIVersion, "api-version", o.APIVersion, "Use given api-version (group/version) of the resource.") + + // Only enable --output as a valid flag if the feature is enabled + cmd.Flags().StringVar(&o.OutputFormat, "output", plaintextTemplateName, "Format in which to render the schema. Valid values are: (plaintext, plaintext-openapiv2).") + + return cmd +} + +func (o *ExplainOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { + var err error + o.Mapper, err = f.ToRESTMapper() + if err != nil { + return err + } + + // Only openapi v3 needs the discovery client. + o.OpenAPIV3Client, err = f.OpenAPIV3Client() + if err != nil { + return err + } + + // Lazy-load the OpenAPI V2 Resources, so they're not loaded when using OpenAPI V3. + o.openAPIGetter = f + o.args = args + return nil +} + +func (o *ExplainOptions) Validate() error { + if len(o.args) == 0 { + return fmt.Errorf("You must specify the type of resource to explain. %s\n", cmdutil.SuggestAPIResources(o.CmdParent)) + } + if len(o.args) > 1 { + return fmt.Errorf("We accept only this format: explain RESOURCE\n") + } + + return nil +} + +// Run executes the appropriate steps to print a model's documentation +func (o *ExplainOptions) Run() error { + var fullySpecifiedGVR schema.GroupVersionResource + var fieldsPath []string + var err error + if len(o.APIVersion) == 0 { + fullySpecifiedGVR, fieldsPath, err = explain.SplitAndParseResourceRequestWithMatchingPrefix(o.args[0], o.Mapper) + if err != nil { + return err + } + } else { + // TODO: After we figured out the new syntax to separate group and resource, allow + // the users to use it in explain (kubectl explain ). + // Refer to issue #16039 for why we do this. Refer to PR #15808 that used "/" syntax. + fullySpecifiedGVR, fieldsPath, err = explain.SplitAndParseResourceRequest(o.args[0], o.Mapper) + if err != nil { + return err + } + } + + // Fallback to openapiv2 implementation using special template name + switch o.OutputFormat { + case plaintextOpenAPIV2TemplateName: + return o.renderOpenAPIV2(fullySpecifiedGVR, fieldsPath) + case plaintextTemplateName: + // Check whether the server reponds to OpenAPIV3. + if _, err := o.OpenAPIV3Client.Paths(); err != nil { + // Use v2 renderer if server does not support v3 + return o.renderOpenAPIV2(fullySpecifiedGVR, fieldsPath) + } + + fallthrough + default: + if len(o.APIVersion) > 0 { + apiVersion, err := schema.ParseGroupVersion(o.APIVersion) + if err != nil { + return err + } + fullySpecifiedGVR.Group = apiVersion.Group + fullySpecifiedGVR.Version = apiVersion.Version + } + + return openapiv3explain.PrintModelDescription( + fieldsPath, + o.Out, + o.OpenAPIV3Client, + fullySpecifiedGVR, + o.Recursive, + o.OutputFormat, + ) + } +} + +func (o *ExplainOptions) renderOpenAPIV2( + fullySpecifiedGVR schema.GroupVersionResource, + fieldsPath []string, +) error { + var err error + + gvk, _ := o.Mapper.KindFor(fullySpecifiedGVR) + if gvk.Empty() { + gvk, err = o.Mapper.KindFor(fullySpecifiedGVR.GroupResource().WithVersion("")) + if err != nil { + return err + } + } + + if len(o.APIVersion) != 0 { + apiVersion, err := schema.ParseGroupVersion(o.APIVersion) + if err != nil { + return err + } + gvk = apiVersion.WithKind(gvk.Kind) + } + + resources, err := o.openAPIGetter.OpenAPISchema() + if err != nil { + return err + } + schema := resources.LookupResource(gvk) + if schema == nil { + return fmt.Errorf("couldn't find resource for %q", gvk) + } + + return explain.PrintModelDescription(fieldsPath, o.Out, schema, gvk, o.Recursive) +} diff --git a/vendor/k8s.io/kubectl/pkg/cmd/label/label.go b/vendor/k8s.io/kubectl/pkg/cmd/label/label.go new file mode 100644 index 000000000000..39ef03f0f416 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/cmd/label/label.go @@ -0,0 +1,466 @@ +/* +Copyright 2014 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 label + +import ( + "fmt" + "reflect" + "strings" + + jsonpatch "github.com/evanphx/json-patch" + "github.com/spf13/cobra" + "k8s.io/klog/v2" + + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructuredscheme" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + utilerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/apimachinery/pkg/util/json" + "k8s.io/apimachinery/pkg/util/validation" + + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/genericiooptions" + "k8s.io/cli-runtime/pkg/printers" + "k8s.io/cli-runtime/pkg/resource" + "k8s.io/client-go/tools/clientcmd" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/scheme" + "k8s.io/kubectl/pkg/util/completion" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/templates" +) + +const ( + MsgNotLabeled = "not labeled" + MsgLabeled = "labeled" + MsgUnLabeled = "unlabeled" +) + +// LabelOptions have the data required to perform the label operation +type LabelOptions struct { + // Filename options + resource.FilenameOptions + RecordFlags *genericclioptions.RecordFlags + + PrintFlags *genericclioptions.PrintFlags + ToPrinter func(string) (printers.ResourcePrinter, error) + + // Common user flags + overwrite bool + list bool + local bool + dryRunStrategy cmdutil.DryRunStrategy + all bool + allNamespaces bool + resourceVersion string + selector string + fieldSelector string + outputFormat string + fieldManager string + + // results of arg parsing + resources []string + newLabels map[string]string + removeLabels []string + + Recorder genericclioptions.Recorder + + namespace string + enforceNamespace bool + builder *resource.Builder + unstructuredClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error) + + // Common shared fields + genericiooptions.IOStreams +} + +var ( + labelLong = templates.LongDesc(i18n.T(` + Update the labels on a resource. + + * A label key and value must begin with a letter or number, and may contain letters, numbers, hyphens, dots, and underscores, up to %[1]d characters each. + * Optionally, the key can begin with a DNS subdomain prefix and a single '/', like example.com/my-app. + * If --overwrite is true, then existing labels can be overwritten, otherwise attempting to overwrite a label will result in an error. + * If --resource-version is specified, then updates will use this resource version, otherwise the existing resource-version will be used.`)) + + labelExample = templates.Examples(i18n.T(` + # Update pod 'foo' with the label 'unhealthy' and the value 'true' + kubectl label pods foo unhealthy=true + + # Update pod 'foo' with the label 'status' and the value 'unhealthy', overwriting any existing value + kubectl label --overwrite pods foo status=unhealthy + + # Update all pods in the namespace + kubectl label pods --all status=unhealthy + + # Update a pod identified by the type and name in "pod.json" + kubectl label -f pod.json status=unhealthy + + # Update pod 'foo' only if the resource is unchanged from version 1 + kubectl label pods foo status=unhealthy --resource-version=1 + + # Update pod 'foo' by removing a label named 'bar' if it exists + # Does not require the --overwrite flag + kubectl label pods foo bar-`)) +) + +func NewLabelOptions(ioStreams genericiooptions.IOStreams) *LabelOptions { + return &LabelOptions{ + RecordFlags: genericclioptions.NewRecordFlags(), + Recorder: genericclioptions.NoopRecorder{}, + + PrintFlags: genericclioptions.NewPrintFlags("labeled").WithTypeSetter(scheme.Scheme), + + IOStreams: ioStreams, + } +} + +func NewCmdLabel(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command { + o := NewLabelOptions(ioStreams) + + cmd := &cobra.Command{ + Use: "label [--overwrite] (-f FILENAME | TYPE NAME) KEY_1=VAL_1 ... KEY_N=VAL_N [--resource-version=version]", + DisableFlagsInUseLine: true, + Short: i18n.T("Update the labels on a resource"), + Long: fmt.Sprintf(labelLong, validation.LabelValueMaxLength), + Example: labelExample, + ValidArgsFunction: completion.ResourceTypeAndNameCompletionFunc(f), + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.RunLabel()) + }, + } + + o.RecordFlags.AddFlags(cmd) + o.PrintFlags.AddFlags(cmd) + + cmd.Flags().BoolVar(&o.overwrite, "overwrite", o.overwrite, "If true, allow labels to be overwritten, otherwise reject label updates that overwrite existing labels.") + cmd.Flags().BoolVar(&o.list, "list", o.list, "If true, display the labels for a given resource.") + cmd.Flags().BoolVar(&o.local, "local", o.local, "If true, label will NOT contact api-server but run locally.") + cmd.Flags().StringVar(&o.fieldSelector, "field-selector", o.fieldSelector, "Selector (field query) to filter on, supports '=', '==', and '!='.(e.g. --field-selector key1=value1,key2=value2). The server only supports a limited number of field queries per type.") + cmd.Flags().BoolVar(&o.all, "all", o.all, "Select all resources, in the namespace of the specified resource types") + cmd.Flags().BoolVarP(&o.allNamespaces, "all-namespaces", "A", o.allNamespaces, "If true, check the specified action in all namespaces.") + cmd.Flags().StringVar(&o.resourceVersion, "resource-version", o.resourceVersion, i18n.T("If non-empty, the labels update will only succeed if this is the current resource-version for the object. Only valid when specifying a single resource.")) + usage := "identifying the resource to update the labels" + cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage) + cmdutil.AddDryRunFlag(cmd) + cmdutil.AddFieldManagerFlagVar(cmd, &o.fieldManager, "kubectl-label") + cmdutil.AddLabelSelectorFlagVar(cmd, &o.selector) + + return cmd +} + +// Complete adapts from the command line args and factory to the data required. +func (o *LabelOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { + var err error + + o.RecordFlags.Complete(cmd) + o.Recorder, err = o.RecordFlags.ToRecorder() + if err != nil { + return err + } + + o.outputFormat = cmdutil.GetFlagString(cmd, "output") + o.dryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd) + if err != nil { + return err + } + + o.ToPrinter = func(operation string) (printers.ResourcePrinter, error) { + o.PrintFlags.NamePrintFlags.Operation = operation + // PrintFlagsWithDryRunStrategy must be done after NamePrintFlags.Operation is set + cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.dryRunStrategy) + return o.PrintFlags.ToPrinter() + } + + resources, labelArgs, err := cmdutil.GetResourcesAndPairs(args, "label") + if err != nil { + return err + } + o.resources = resources + o.newLabels, o.removeLabels, err = parseLabels(labelArgs) + if err != nil { + return err + } + + if o.list && len(o.outputFormat) > 0 { + return fmt.Errorf("--list and --output may not be specified together") + } + + o.namespace, o.enforceNamespace, err = f.ToRawKubeConfigLoader().Namespace() + if err != nil && !(o.local && clientcmd.IsEmptyConfig(err)) { + return err + } + o.builder = f.NewBuilder() + o.unstructuredClientForMapping = f.UnstructuredClientForMapping + + return nil +} + +// Validate checks to the LabelOptions to see if there is sufficient information run the command. +func (o *LabelOptions) Validate() error { + if o.all && len(o.selector) > 0 { + return fmt.Errorf("cannot set --all and --selector at the same time") + } + if o.all && len(o.fieldSelector) > 0 { + return fmt.Errorf("cannot set --all and --field-selector at the same time") + } + if o.local { + if o.dryRunStrategy == cmdutil.DryRunServer { + return fmt.Errorf("cannot specify --local and --dry-run=server - did you mean --dry-run=client?") + } + if len(o.resources) > 0 { + return fmt.Errorf("can only use local files by -f pod.yaml or --filename=pod.json when --local=true is set") + } + if cmdutil.IsFilenameSliceEmpty(o.FilenameOptions.Filenames, o.FilenameOptions.Kustomize) { + return fmt.Errorf("one or more files must be specified as -f pod.yaml or --filename=pod.json") + } + } else { + if len(o.resources) < 1 && cmdutil.IsFilenameSliceEmpty(o.FilenameOptions.Filenames, o.FilenameOptions.Kustomize) { + return fmt.Errorf("one or more resources must be specified as or /") + } + } + if len(o.newLabels) < 1 && len(o.removeLabels) < 1 && !o.list { + return fmt.Errorf("at least one label update is required") + } + return nil +} + +// RunLabel does the work +func (o *LabelOptions) RunLabel() error { + b := o.builder. + Unstructured(). + LocalParam(o.local). + ContinueOnError(). + NamespaceParam(o.namespace).DefaultNamespace(). + FilenameParam(o.enforceNamespace, &o.FilenameOptions). + Flatten() + + if !o.local { + b = b.LabelSelectorParam(o.selector). + FieldSelectorParam(o.fieldSelector). + AllNamespaces(o.allNamespaces). + ResourceTypeOrNameArgs(o.all, o.resources...). + Latest() + } + + one := false + r := b.Do().IntoSingleItemImplied(&one) + if err := r.Err(); err != nil { + return err + } + + // only apply resource version locking on a single resource + if !one && len(o.resourceVersion) > 0 { + return fmt.Errorf("--resource-version may only be used with a single resource") + } + + // TODO: support bulk generic output a la Get + return r.Visit(func(info *resource.Info, err error) error { + if err != nil { + return err + } + + var outputObj runtime.Object + var dataChangeMsg string + obj := info.Object + + if len(o.resourceVersion) != 0 { + // ensure resourceVersion is always sent in the patch by clearing it from the starting JSON + accessor, err := meta.Accessor(obj) + if err != nil { + return err + } + accessor.SetResourceVersion("") + } + + oldData, err := json.Marshal(obj) + if err != nil { + return err + } + if o.dryRunStrategy == cmdutil.DryRunClient || o.local || o.list { + err = labelFunc(obj, o.overwrite, o.resourceVersion, o.newLabels, o.removeLabels) + if err != nil { + return err + } + newObj, err := json.Marshal(obj) + if err != nil { + return err + } + dataChangeMsg = updateDataChangeMsg(oldData, newObj, o.overwrite) + outputObj = info.Object + } else { + name, namespace := info.Name, info.Namespace + if err != nil { + return err + } + accessor, err := meta.Accessor(obj) + if err != nil { + return err + } + for _, label := range o.removeLabels { + if _, ok := accessor.GetLabels()[label]; !ok { + fmt.Fprintf(o.Out, "label %q not found.\n", label) + } + } + + if err := labelFunc(obj, o.overwrite, o.resourceVersion, o.newLabels, o.removeLabels); err != nil { + return err + } + if err := o.Recorder.Record(obj); err != nil { + klog.V(4).Infof("error recording current command: %v", err) + } + newObj, err := json.Marshal(obj) + if err != nil { + return err + } + dataChangeMsg = updateDataChangeMsg(oldData, newObj, o.overwrite) + patchBytes, err := jsonpatch.CreateMergePatch(oldData, newObj) + createdPatch := err == nil + if err != nil { + klog.V(2).Infof("couldn't compute patch: %v", err) + } + + mapping := info.ResourceMapping() + client, err := o.unstructuredClientForMapping(mapping) + if err != nil { + return err + } + helper := resource.NewHelper(client, mapping). + DryRun(o.dryRunStrategy == cmdutil.DryRunServer). + WithFieldManager(o.fieldManager) + + if createdPatch { + outputObj, err = helper.Patch(namespace, name, types.MergePatchType, patchBytes, nil) + } else { + outputObj, err = helper.Replace(namespace, name, false, obj) + } + if err != nil { + return err + } + } + + if o.list { + accessor, err := meta.Accessor(outputObj) + if err != nil { + return err + } + + indent := "" + if !one { + indent = " " + gvks, _, err := unstructuredscheme.NewUnstructuredObjectTyper().ObjectKinds(info.Object) + if err != nil { + return err + } + fmt.Fprintf(o.Out, "Listing labels for %s.%s/%s:\n", gvks[0].Kind, gvks[0].Group, info.Name) + } + for k, v := range accessor.GetLabels() { + fmt.Fprintf(o.Out, "%s%s=%s\n", indent, k, v) + } + + return nil + } + + printer, err := o.ToPrinter(dataChangeMsg) + if err != nil { + return err + } + return printer.PrintObj(info.Object, o.Out) + }) +} + +func updateDataChangeMsg(oldObj []byte, newObj []byte, overwrite bool) string { + msg := MsgNotLabeled + if !reflect.DeepEqual(oldObj, newObj) { + msg = MsgLabeled + if !overwrite && len(newObj) < len(oldObj) { + msg = MsgUnLabeled + } + } + return msg +} + +func validateNoOverwrites(accessor metav1.Object, labels map[string]string) error { + allErrs := []error{} + for key, value := range labels { + if currValue, found := accessor.GetLabels()[key]; found && currValue != value { + allErrs = append(allErrs, fmt.Errorf("'%s' already has a value (%s), and --overwrite is false", key, currValue)) + } + } + return utilerrors.NewAggregate(allErrs) +} + +func parseLabels(spec []string) (map[string]string, []string, error) { + labels := map[string]string{} + var remove []string + for _, labelSpec := range spec { + if strings.Contains(labelSpec, "=") { + parts := strings.Split(labelSpec, "=") + if len(parts) != 2 { + return nil, nil, fmt.Errorf("invalid label spec: %v", labelSpec) + } + if errs := validation.IsValidLabelValue(parts[1]); len(errs) != 0 { + return nil, nil, fmt.Errorf("invalid label value: %q: %s", labelSpec, strings.Join(errs, ";")) + } + labels[parts[0]] = parts[1] + } else if strings.HasSuffix(labelSpec, "-") { + remove = append(remove, labelSpec[:len(labelSpec)-1]) + } else { + return nil, nil, fmt.Errorf("unknown label spec: %v", labelSpec) + } + } + for _, removeLabel := range remove { + if _, found := labels[removeLabel]; found { + return nil, nil, fmt.Errorf("can not both modify and remove a label in the same command") + } + } + return labels, remove, nil +} + +func labelFunc(obj runtime.Object, overwrite bool, resourceVersion string, labels map[string]string, remove []string) error { + accessor, err := meta.Accessor(obj) + if err != nil { + return err + } + if !overwrite { + if err := validateNoOverwrites(accessor, labels); err != nil { + return err + } + } + + objLabels := accessor.GetLabels() + if objLabels == nil { + objLabels = make(map[string]string) + } + + for key, value := range labels { + objLabels[key] = value + } + for _, label := range remove { + delete(objLabels, label) + } + accessor.SetLabels(objLabels) + + if len(resourceVersion) != 0 { + accessor.SetResourceVersion(resourceVersion) + } + return nil +} diff --git a/vendor/k8s.io/kubectl/pkg/explain/OWNERS b/vendor/k8s.io/kubectl/pkg/explain/OWNERS new file mode 100644 index 000000000000..cb873612b13e --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/explain/OWNERS @@ -0,0 +1,6 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +approvers: + - apelisse +reviewers: + - apelisse diff --git a/vendor/k8s.io/kubectl/pkg/explain/explain.go b/vendor/k8s.io/kubectl/pkg/explain/explain.go new file mode 100644 index 000000000000..ccc7b3a9abc7 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/explain/explain.go @@ -0,0 +1,168 @@ +/* +Copyright 2017 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 explain + +import ( + "fmt" + "io" + "strings" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/util/jsonpath" + "k8s.io/kube-openapi/pkg/util/proto" +) + +type fieldsPrinter interface { + PrintFields(proto.Schema) error +} + +// jsonPathParse gets back the inner list of nodes we want to work with +func jsonPathParse(in string) ([]jsonpath.Node, error) { + // Remove trailing period just in case + in = strings.TrimSuffix(in, ".") + + // Define initial jsonpath Parser + jpp, err := jsonpath.Parse("user", "{."+in+"}") + if err != nil { + return nil, err + } + + // Because of the way the jsonpath library works, the schema of the parser is [][]NodeList + // meaning we need to get the outer node list, make sure it's only length 1, then get the inner node + // list, and only then can we look at the individual nodes themselves. + outerNodeList := jpp.Root.Nodes + if len(outerNodeList) != 1 { + return nil, fmt.Errorf("must pass in 1 jsonpath string") + } + + // The root node is always a list node so this type assertion is safe + return outerNodeList[0].(*jsonpath.ListNode).Nodes, nil +} + +// SplitAndParseResourceRequest separates the users input into a model and fields +func SplitAndParseResourceRequest(inResource string, mapper meta.RESTMapper) (schema.GroupVersionResource, []string, error) { + inResourceNodeList, err := jsonPathParse(inResource) + if err != nil { + return schema.GroupVersionResource{}, nil, err + } + + if inResourceNodeList[0].Type() != jsonpath.NodeField { + return schema.GroupVersionResource{}, nil, fmt.Errorf("invalid jsonpath syntax, first node must be field node") + } + resource := inResourceNodeList[0].(*jsonpath.FieldNode).Value + gvr, err := mapper.ResourceFor(schema.GroupVersionResource{Resource: resource}) + if err != nil { + return schema.GroupVersionResource{}, nil, err + } + + var fieldsPath []string + for _, node := range inResourceNodeList[1:] { + if node.Type() != jsonpath.NodeField { + return schema.GroupVersionResource{}, nil, fmt.Errorf("invalid jsonpath syntax, all nodes must be field nodes") + } + fieldsPath = append(fieldsPath, node.(*jsonpath.FieldNode).Value) + } + + return gvr, fieldsPath, nil +} + +// SplitAndParseResourceRequestWithMatchingPrefix separates the users input into a model and fields +// while selecting gvr whose (resource, group) prefix matches the resource +func SplitAndParseResourceRequestWithMatchingPrefix(inResource string, mapper meta.RESTMapper) (gvr schema.GroupVersionResource, fieldsPath []string, err error) { + inResourceNodeList, err := jsonPathParse(inResource) + if err != nil { + return schema.GroupVersionResource{}, nil, err + } + + // Get resource from first node of jsonpath + if inResourceNodeList[0].Type() != jsonpath.NodeField { + return schema.GroupVersionResource{}, nil, fmt.Errorf("invalid jsonpath syntax, first node must be field node") + } + resource := inResourceNodeList[0].(*jsonpath.FieldNode).Value + + gvrs, err := mapper.ResourcesFor(schema.GroupVersionResource{Resource: resource}) + if err != nil { + return schema.GroupVersionResource{}, nil, err + } + + for _, gvrItem := range gvrs { + // Find first gvr whose gr prefixes requested resource + groupResource := gvrItem.GroupResource().String() + if strings.HasPrefix(inResource, groupResource) { + resourceSuffix := inResource[len(groupResource):] + var fieldsPath []string + if len(resourceSuffix) > 0 { + // Define another jsonpath Parser for the resource suffix + resourceSuffixNodeList, err := jsonPathParse(resourceSuffix) + if err != nil { + return schema.GroupVersionResource{}, nil, err + } + + if len(resourceSuffixNodeList) > 0 { + nodeList := resourceSuffixNodeList[1:] + for _, node := range nodeList { + if node.Type() != jsonpath.NodeField { + return schema.GroupVersionResource{}, nil, fmt.Errorf("invalid jsonpath syntax, first node must be field node") + } + fieldsPath = append(fieldsPath, node.(*jsonpath.FieldNode).Value) + } + } + } + return gvrItem, fieldsPath, nil + } + } + + // If no match, take the first (the highest priority) gvr + fieldsPath = []string{} + if len(gvrs) > 0 { + gvr = gvrs[0] + + fieldsPathNodeList, err := jsonPathParse(inResource) + if err != nil { + return schema.GroupVersionResource{}, nil, err + } + + for _, node := range fieldsPathNodeList[1:] { + if node.Type() != jsonpath.NodeField { + return schema.GroupVersionResource{}, nil, fmt.Errorf("invalid jsonpath syntax, first node must be field node") + } + fieldsPath = append(fieldsPath, node.(*jsonpath.FieldNode).Value) + } + } + + return gvr, fieldsPath, nil +} + +// PrintModelDescription prints the description of a specific model or dot path. +// If recursive, all components nested within the fields of the schema will be +// printed. +func PrintModelDescription(fieldsPath []string, w io.Writer, schema proto.Schema, gvk schema.GroupVersionKind, recursive bool) error { + fieldName := "" + if len(fieldsPath) != 0 { + fieldName = fieldsPath[len(fieldsPath)-1] + } + + // Go down the fieldsPath to find what we're trying to explain + schema, err := LookupSchemaForField(schema, fieldsPath) + if err != nil { + return err + } + b := fieldsPrinterBuilder{Recursive: recursive} + f := &Formatter{Writer: w, Wrap: 80} + return PrintModel(fieldName, f, b, schema, gvk) +} diff --git a/vendor/k8s.io/kubectl/pkg/explain/field_lookup.go b/vendor/k8s.io/kubectl/pkg/explain/field_lookup.go new file mode 100644 index 000000000000..9f96c507269d --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/explain/field_lookup.go @@ -0,0 +1,111 @@ +/* +Copyright 2017 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 explain + +import ( + "fmt" + + "k8s.io/kube-openapi/pkg/util/proto" +) + +// fieldLookup walks through a schema by following a path, and returns +// the final schema. +type fieldLookup struct { + // Path to walk + Path []string + + // Return information: Schema found, or error. + Schema proto.Schema + Error error +} + +// SaveLeafSchema is used to detect if we are done walking the path, and +// saves the schema as a match. +func (f *fieldLookup) SaveLeafSchema(schema proto.Schema) bool { + if len(f.Path) != 0 { + return false + } + + f.Schema = schema + + return true +} + +// VisitArray is mostly a passthrough. +func (f *fieldLookup) VisitArray(a *proto.Array) { + if f.SaveLeafSchema(a) { + return + } + + // Passthrough arrays. + a.SubType.Accept(f) +} + +// VisitMap is mostly a passthrough. +func (f *fieldLookup) VisitMap(m *proto.Map) { + if f.SaveLeafSchema(m) { + return + } + + // Passthrough maps. + m.SubType.Accept(f) +} + +// VisitPrimitive stops the operation and returns itself as the found +// schema, even if it had more path to walk. +func (f *fieldLookup) VisitPrimitive(p *proto.Primitive) { + // Even if Path is not empty (we're not expecting a leaf), + // return that primitive. + f.Schema = p +} + +// VisitKind unstacks fields as it finds them. +func (f *fieldLookup) VisitKind(k *proto.Kind) { + if f.SaveLeafSchema(k) { + return + } + + subSchema, ok := k.Fields[f.Path[0]] + if !ok { + f.Error = fmt.Errorf("field %q does not exist", f.Path[0]) + return + } + + f.Path = f.Path[1:] + subSchema.Accept(f) +} + +func (f *fieldLookup) VisitArbitrary(a *proto.Arbitrary) { + f.Schema = a +} + +// VisitReference is mostly a passthrough. +func (f *fieldLookup) VisitReference(r proto.Reference) { + if f.SaveLeafSchema(r) { + return + } + + // Passthrough references. + r.SubSchema().Accept(f) +} + +// LookupSchemaForField looks for the schema of a given path in a base schema. +func LookupSchemaForField(schema proto.Schema, path []string) (proto.Schema, error) { + f := &fieldLookup{Path: path} + schema.Accept(f) + return f.Schema, f.Error +} diff --git a/vendor/k8s.io/kubectl/pkg/explain/fields_printer.go b/vendor/k8s.io/kubectl/pkg/explain/fields_printer.go new file mode 100644 index 000000000000..bb25241a4527 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/explain/fields_printer.go @@ -0,0 +1,82 @@ +/* +Copyright 2017 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 explain + +import "k8s.io/kube-openapi/pkg/util/proto" + +// indentDesc is the level of indentation for descriptions. +const indentDesc = 2 + +// regularFieldsPrinter prints fields with their type and description. +type regularFieldsPrinter struct { + Writer *Formatter + Error error +} + +var _ proto.SchemaVisitor = ®ularFieldsPrinter{} +var _ fieldsPrinter = ®ularFieldsPrinter{} + +// VisitArray prints a Array type. It is just a passthrough. +func (f *regularFieldsPrinter) VisitArray(a *proto.Array) { + a.SubType.Accept(f) +} + +// VisitKind prints a Kind type. It prints each key in the kind, with +// the type, the required flag, and the description. +func (f *regularFieldsPrinter) VisitKind(k *proto.Kind) { + for _, key := range k.Keys() { + v := k.Fields[key] + required := "" + if k.IsRequired(key) { + required = " -required-" + } + + if err := f.Writer.Write("%s\t<%s>%s", key, GetTypeName(v), required); err != nil { + f.Error = err + return + } + if err := f.Writer.Indent(indentDesc).WriteWrapped("%s", v.GetDescription()); err != nil { + f.Error = err + return + } + if err := f.Writer.Write(""); err != nil { + f.Error = err + return + } + } +} + +// VisitMap prints a Map type. It is just a passthrough. +func (f *regularFieldsPrinter) VisitMap(m *proto.Map) { + m.SubType.Accept(f) +} + +// VisitPrimitive prints a Primitive type. It stops the recursion. +func (f *regularFieldsPrinter) VisitPrimitive(p *proto.Primitive) { + // Nothing to do. Shouldn't really happen. +} + +// VisitReference prints a Reference type. It is just a passthrough. +func (f *regularFieldsPrinter) VisitReference(r proto.Reference) { + r.SubSchema().Accept(f) +} + +// PrintFields will write the types from schema. +func (f *regularFieldsPrinter) PrintFields(schema proto.Schema) error { + schema.Accept(f) + return f.Error +} diff --git a/vendor/k8s.io/kubectl/pkg/explain/fields_printer_builder.go b/vendor/k8s.io/kubectl/pkg/explain/fields_printer_builder.go new file mode 100644 index 000000000000..8a2fc045eba7 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/explain/fields_printer_builder.go @@ -0,0 +1,36 @@ +/* +Copyright 2017 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 explain + +// fieldsPrinterBuilder builds either a regularFieldsPrinter or a +// recursiveFieldsPrinter based on the argument. +type fieldsPrinterBuilder struct { + Recursive bool +} + +// BuildFieldsPrinter builds the appropriate fieldsPrinter. +func (f fieldsPrinterBuilder) BuildFieldsPrinter(writer *Formatter) fieldsPrinter { + if f.Recursive { + return &recursiveFieldsPrinter{ + Writer: writer, + } + } + + return ®ularFieldsPrinter{ + Writer: writer, + } +} diff --git a/vendor/k8s.io/kubectl/pkg/explain/formatter.go b/vendor/k8s.io/kubectl/pkg/explain/formatter.go new file mode 100644 index 000000000000..9f94f1206f4c --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/explain/formatter.go @@ -0,0 +1,178 @@ +/* +Copyright 2017 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 explain + +import ( + "fmt" + "io" + "regexp" + "strings" +) + +// Formatter helps you write with indentation, and can wrap text as needed. +type Formatter struct { + IndentLevel int + Wrap int + Writer io.Writer +} + +// Indent creates a new Formatter that will indent the code by that much more. +func (f Formatter) Indent(indent int) *Formatter { + f.IndentLevel = f.IndentLevel + indent + return &f +} + +// Write writes a string with the indentation set for the +// Formatter. This is not wrapping text. +func (f *Formatter) Write(str string, a ...interface{}) error { + // Don't indent empty lines + if str == "" { + _, err := io.WriteString(f.Writer, "\n") + return err + } + + indent := "" + for i := 0; i < f.IndentLevel; i++ { + indent = indent + " " + } + + if len(a) > 0 { + str = fmt.Sprintf(str, a...) + } + _, err := io.WriteString(f.Writer, indent+str+"\n") + return err +} + +// WriteWrapped writes a string with the indentation set for the +// Formatter, and wraps as needed. +func (f *Formatter) WriteWrapped(str string, a ...interface{}) error { + if f.Wrap == 0 { + return f.Write(str, a...) + } + text := fmt.Sprintf(str, a...) + strs := wrapString(text, f.Wrap-f.IndentLevel) + for _, substr := range strs { + if err := f.Write(substr); err != nil { + return err + } + } + return nil +} + +type line struct { + wrap int + words []string +} + +func (l *line) String() string { + return strings.Join(l.words, " ") +} + +func (l *line) Empty() bool { + return len(l.words) == 0 +} + +func (l *line) Len() int { + return len(l.String()) +} + +// Add adds the word to the line, returns true if we could, false if we +// didn't have enough room. It's always possible to add to an empty line. +func (l *line) Add(word string) bool { + newLine := line{ + wrap: l.wrap, + words: append(l.words, word), + } + if newLine.Len() <= l.wrap || len(l.words) == 0 { + l.words = newLine.words + return true + } + return false +} + +var bullet = regexp.MustCompile(`^(\d+\.?|-|\*)\s`) + +func shouldStartNewLine(lastWord, str string) bool { + // preserve line breaks ending in : + if strings.HasSuffix(lastWord, ":") { + return true + } + + // preserve code blocks + if strings.HasPrefix(str, " ") { + return true + } + str = strings.TrimSpace(str) + // preserve empty lines + if len(str) == 0 { + return true + } + // preserve lines that look like they're starting lists + if bullet.MatchString(str) { + return true + } + // otherwise combine + return false +} + +func wrapString(str string, wrap int) []string { + wrapped := []string{} + l := line{wrap: wrap} + // track the last word added to the current line + lastWord := "" + flush := func() { + if !l.Empty() { + lastWord = "" + wrapped = append(wrapped, l.String()) + l = line{wrap: wrap} + } + } + + // iterate over the lines in the original description + for _, str := range strings.Split(str, "\n") { + // preserve code blocks and blockquotes as-is + if strings.HasPrefix(str, " ") { + flush() + wrapped = append(wrapped, str) + continue + } + + // preserve empty lines after the first line, since they can separate logical sections + if len(wrapped) > 0 && len(strings.TrimSpace(str)) == 0 { + flush() + wrapped = append(wrapped, "") + continue + } + + // flush if we should start a new line + if shouldStartNewLine(lastWord, str) { + flush() + } + words := strings.Fields(str) + for _, word := range words { + lastWord = word + if !l.Add(word) { + flush() + if !l.Add(word) { + panic("Couldn't add to empty line.") + } + } + } + } + flush() + return wrapped +} diff --git a/vendor/k8s.io/kubectl/pkg/explain/model_printer.go b/vendor/k8s.io/kubectl/pkg/explain/model_printer.go new file mode 100644 index 000000000000..8bd145dd20a6 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/explain/model_printer.go @@ -0,0 +1,163 @@ +/* +Copyright 2017 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 explain + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/kube-openapi/pkg/util/proto" +) + +const ( + // fieldIndentLevel is the level of indentation for fields. + fieldIndentLevel = 3 + // descriptionIndentLevel is the level of indentation for the + // description. + descriptionIndentLevel = 5 +) + +// modelPrinter prints a schema in Writer. Its "Builder" will decide if +// it's recursive or not. +type modelPrinter struct { + Name string + Type string + Descriptions []string + Writer *Formatter + Builder fieldsPrinterBuilder + GVK schema.GroupVersionKind + Error error +} + +var _ proto.SchemaVisitor = &modelPrinter{} + +func (m *modelPrinter) PrintKindAndVersion() error { + if err := m.Writer.Write("KIND: %s", m.GVK.Kind); err != nil { + return err + } + return m.Writer.Write("VERSION: %s\n", m.GVK.GroupVersion()) +} + +// PrintDescription prints the description for a given schema. There +// might be multiple description, since we collect descriptions when we +// go through references, arrays and maps. +func (m *modelPrinter) PrintDescription(schema proto.Schema) error { + if err := m.Writer.Write("DESCRIPTION:"); err != nil { + return err + } + empty := true + for i, desc := range append(m.Descriptions, schema.GetDescription()) { + if desc == "" { + continue + } + empty = false + if i != 0 { + if err := m.Writer.Write(""); err != nil { + return err + } + } + if err := m.Writer.Indent(descriptionIndentLevel).WriteWrapped("%s", desc); err != nil { + return err + } + } + if empty { + return m.Writer.Indent(descriptionIndentLevel).WriteWrapped("") + } + return nil +} + +// VisitArray recurses inside the subtype, while collecting the type if +// not done yet, and the description. +func (m *modelPrinter) VisitArray(a *proto.Array) { + m.Descriptions = append(m.Descriptions, a.GetDescription()) + if m.Type == "" { + m.Type = GetTypeName(a) + } + a.SubType.Accept(m) +} + +// VisitKind prints a full resource with its fields. +func (m *modelPrinter) VisitKind(k *proto.Kind) { + if err := m.PrintKindAndVersion(); err != nil { + m.Error = err + return + } + + if m.Type == "" { + m.Type = GetTypeName(k) + } + if m.Name != "" { + m.Writer.Write("RESOURCE: %s <%s>\n", m.Name, m.Type) + } + + if err := m.PrintDescription(k); err != nil { + m.Error = err + return + } + if err := m.Writer.Write("\nFIELDS:"); err != nil { + m.Error = err + return + } + m.Error = m.Builder.BuildFieldsPrinter(m.Writer.Indent(fieldIndentLevel)).PrintFields(k) +} + +// VisitMap recurses inside the subtype, while collecting the type if +// not done yet, and the description. +func (m *modelPrinter) VisitMap(om *proto.Map) { + m.Descriptions = append(m.Descriptions, om.GetDescription()) + if m.Type == "" { + m.Type = GetTypeName(om) + } + om.SubType.Accept(m) +} + +// VisitPrimitive prints a field type and its description. +func (m *modelPrinter) VisitPrimitive(p *proto.Primitive) { + if err := m.PrintKindAndVersion(); err != nil { + m.Error = err + return + } + + if m.Type == "" { + m.Type = GetTypeName(p) + } + if err := m.Writer.Write("FIELD: %s <%s>\n", m.Name, m.Type); err != nil { + m.Error = err + return + } + m.Error = m.PrintDescription(p) +} + +func (m *modelPrinter) VisitArbitrary(a *proto.Arbitrary) { + if err := m.PrintKindAndVersion(); err != nil { + m.Error = err + return + } + + m.Error = m.PrintDescription(a) +} + +// VisitReference recurses inside the subtype, while collecting the description. +func (m *modelPrinter) VisitReference(r proto.Reference) { + m.Descriptions = append(m.Descriptions, r.GetDescription()) + r.SubSchema().Accept(m) +} + +// PrintModel prints the description of a schema in writer. +func PrintModel(name string, writer *Formatter, builder fieldsPrinterBuilder, schema proto.Schema, gvk schema.GroupVersionKind) error { + m := &modelPrinter{Name: name, Writer: writer, Builder: builder, GVK: gvk} + schema.Accept(m) + return m.Error +} diff --git a/vendor/k8s.io/kubectl/pkg/explain/recursive_fields_printer.go b/vendor/k8s.io/kubectl/pkg/explain/recursive_fields_printer.go new file mode 100644 index 000000000000..6429a73264eb --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/explain/recursive_fields_printer.go @@ -0,0 +1,81 @@ +/* +Copyright 2017 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 explain + +import "k8s.io/kube-openapi/pkg/util/proto" + +// indentPerLevel is the level of indentation for each field recursion. +const indentPerLevel = 3 + +// recursiveFieldsPrinter recursively prints all the fields for a given +// schema. +type recursiveFieldsPrinter struct { + Writer *Formatter + Error error +} + +var _ proto.SchemaVisitor = &recursiveFieldsPrinter{} +var _ fieldsPrinter = &recursiveFieldsPrinter{} +var visitedReferences = map[string]struct{}{} + +// VisitArray is just a passthrough. +func (f *recursiveFieldsPrinter) VisitArray(a *proto.Array) { + a.SubType.Accept(f) +} + +// VisitKind prints all its fields with their type, and then recurses +// inside each of these (pre-order). +func (f *recursiveFieldsPrinter) VisitKind(k *proto.Kind) { + for _, key := range k.Keys() { + v := k.Fields[key] + f.Writer.Write("%s\t<%s>", key, GetTypeName(v)) + subFields := &recursiveFieldsPrinter{ + Writer: f.Writer.Indent(indentPerLevel), + } + if err := subFields.PrintFields(v); err != nil { + f.Error = err + return + } + } +} + +// VisitMap is just a passthrough. +func (f *recursiveFieldsPrinter) VisitMap(m *proto.Map) { + m.SubType.Accept(f) +} + +// VisitPrimitive does nothing, since it doesn't have sub-fields. +func (f *recursiveFieldsPrinter) VisitPrimitive(p *proto.Primitive) { + // Nothing to do. +} + +// VisitReference is just a passthrough. +func (f *recursiveFieldsPrinter) VisitReference(r proto.Reference) { + if _, ok := visitedReferences[r.Reference()]; ok { + return + } + visitedReferences[r.Reference()] = struct{}{} + r.SubSchema().Accept(f) + delete(visitedReferences, r.Reference()) +} + +// PrintFields will recursively print all the fields for the given +// schema. +func (f *recursiveFieldsPrinter) PrintFields(schema proto.Schema) error { + schema.Accept(f) + return f.Error +} diff --git a/vendor/k8s.io/kubectl/pkg/explain/test-recursive-swagger.json b/vendor/k8s.io/kubectl/pkg/explain/test-recursive-swagger.json new file mode 100644 index 000000000000..1ae79855d393 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/explain/test-recursive-swagger.json @@ -0,0 +1,63 @@ +{ + "swagger": "2.0", + "info": { + "title": "Kubernetes", + "version": "v1.9.0" + }, + "paths": {}, + "definitions": { + "OneKind": { + "description": "OneKind has a short description", + "required": [ + "field1" + ], + "properties": { + "field1": { + "description": "This is first reference field", + "$ref": "#/definitions/ReferenceKind" + }, + "field2": { + "description": "This is other kind field with string and reference", + "$ref": "#/definitions/OtherKind" + } + }, + "x-kubernetes-group-version-kind": [ + { + "group": "", + "kind": "OneKind", + "version": "v2" + } + ] + }, + "ReferenceKind": { + "description": "This is reference Kind", + "properties": { + "referencefield": { + "description": "This is reference to itself.", + "$ref": "#/definitions/ReferenceKind" + }, + "referencesarray": { + "description": "This is an array of references", + "type": "array", + "items": { + "description": "This is reference object", + "$ref": "#/definitions/ReferenceKind" + } + } + } + }, + "OtherKind": { + "description": "This is other kind with string and reference fields", + "properties": { + "string": { + "description": "This string must be a string", + "type": "string" + }, + "reference": { + "description": "This is reference field.", + "$ref": "#/definitions/ReferenceKind" + } + } + } + } +} diff --git a/vendor/k8s.io/kubectl/pkg/explain/test-swagger.json b/vendor/k8s.io/kubectl/pkg/explain/test-swagger.json new file mode 100644 index 000000000000..ba5fa1ff71c0 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/explain/test-swagger.json @@ -0,0 +1,102 @@ +{ + "swagger": "2.0", + "info": { + "title": "Kubernetes", + "version": "v1.9.0" + }, + "paths": {}, + "definitions": { + "PrimitiveDef": { + "type": "string" + }, + "OneKind": { + "description": "OneKind has a short description", + "required": [ + "field1" + ], + "properties": { + "field1": { + "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ut lacus ac enim vulputate imperdiet ac accumsan risus. Integer vel accumsan lectus. Praesent tempus nulla id tortor luctus, quis varius nulla laoreet. Ut orci nisi, suscipit id velit sed, blandit eleifend turpis. Curabitur tempus ante at lectus viverra, a mattis augue euismod. Morbi quam ligula, porttitor sit amet lacus non, interdum pulvinar tortor. Praesent accumsan risus et ipsum dictum, vel ullamcorper lorem egestas.", + "$ref": "#/definitions/OtherKind" + }, + "field2": { + "description": "This is an array of object of PrimitiveDef", + "type": "array", + "items": { + "description": "This is an object of PrimitiveDef", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/PrimitiveDef" + } + } + } + }, + "x-kubernetes-group-version-kind": [ + { + "group": "", + "kind": "OneKind", + "version": "v1" + } + ] + }, + "ControlCharacterKind": { + "description": "Control character %", + "properties": { + "field1": { + "description": "Control character %", + } + }, + "x-kubernetes-group-version-kind": [ + { + "group": "", + "kind": "ControlCharacterKind", + "version": "v1" + } + ] + }, + "OtherKind": { + "description": "This is another kind of Kind", + "required": [ + "string" + ], + "properties": { + "string": { + "description": "This string must be a string", + "type": "string" + }, + "int": { + "description": "This int must be an int", + "type": "integer" + }, + "array": { + "description": "This array must be an array of int", + "type": "array", + "items": { + "description": "This is an int in an array", + "type": "integer" + } + }, + "object": { + "description": "This is an object of string", + "type": "object", + "additionalProperties": { + "description": "this is a string in an object", + "type": "string" + } + }, + "primitive": { + "$ref": "#/definitions/PrimitiveDef" + } + } + }, + "CrdKind": { + "x-kubernetes-group-version-kind": [ + { + "group": "", + "kind": "CrdKind", + "version": "v1" + } + ] + } + } +} diff --git a/vendor/k8s.io/kubectl/pkg/explain/typename.go b/vendor/k8s.io/kubectl/pkg/explain/typename.go new file mode 100644 index 000000000000..b9d71b69a5ca --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/explain/typename.go @@ -0,0 +1,66 @@ +/* +Copyright 2017 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 explain + +import ( + "fmt" + + "k8s.io/kube-openapi/pkg/util/proto" +) + +// typeName finds the name of a schema +type typeName struct { + Name string +} + +var _ proto.SchemaVisitor = &typeName{} + +// VisitArray adds the [] prefix and recurses. +func (t *typeName) VisitArray(a *proto.Array) { + s := &typeName{} + a.SubType.Accept(s) + t.Name = fmt.Sprintf("[]%s", s.Name) +} + +// VisitKind just returns "Object". +func (t *typeName) VisitKind(k *proto.Kind) { + t.Name = "Object" +} + +// VisitMap adds the map[string] prefix and recurses. +func (t *typeName) VisitMap(m *proto.Map) { + s := &typeName{} + m.SubType.Accept(s) + t.Name = fmt.Sprintf("map[string]%s", s.Name) +} + +// VisitPrimitive returns the name of the primitive. +func (t *typeName) VisitPrimitive(p *proto.Primitive) { + t.Name = p.Type +} + +// VisitReference is just a passthrough. +func (t *typeName) VisitReference(r proto.Reference) { + r.SubSchema().Accept(t) +} + +// GetTypeName returns the type of a schema. +func GetTypeName(schema proto.Schema) string { + t := &typeName{} + schema.Accept(t) + return t.Name +} diff --git a/vendor/k8s.io/kubectl/pkg/explain/v2/explain.go b/vendor/k8s.io/kubectl/pkg/explain/v2/explain.go new file mode 100644 index 000000000000..43db73378da4 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/explain/v2/explain.go @@ -0,0 +1,97 @@ +/* +Copyright 2022 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 v2 + +import ( + "encoding/json" + "errors" + "fmt" + "io" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/openapi" +) + +// PrintModelDescription prints the description of a specific model or dot path. +// If recursive, all components nested within the fields of the schema will be +// printed. +func PrintModelDescription( + fieldsPath []string, + w io.Writer, + client openapi.Client, + gvr schema.GroupVersionResource, + recursive bool, + outputFormat string, +) error { + generator := NewGenerator() + if err := registerBuiltinTemplates(generator); err != nil { + return fmt.Errorf("error parsing builtin templates. Please file a bug on GitHub: %w", err) + } + + return printModelDescriptionWithGenerator( + generator, fieldsPath, w, client, gvr, recursive, outputFormat) +} + +// Factored out for testability +func printModelDescriptionWithGenerator( + generator Generator, + fieldsPath []string, + w io.Writer, + client openapi.Client, + gvr schema.GroupVersionResource, + recursive bool, + outputFormat string, +) error { + paths, err := client.Paths() + + if err != nil { + return fmt.Errorf("failed to fetch list of groupVersions: %w", err) + } + + var resourcePath string + if len(gvr.Group) == 0 { + resourcePath = fmt.Sprintf("api/%s", gvr.Version) + } else { + resourcePath = fmt.Sprintf("apis/%s/%s", gvr.Group, gvr.Version) + } + + gv, exists := paths[resourcePath] + + if !exists { + return fmt.Errorf("couldn't find resource for \"%v\"", gvr) + } + + openAPISchemaBytes, err := gv.Schema(runtime.ContentTypeJSON) + if err != nil { + return fmt.Errorf("failed to fetch openapi schema for %s: %w", resourcePath, err) + } + + var parsedV3Schema map[string]interface{} + if err := json.Unmarshal(openAPISchemaBytes, &parsedV3Schema); err != nil { + return fmt.Errorf("failed to parse openapi schema for %s: %w", resourcePath, err) + } + + err = generator.Render(outputFormat, parsedV3Schema, gvr, fieldsPath, recursive, w) + + explainErr := explainError("") + if errors.As(err, &explainErr) { + return explainErr + } + + return err +} diff --git a/vendor/k8s.io/kubectl/pkg/explain/v2/funcs.go b/vendor/k8s.io/kubectl/pkg/explain/v2/funcs.go new file mode 100644 index 000000000000..4c5e1c62be57 --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/explain/v2/funcs.go @@ -0,0 +1,240 @@ +/* +Copyright 2022 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 v2 + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "reflect" + "strings" + "text/template" + + "github.com/go-openapi/jsonreference" + "k8s.io/kubectl/pkg/util/term" +) + +type explainError string + +func (e explainError) Error() string { + return string(e) +} + +func WithBuiltinTemplateFuncs(tmpl *template.Template) *template.Template { + return tmpl.Funcs(map[string]interface{}{ + "throw": func(e string, args ...any) (string, error) { + errString := fmt.Sprintf(e, args...) + return "", explainError(errString) + }, + "toJson": func(obj any) (string, error) { + res, err := json.Marshal(obj) + return string(res), err + }, + "toPrettyJson": func(obj any) (string, error) { + res, err := json.MarshalIndent(obj, "", " ") + if err != nil { + return "", err + } + return string(res), err + }, + "fail": func(message string) (string, error) { + return "", errors.New(message) + }, + "wrap": func(l int, s string) (string, error) { + buf := bytes.NewBuffer(nil) + writer := term.NewWordWrapWriter(buf, uint(l)) + _, err := writer.Write([]byte(s)) + if err != nil { + return "", err + } + return buf.String(), nil + }, + "split": func(s string, sep string) []string { + return strings.Split(s, sep) + }, + "join": func(sep string, strs ...string) string { + return strings.Join(strs, sep) + }, + "include": func(name string, data interface{}) (string, error) { + buf := bytes.NewBuffer(nil) + if err := tmpl.ExecuteTemplate(buf, name, data); err != nil { + return "", err + } + return buf.String(), nil + }, + "ternary": func(a, b any, condition bool) any { + if condition { + return a + } + return b + }, + "first": func(list any) (any, error) { + if list == nil { + return nil, errors.New("list is empty") + } + + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + if l == 0 { + return nil, errors.New("list is empty") + } + + return l2.Index(0).Interface(), nil + default: + return nil, fmt.Errorf("first cannot be used on type: %T", list) + } + }, + "last": func(list any) (any, error) { + if list == nil { + return nil, errors.New("list is empty") + } + + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + if l == 0 { + return nil, errors.New("list is empty") + } + + return l2.Index(l - 1).Interface(), nil + default: + return nil, fmt.Errorf("last cannot be used on type: %T", list) + } + }, + "indent": func(amount int, str string) string { + pad := strings.Repeat(" ", amount) + return pad + strings.Replace(str, "\n", "\n"+pad, -1) + }, + "dict": func(keysAndValues ...any) (map[string]any, error) { + if len(keysAndValues)%2 != 0 { + return nil, errors.New("expected even # of arguments") + } + + res := map[string]any{} + for i := 0; i+1 < len(keysAndValues); i = i + 2 { + if key, ok := keysAndValues[i].(string); ok { + res[key] = keysAndValues[i+1] + } else { + return nil, fmt.Errorf("key of type %T is not a string as expected", key) + } + } + + return res, nil + }, + "contains": func(list any, value any) bool { + if list == nil { + return false + } + + val := reflect.ValueOf(list) + switch val.Kind() { + case reflect.Array: + case reflect.Slice: + for i := 0; i < val.Len(); i++ { + cur := val.Index(i) + if cur.CanInterface() && reflect.DeepEqual(cur.Interface(), value) { + return true + } + } + return false + default: + return false + } + return false + }, + "set": func(dict map[string]any, keysAndValues ...any) (any, error) { + if len(keysAndValues)%2 != 0 { + return nil, errors.New("expected even number of arguments") + } + + copyDict := make(map[string]any, len(dict)) + for k, v := range dict { + copyDict[k] = v + } + + for i := 0; i < len(keysAndValues); i += 2 { + key, ok := keysAndValues[i].(string) + if !ok { + return nil, errors.New("keys must be strings") + } + + copyDict[key] = keysAndValues[i+1] + } + + return copyDict, nil + }, + "list": func(values ...any) ([]any, error) { + return values, nil + }, + "add": func(value, operand int) int { + return value + operand + }, + "sub": func(value, operand int) int { + return value - operand + }, + "mul": func(value, operand int) int { + return value * operand + }, + "resolveRef": func(refAny any, document map[string]any) map[string]any { + refString, ok := refAny.(string) + if !ok { + // if passed nil, or wrong type just treat the same + // way as unresolved reference (makes for easier templates) + return nil + } + + // Resolve field path encoded by the ref + ref, err := jsonreference.New(refString) + if err != nil { + // Unrecognized ref format. + return nil + } + + if !ref.HasFragmentOnly { + // Downloading is not supported. Treat as not found + return nil + } + + fragment := ref.GetURL().Fragment + components := strings.Split(fragment, "/") + cur := document + + for _, k := range components { + if len(k) == 0 { + // first component is usually empty (#/components/) , etc + continue + } + + next, ok := cur[k].(map[string]any) + if !ok { + return nil + } + + cur = next + } + return cur + }, + }) +} diff --git a/vendor/k8s.io/kubectl/pkg/explain/v2/generator.go b/vendor/k8s.io/kubectl/pkg/explain/v2/generator.go new file mode 100644 index 000000000000..cfcf2eaabece --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/explain/v2/generator.go @@ -0,0 +1,102 @@ +/* +Copyright 2022 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 v2 + +import ( + "fmt" + "io" + "text/template" + + "k8s.io/apimachinery/pkg/runtime/schema" +) + +type Generator interface { + AddTemplate(name string, contents string) error + + Render( + // Template to use for rendering + templateName string, + // Self-Contained OpenAPI Document Containing all schemas used by $ref + // Only OpenAPI V3 documents are supported + document map[string]interface{}, + // Resource within OpenAPI document for which to render explain schema + gvr schema.GroupVersionResource, + // Field path of child of resource to focus output onto + fieldSelector []string, + // Boolean indicating whether the fields should be rendered recursively/deeply + recursive bool, + // Output writer + writer io.Writer, + ) error +} + +type TemplateContext struct { + GVR schema.GroupVersionResource + Document map[string]interface{} + Recursive bool + FieldPath []string +} + +type generator struct { + templates map[string]*template.Template +} + +func NewGenerator() Generator { + return &generator{ + templates: make(map[string]*template.Template), + } +} + +func (g *generator) AddTemplate(name string, contents string) error { + compiled, err := WithBuiltinTemplateFuncs(template.New(name)).Parse(contents) + + if err != nil { + return err + } + + g.templates[name] = compiled + return nil +} + +func (g *generator) Render( + // Template to use for rendering + templateName string, + // Self-Contained OpenAPI Document Containing all schemas used by $ref + // Only OpenAPI V3 documents are supported + document map[string]interface{}, + // Resource within OpenAPI document for which to render explain schema + gvr schema.GroupVersionResource, + // Field path of child of resource to focus output onto + fieldSelector []string, + // Boolean indicating whether the fields should be rendered recursively/deeply + recursive bool, + // Output writer + writer io.Writer, +) error { + compiledTemplate, ok := g.templates[templateName] + if !ok { + return fmt.Errorf("unrecognized format: %s", templateName) + } + + err := compiledTemplate.Execute(writer, TemplateContext{ + Document: document, + Recursive: recursive, + FieldPath: fieldSelector, + GVR: gvr, + }) + return err +} diff --git a/vendor/k8s.io/kubectl/pkg/explain/v2/template.go b/vendor/k8s.io/kubectl/pkg/explain/v2/template.go new file mode 100644 index 000000000000..45b1762eb7dc --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/explain/v2/template.go @@ -0,0 +1,50 @@ +/* +Copyright 2022 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 v2 + +import ( + "embed" + "path/filepath" + "strings" +) + +//go:embed templates/*.tmpl +var rawBuiltinTemplates embed.FS + +func registerBuiltinTemplates(gen Generator) error { + files, err := rawBuiltinTemplates.ReadDir("templates") + if err != nil { + return err + } + + for _, entry := range files { + contents, err := rawBuiltinTemplates.ReadFile("templates/" + entry.Name()) + if err != nil { + return err + } + + err = gen.AddTemplate( + strings.TrimSuffix(entry.Name(), filepath.Ext(entry.Name())), + string(contents)) + + if err != nil { + return err + } + } + + return nil +} diff --git a/vendor/k8s.io/kubectl/pkg/explain/v2/templates/plaintext.tmpl b/vendor/k8s.io/kubectl/pkg/explain/v2/templates/plaintext.tmpl new file mode 100644 index 000000000000..971dfff1f22c --- /dev/null +++ b/vendor/k8s.io/kubectl/pkg/explain/v2/templates/plaintext.tmpl @@ -0,0 +1,339 @@ +{{- /* Determine if Path for requested GVR is at /api or /apis based on emptiness of group */ -}} +{{- $prefix := (ternary "/api" (join "" "/apis/" $.GVR.Group) (not $.GVR.Group)) -}} + +{{- /* Search both cluster-scoped and namespaced-scoped paths for the GVR to find its GVK */ -}} +{{- /* Also search for paths with {name} component in case the list path is missing */ -}} +{{- /* Looks for the following paths: */ -}} +{{- /* /apis/// */ -}} +{{- /* /apis////{name} */ -}} +{{- /* /apis///namespaces/{namespace}/ */ -}} +{{- /* /apis///namespaces/{namespace}//{name} */ -}} +{{- /* Also search for get verb paths in case list verb is missing */ -}} +{{- $clusterScopedSearchPath := join "/" $prefix $.GVR.Version $.GVR.Resource -}} +{{- $clusterScopedNameSearchPath := join "/" $prefix $.GVR.Version $.GVR.Resource "{name}" -}} +{{- $namespaceScopedSearchPath := join "/" $prefix $.GVR.Version "namespaces" "{namespace}" $.GVR.Resource -}} +{{- $namespaceScopedNameSearchPath := join "/" $prefix $.GVR.Version "namespaces" "{namespace}" $.GVR.Resource "{name}" -}} +{{- $gvk := "" -}} + +{{- /* Pull GVK from operation */ -}} +{{- range $index, $searchPath := (list $clusterScopedSearchPath $clusterScopedNameSearchPath $namespaceScopedSearchPath $namespaceScopedNameSearchPath) -}} + {{- with $resourcePathElement := index $.Document "paths" $searchPath -}} + {{- range $methodIndex, $method := (list "get" "post" "put" "patch" "delete") -}} + {{- with $resourceMethodPathElement := index $resourcePathElement $method -}} + {{- with $gvk = index $resourceMethodPathElement "x-kubernetes-group-version-kind" -}} + {{- break -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- with $gvk -}} + {{- if $gvk.group -}} + GROUP: {{ $gvk.group }}{{"\n" -}} + {{- end -}} + KIND: {{ $gvk.kind}}{{"\n" -}} + VERSION: {{ $gvk.version }}{{"\n" -}} + {{- "\n" -}} + + {{- with include "schema" (dict "gvk" $gvk "Document" $.Document "FieldPath" $.FieldPath "Recursive" $.Recursive) -}} + {{- . -}} + {{- else -}} + {{- throw "error: GVK %v not found in OpenAPI schema" $gvk -}} + {{- end -}} +{{- else -}} + {{- throw "error: GVR (%v) not found in OpenAPI schema" $.GVR.String -}} +{{- end -}} +{{- "\n" -}} + +{{- /* +Finds a schema with the given GVK and prints its explain output or empty string +if GVK was not found + +Takes dictionary as argument with keys: + gvk: openapiv3 JSON schema + Document: entire doc + FieldPath: field path to follow + Recursive: print recursive +*/ -}} +{{- define "schema" -}} + {{- /* Find definition with this GVK by filtering out the components/schema with the given x-kubernetes-group-version-kind */ -}} + {{- range index $.Document "components" "schemas" -}} + {{- if contains (index . "x-kubernetes-group-version-kind") $.gvk -}} + {{- with include "output" (set $ "schema" .) -}} + {{- . -}} + {{- else -}} + {{- $fieldName := (index $.FieldPath (sub (len $.FieldPath) 1)) -}} + {{- throw "error: field \"%v\" does not exist" $fieldName}} + {{- end -}} + {{- break -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- /* +Follows FieldPath until the FieldPath is empty. Then prints field name and field +list of resultant schema. If field path is not found. Prints nothing. +Example output: + +FIELD: spec + +DESCRIPTION: +