diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..095b56c --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,32 @@ +name: Lint + +on: + push: + branches: + - master + pull_request: + workflow_dispatch: + + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up Python 3 + uses: actions/setup-python@v4 + with: + python-version: '3.11' + + - name: Install Dependencies + shell: bash + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install -r requirements-lint.txt + - name: Lint + shell: bash + run: | + pylint nomad/ + black --check -l 120 -t py311 nomad/ diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 99f5e25..c1de942 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -20,13 +20,12 @@ jobs: env: NOMAD_IP: '127.0.0.1' NOMAD_PORT: '4646' - NOMAD_LATEST: '1.1.18' strategy: fail-fast: false matrix: - python-version: ['2.7', '3.7', '3.10'] - nomad-version: ['1.0.18', '1.1.18', '1.2.14', '1.3.7', '1.4.2'] + python-version: ['3.7', '3.11'] # the oldest and newest support versions + nomad-version: ['1.0.18', '1.1.18', '1.2.15', '1.3.14', '1.4.9', '1.5.5'] steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} @@ -38,41 +37,30 @@ jobs: NOMAD_VERSION: ${{ matrix.nomad-version }} shell: bash run: | - echo $NOMAD_VERSION echo ${NOMAD_VERSION} echo "downloading nomad" curl -L -o /tmp/nomad_${NOMAD_VERSION}_linux_amd64.zip https://releases.hashicorp.com/nomad/${NOMAD_VERSION}/nomad_${NOMAD_VERSION}_linux_amd64.zip echo "unzip nomad" - unzip -d /tmp /tmp/nomad_${NOMAD_VERSION}_linux_amd64.zip - - echo "starting nomad server" - /tmp/nomad agent -dev -bind ${NOMAD_IP} -node pynomad1 --acl-enabled > /dev/null 2>&1 & - sleep 30 + unzip -d /usr/local/bin/ /tmp/nomad_${NOMAD_VERSION}_linux_amd64.zip - name: Install Dependencies - env: - PYTHON_VERSION: ${{ matrix.python-version }} shell: bash run: | python -m pip install --upgrade pip if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - if [ $PYTHON_VERSION = "2.7" ]; then - pip install -r requirements-dev-py27.txt - else - pip install -r requirements-dev.txt - fi + pip install -r requirements-dev.txt - name: Before Tests shell: bash run: | - /tmp/nomad init - /tmp/nomad run -output example.nomad > example.json + nomad init example.nomad + nomad run -output example.nomad > example.json - name: Unit and Integration Tests env: NOMAD_VERSION: ${{ matrix.nomad-version }} shell: bash run: | - py.test --cov=nomad --cov-report=term-missing --runxfail tests/ + ./run_tests.sh - name: Upload coverage to Codecov uses: codecov/codecov-action@v2 - name: Create Package diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000..279e122 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,6 @@ +[FORMAT] +# Maximum number of characters on a single line. +max-line-length=120 + +[MESSAGES CONTROL] +disable=duplicate-code \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c89101..5c452ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ +## 2.0.0 +### BREAKING CHANGES +* Drop Python 2 and Python 3.6 support +* Rename `id` arguments to `id_` across of code base +* Rename `type` arguments to `type_` across of code base +### Other changes +* Add more missing parameters to allocations.get_allocations() +* Up `requests` lib version to 2.28.1 +* Add missing parameters to allocations.get_allocations and jobs.get_jobs (#144). Thanks @Kamilcuk +* Add option for custom user agent (#150) +* Add missing parameters to nodes.get_nodes (#152). ## 1.5.0 -* Add `namespace` agrument support for `get_allocations` and `get_deployments` endpoints (#133) +* Add `namespace` argument support for `get_allocations` and `get_deployments` endpoints (#133) * Add Python 3.10 support (#133) * Add support for pre-populated Sessions (#132) * Add scaling policy endpoint (#136) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fb4e933..f888149 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -180,7 +180,7 @@ class (Requester): ENDPOINT = "" def __init__(self, **kwargs): - super(, self).__init__(**kwargs) + super().__init__(**kwargs) ``` ##### Entity @@ -249,7 +249,7 @@ class cat(Requester): ENDPOINT = "client/fs/cat" def __init__(self, **kwargs): - super(cat, self).__init__(**kwargs) + super().__init__(**kwargs) def read_file(self, id=None, path="/"): """ Read contents of a file in an allocation directory. @@ -382,7 +382,7 @@ class (Requester): ENDPOINT = "" def __init__(self, **kwargs): - super(, self).__init__(**kwargs) + super().__init__(**kwargs) def __str__(self): return "{0}".format(self.__dict__) diff --git a/docs/api/acl.md b/docs/api/acl.md index 34ec265..90fe636 100644 --- a/docs/api/acl.md +++ b/docs/api/acl.md @@ -8,7 +8,7 @@ Nomad must be running with ACL mode enabled. This endpoint is used to bootstrap the ACL system and provide the initial management token. This request is always forwarded to the authoritative region. It can only be invoked once until a bootstrap reset is performed. -https://www.nomadproject.io/api/acl-tokens.html#bootstrap-token +https://developer.hashicorp.com/nomad/api-docs/acl/tokens#bootstrap-token Example: @@ -48,7 +48,7 @@ print (my_nomad.get_token()) This endpoint lists all ACL tokens. This lists the local tokens and the global tokens which have been replicated to the region, and may lag behind the authoritative region. -https://www.nomadproject.io/api/acl-tokens.html#list-tokens +https://developer.hashicorp.com/nomad/api-docs/acl/tokens#list-tokens Exmaple: @@ -68,7 +68,7 @@ for token in tokens: This endpoint creates an ACL Token. If the token is a global token, the request is forwarded to the authoritative region. -https://www.nomadproject.io/api/acl-tokens.html#create-token +https://developer.hashicorp.com/nomad/api-docs/acl/tokens#create-token Exmample: @@ -91,7 +91,7 @@ created_token = my_nomad.acl.create_token(new_token) This endpoint updates an existing ACL Token. If the token is a global token, the request is forwarded to the authoritative region. Note that a token cannot be switched from global to local or vice versa. -https://www.nomadproject.io/api/acl-tokens.html#update-token +https://developer.hashicorp.com/nomad/api-docs/acl/tokens#update-token Example: @@ -115,7 +115,7 @@ updated_token = my_nomad.acl.update_token('377ba749-8b0e-c7fd-c0c0-9da5bb943088' This endpoint reads an ACL token with the given accessor. If the token is a global token which has been replicated to the region it may lag behind the authoritative region. -https://www.nomadproject.io/api/acl-tokens.html#read-token +https://developer.hashicorp.com/nomad/api-docs/acl/tokens#read-token Exmaple: @@ -131,7 +131,7 @@ token = my_nomad.acl.get_token("377ba749-8b0e-c7fd-c0c0-9da5bb943088") This endpoint reads the ACL token given by the passed SecretID. If the token is a global token which has been replicated to the region it may lag behind the authoritative region. -https://www.nomadproject.io/api/acl-tokens.html#read-self-token +https://developer.hashicorp.com/nomad/api-docs/acl/tokens#read-self-token Exmaple: @@ -147,7 +147,7 @@ self_token = my_nomad.acl.get_self_token() This endpoint deletes the ACL token by accessor. This request is forwarded to the authoritative region for global tokens. -https://www.nomadproject.io/api/acl-tokens.html#delete-token +https://developer.hashicorp.com/nomad/api-docs/acl/tokens#delete-token Example: @@ -164,13 +164,13 @@ my_nomad.acl.delete_token("377ba749-8b0e-c7fd-c0c0-9da5bb943088") Manage acl Policies -https://www.nomadproject.io/api/acl-policies.html +https://developer.hashicorp.com/nomad/api-docs/acl-policies.html ### List policies This endpoint lists all ACL policies. This lists the policies that have been replicated to the region, and may lag behind the authoritative region. -https://www.nomadproject.io/api/acl-policies.html#list-policies +https://developer.hashicorp.com/nomad/api-docs/acl-policies#list-policies Example: @@ -186,7 +186,7 @@ policies = my_nomad.acl.get_policies() This endpoint creates an ACL Policy. This request is always forwarded to the authoritative region. -https://www.nomadproject.io/api/acl-policies.html#create-or-update-policy +https://developer.hashicorp.com/nomad/api-docs/acl-policies#create-or-update-policy Example: ``` @@ -207,7 +207,7 @@ my_nomad.acl.create_policy("my-policy", policy) This endpoint update an ACL Policy. This request is always forwarded to the authoritative region. -https://www.nomadproject.io/api/acl-policies.html#create-or-update-policy +https://developer.hashicorp.com/nomad/api-docs/acl-policies#create-or-update-policy Example: @@ -229,7 +229,7 @@ my_nomad.acl.update_policy("my-policy", policy) This endpoint reads an ACL policy with the given name. This queries the policy that have been replicated to the region, and may lag behind the authoritative region. -https://www.nomadproject.io/api/acl-policies.html#read-policy +https://developer.hashicorp.com/nomad/api-docs/acl-policies#read-policy Example: diff --git a/docs/api/agent.md b/docs/api/agent.md index 32da2d2..81f623f 100644 --- a/docs/api/agent.md +++ b/docs/api/agent.md @@ -4,7 +4,7 @@ This endpoint queries the agent for the known peers in the gossip pool. This endpoint is only applicable to servers. Due to the nature of gossip, this is eventually consistent. -https://www.nomadproject.io/api/agent.html#list-members +https://developer.hashicorp.com/nomad/api-docs/agent#list-members Example: @@ -23,7 +23,7 @@ for member in members["Members"]: This endpoint lists the known server nodes. The servers endpoint is used to query an agent in client mode for its list of known servers. Client nodes register themselves with these server addresses so that they may dequeue work. The servers endpoint can be used to keep this configuration up to date if there are changes in the cluster -https://www.nomadproject.io/api/agent.html#list-servers +https://developer.hashicorp.com/nomad/api-docs/agent#list-servers Example: @@ -42,7 +42,7 @@ for server in servers: This endpoint queries the state of the target agent (self). -https://www.nomadproject.io/api/agent.html#query-self +https://developer.hashicorp.com/nomad/api-docs/agent#query-self Example: @@ -60,7 +60,7 @@ print (agent) This endpoint updates the list of known servers to the provided list. This replaces all previous server addresses with the new list. -https://www.nomadproject.io/api/agent.html#update-servers +https://developer.hashicorp.com/nomad/api-docs/agent#update-servers Example: @@ -76,7 +76,7 @@ r = my_nomad.agent.update_servers(['192.168.33.11', '10.1.10.200:4829']) This endpoint introduces a new member to the gossip pool. This endpoint is only eligible for servers. -https://www.nomadproject.io/api/agent.html#join-agent +https://developer.hashicorp.com/nomad/api-docs/agent#join-agent Example: @@ -92,7 +92,7 @@ r = my_nomad.agent.join_agent("server02") This endpoint forces a member of the gossip pool from the "failed" state to the "left" state. This allows the consensus protocol to remove the peer and stop attempting replication. This is only applicable for servers. -https://www.nomadproject.io/api/agent.html#force-leave-agent +https://developer.hashicorp.com/nomad/api-docs/agent#force-leave-agent Exmaple: @@ -110,7 +110,7 @@ This endpoint returns whether or not the agent is healthy. When using Consul it When the agent is unhealthy 500 will be returned along with JSON response containing an error message. -https://www.nomadproject.io/api/agent.html#health +https://developer.hashicorp.com/nomad/api-docs/agent#health Example: diff --git a/docs/api/allocation.md b/docs/api/allocation.md index 2c331d2..02efd9d 100644 --- a/docs/api/allocation.md +++ b/docs/api/allocation.md @@ -4,7 +4,7 @@ This endpoint reads information about a specific allocation. -https://www.nomadproject.io/api/allocations.html#read-allocation +https://developer.hashicorp.com/nomad/api-docs/allocations#read-allocation ``` import nomad diff --git a/docs/api/allocations.md b/docs/api/allocations.md index 8c7ef2f..4f525af 100644 --- a/docs/api/allocations.md +++ b/docs/api/allocations.md @@ -4,7 +4,7 @@ This endpoint lists all allocations. -https://www.nomadproject.io/api/allocations.html#list-allocations +https://developer.hashicorp.com/nomad/api-docs/allocations#list-allocations Example: diff --git a/docs/api/client.md b/docs/api/client.md index da9ca15..bd7746f 100644 --- a/docs/api/client.md +++ b/docs/api/client.md @@ -4,7 +4,7 @@ This endpoint queries the actual resources consumed on a node. The API endpoint is hosted by the Nomad client and requests have to be made to the nomad client whose resource usage metrics are of interest. -https://www.nomadproject.io/api/client.html#read-stats +https://developer.hashicorp.com/nomad/api-docs/client#read-stats Example: diff --git a/docs/api/deployment.md b/docs/api/deployment.md index 9445cd8..919bbcd 100644 --- a/docs/api/deployment.md +++ b/docs/api/deployment.md @@ -6,7 +6,7 @@ The deployment endpoints are used to query for and interact with deployments. This endpoint reads information about a specific deployment by ID. -https://www.nomadproject.io/api/deployments.html#read-deployment +https://developer.hashicorp.com/nomad/api-docs/deployments#read-deployment Example: @@ -25,7 +25,7 @@ print (deployment) This endpoint lists the allocations created or modified for the given deployment. -https://www.nomadproject.io/api/deployments.html#list-allocations-for-deployment +https://developer.hashicorp.com/nomad/api-docs/deployments#list-allocations-for-deployment Example: @@ -44,7 +44,7 @@ for allocation in allocations: This endpoint is used to mark a deployment as failed. This should be done to force the scheduler to stop creating allocations as part of the deployment or to cause a rollback to a previous job version. This endpoint only triggers a rollback if the most recent stable version of the job has a different specification than the job being reverted. -https://www.nomadproject.io/api/deployments.html#fail-deployment +https://developer.hashicorp.com/nomad/api-docs/deployments#fail-deployment example: @@ -69,7 +69,7 @@ fail_deployment = my_nomad.deployment.fail_deployment('a8061a1c-d4c9-2a7d-a4b2-9 This endpoint is used to pause or unpause a deployment. This is done to pause a rolling upgrade or resume it. -https://www.nomadproject.io/api/deployments.html#pause-deployment +https://developer.hashicorp.com/nomad/api-docs/deployments#pause-deployment example: @@ -103,7 +103,7 @@ pause = my_nomad.deployment.pause_deployment("52c47d49-eefa-540f-f0f1-d25ba298c8 This endpoint is used to promote task groups that have canaries for a deployment. This should be done when the placed canaries are healthy and the rolling upgrade of the remaining allocations should begin. -https://www.nomadproject.io/api/deployments.html#promote-deployment +https://developer.hashicorp.com/nomad/api-docs/deployments#promote-deployment #### Promote All @@ -138,7 +138,7 @@ promote = my_nomad.deployment.promote_deployment_groups("52c47d49-eefa-540f-f0f1 This endpoint is used to set the health of an allocation that is in the deployment manually. In some use cases, automatic detection of allocation health may not be desired. As such those task groups can be marked with an upgrade policy that uses health_check = "manual". Those allocations must have their health marked manually using this endpoint. Marking an allocation as healthy will allow the rolling upgrade to proceed. Marking it as failed will cause the deployment to fail. This endpoint only triggers a rollback if the most recent stable version of the job has a different specification than the job being reverted. -https://www.nomadproject.io/api/deployments.html#set-allocation-health-in-deployment +https://developer.hashicorp.com/nomad/api-docs/deployments#set-allocation-health-in-deployment example: diff --git a/docs/api/deployments.md b/docs/api/deployments.md index ab5bdcf..4cc0a03 100644 --- a/docs/api/deployments.md +++ b/docs/api/deployments.md @@ -6,7 +6,7 @@ The deployment endpoints are used to query for and interact with deployments. This endpoint lists all deployments. -https://www.nomadproject.io/api/deployments.html#list-deployments +https://developer.hashicorp.com/nomad/api-docs/deployments#list-deployments Example: diff --git a/docs/api/evaluation.md b/docs/api/evaluation.md index e035a83..561dc98 100644 --- a/docs/api/evaluation.md +++ b/docs/api/evaluation.md @@ -4,7 +4,7 @@ This endpoint reads information about a specific evaluation by ID. -https://www.nomadproject.io/api/evaluations.html#read-evaluation +https://developer.hashicorp.com/nomad/api-docs/evaluations#read-evaluation Example: @@ -22,7 +22,7 @@ print (evaluation) This endpoint lists the allocations created or modified for the given evaluation. -https://www.nomadproject.io/api/evaluations.html#list-allocations-for-evaluation +https://developer.hashicorp.com/nomad/api-docs/evaluations#list-allocations-for-evaluation Example: diff --git a/docs/api/evaluations.md b/docs/api/evaluations.md index f0745cd..fcf48b3 100644 --- a/docs/api/evaluations.md +++ b/docs/api/evaluations.md @@ -4,7 +4,7 @@ This endpoint lists all evaluations. -https://www.nomadproject.io/api/evaluations.html#list-evaluations +https://developer.hashicorp.com/nomad/api-docs/evaluations#list-evaluations Example: diff --git a/docs/api/job.md b/docs/api/job.md index 9e7d39d..af6f77f 100644 --- a/docs/api/job.md +++ b/docs/api/job.md @@ -4,7 +4,7 @@ This endpoint creates (aka "registers") a new job in the system. -https://www.nomadproject.io/api/jobs.html#create-job +https://developer.hashicorp.com/nomad/api-docs/jobs#create-job Example: @@ -109,7 +109,7 @@ response = my_nomad.job.register_job("example", job) This endpoint reads information about a single job for its specification and status. -https://www.nomadproject.io/api/jobs.html#read-job +https://developer.hashicorp.com/nomad/api-docs/jobs#read-job Example: @@ -126,7 +126,7 @@ job = my_nomad.job.get_job("example") This endpoint reads information about all versions of a job. -https://www.nomadproject.io/api/jobs.html#list-job-versions +https://developer.hashicorp.com/nomad/api-docs/jobs#list-job-versions Example: @@ -145,7 +145,7 @@ for version in versions["Versions"]: This endpoint reads information about a single job's allocations. -https://www.nomadproject.io/api/jobs.html#list-job-allocations +https://developer.hashicorp.com/nomad/api-docs/jobs#list-job-allocations Example: @@ -164,7 +164,7 @@ for allocation in allocations: This endpoint reads information about a single job's evaluations -https://www.nomadproject.io/api/jobs.html#list-job-evaluations +https://developer.hashicorp.com/nomad/api-docs/jobs#list-job-evaluations Example: @@ -184,7 +184,7 @@ for evaluation in evaluations: This endpoint lists a single job's deployments -https://www.nomadproject.io/api/jobs.html#list-job-deployments +https://developer.hashicorp.com/nomad/api-docs/jobs#list-job-deployments Example: @@ -204,7 +204,7 @@ for deployment in deployments: This endpoint returns a single job's most recent deployment. -https://www.nomadproject.io/api/jobs.html#read-job-39-s-most-recent-deployment +https://developer.hashicorp.com/nomad/api-docs/jobs#read-job-39-s-most-recent-deployment Example: @@ -221,7 +221,7 @@ deployment = my_nomad.job.get_deployment("example") This endpoint reads summary information about a job. -https://www.nomadproject.io/api/jobs.html#read-job-summary +https://developer.hashicorp.com/nomad/api-docs/jobs#read-job-summary Example: @@ -238,7 +238,7 @@ summary = my_nomad.job.get_summary("example") This endpoint registers a new job or updates an existing job. -https://www.nomadproject.io/api/jobs.html#update-existing-job +https://developer.hashicorp.com/nomad/api-docs/jobs#update-existing-job Example: @@ -249,7 +249,7 @@ See create new job This endpoint dispatches a new instance of a parameterized job. -https://www.nomadproject.io/api/jobs.html#dispatch-job +https://developer.hashicorp.com/nomad/api-docs/jobs#dispatch-job Example: @@ -287,7 +287,7 @@ parametrize_job = { "Name": "example-task", "Driver": "docker", "Config": { - "args": ["${NOMAD_META_TIME"], + "args": ["${NOMAD_META_TIME}"], "command": "sleep", "image": "scratch", "logging": [], @@ -340,7 +340,7 @@ my_nomad.job.dispatch_job("example-batch", meta={"time": "500"}) This endpoint reverts the job to an older version. -https://www.nomadproject.io/api/jobs.html#revert-to-older-job-version +https://developer.hashicorp.com/nomad/api-docs/jobs#revert-to-older-job-version Example: @@ -361,7 +361,7 @@ my_nomad.job.revert_job("example", prior_job_version, current_job_version) This endpoint sets the job's stability. -https://www.nomadproject.io/api/jobs.html#set-job-stability +https://developer.hashicorp.com/nomad/api-docs/jobs#set-job-stability Example: @@ -380,7 +380,7 @@ my_nomad.job.stable_job("example", current_job_version, True) This endpoint creates a new evaluation for the given job. This can be used to force run the scheduling logic if necessary. -https://www.nomadproject.io/api/jobs.html#create-job-evaluation +https://developer.hashicorp.com/nomad/api-docs/jobs#create-job-evaluation Example: @@ -396,7 +396,7 @@ my_nomad.job.evaluate_job("example") This endpoint invokes a dry-run of the scheduler for the job. -https://www.nomadproject.io/api/jobs.html#create-job-plan +https://developer.hashicorp.com/nomad/api-docs/jobs#create-job-plan Example: @@ -500,7 +500,7 @@ plan = my_nomad.job.plan_job("example", job) This endpoint deregisters a job, and stops all allocations part of it. -https://www.nomadproject.io/api/jobs.html#stop-a-job +https://developer.hashicorp.com/nomad/api-docs/jobs#stop-a-job Example of deferred removal of job (performed by Nomad garbage collector): diff --git a/docs/api/jobs.md b/docs/api/jobs.md index 08fb1f6..c1a94a5 100644 --- a/docs/api/jobs.md +++ b/docs/api/jobs.md @@ -4,7 +4,7 @@ This endpoint lists all known jobs in the system registered with Nomad. -https://www.nomadproject.io/api/jobs.html#list-jobs +https://developer.hashicorp.com/nomad/api-docs/jobs#list-jobs Example: @@ -23,7 +23,7 @@ for job in jobs: This endpoint creates (aka "registers") a new job in the system. -https://www.nomadproject.io/api/jobs.html#create-job +https://developer.hashicorp.com/nomad/api-docs/jobs#create-job Example: @@ -129,7 +129,7 @@ To convert to python dict and verify for correctness a hcl/nomad file. The examp `nomad job init` and it will assume this file is in the current working directory. In practice this file should already be read and used as the parameter hcl. -https://www.nomadproject.io/api/jobs.html#parse-job +https://developer.hashicorp.com/nomad/api-docs/jobs#parse-job ```python diff --git a/docs/api/metrics.md b/docs/api/metrics.md index f797525..5c5fe0c 100644 --- a/docs/api/metrics.md +++ b/docs/api/metrics.md @@ -2,7 +2,7 @@ ### Get node metrics -https://www.nomadproject.io/api/metrics.html +https://developer.hashicorp.com/nomad/api-docs/metrics.html Example: diff --git a/docs/api/namespace.md b/docs/api/namespace.md index c4d8a42..52d126c 100644 --- a/docs/api/namespace.md +++ b/docs/api/namespace.md @@ -8,7 +8,7 @@ You must have nomad **ENTERPRISE Edition** Create new namespace -https://www.nomadproject.io/api/namespaces.html#create-or-update-namespace +https://developer.hashicorp.com/nomad/api-docs/namespaces#create-or-update-namespace Exmample: @@ -52,7 +52,7 @@ print (my_nomad.get_namespace()) This endpoint reads information about a specific namespace. -https://www.nomadproject.io/api/namespaces.html#read-namespace +https://developer.hashicorp.com/nomad/api-docs/namespaces#read-namespace Exmample: @@ -69,7 +69,7 @@ namespace = my_nomad.namespace.get_namespace("api-prod") Update existing namespace -https://www.nomadproject.io/api/namespaces.html#create-or-update-namespace +https://developer.hashicorp.com/nomad/api-docs/namespaces#create-or-update-namespace Example: @@ -89,7 +89,7 @@ my_nomad.namespace.create_namespace("api-prod", namespace) Delete namespace -https://www.nomadproject.io/api/namespaces.html#create-or-update-namespace +https://developer.hashicorp.com/nomad/api-docs/namespaces#create-or-update-namespace Exmaple: diff --git a/docs/api/namespaces.md b/docs/api/namespaces.md index bb2595b..359ced3 100644 --- a/docs/api/namespaces.md +++ b/docs/api/namespaces.md @@ -8,7 +8,7 @@ You must have nomad **ENTERPRISE Edition** This endpoint lists all namespaces. -https://www.nomadproject.io/api/namespaces.html#list-namespaces +https://developer.hashicorp.com/nomad/api-docs/namespaces#list-namespaces Exmaple: diff --git a/docs/api/node.md b/docs/api/node.md index 9accd9d..f89ef69 100644 --- a/docs/api/node.md +++ b/docs/api/node.md @@ -4,7 +4,7 @@ This endpoint queries the status of a client node. -https://www.nomadproject.io/api/nodes.html#read-node +https://developer.hashicorp.com/nomad/api-docs/nodes#read-node Example: @@ -20,7 +20,7 @@ node = my_nomad.node.get_node('ed1bbae7-c38a-df2d-1de7-50dbc753fc98') This endpoint lists all of the allocations for the given node. This can be used to determine what allocations have been scheduled on the node, their current status, and the values of dynamically assigned resources, like ports. -https://www.nomadproject.io/api/nodes.html#list-node-allocations +https://developer.hashicorp.com/nomad/api-docs/nodes#list-node-allocations Example: @@ -40,7 +40,7 @@ for allocation in allocations: This endpoint creates a new evaluation for the given node. This can be used to force a run of the scheduling logic. -https://www.nomadproject.io/api/nodes.html#create-node-evaluation +https://developer.hashicorp.com/nomad/api-docs/nodes#create-node-evaluation Example: @@ -56,7 +56,7 @@ my_nomad.node.evaluate_node('ed1bbae7-c38a-df2d-1de7-50dbc753fc98') This endpoint toggles the drain mode of the node. When draining is enabled, no further allocations will be assigned to this node, and existing allocations will be migrated to new nodes. -https://www.nomadproject.io/api/nodes.html#drain-node +https://developer.hashicorp.com/nomad/api-docs/nodes#drain-node Example: @@ -76,7 +76,7 @@ my_nomad.node.drain_node('ed1bbae7-c38a-df2d-1de7-50dbc753fc98', enable=False) This endpoint toggles the drain mode of the node. When draining is enabled, no further allocations will be assigned to this node, and existing allocations will be migrated to new nodes. -https://www.nomadproject.io/api/nodes.html#drain-node +https://developer.hashicorp.com/nomad/api-docs/nodes#drain-node Example: @@ -102,7 +102,7 @@ my_nomad.node.drain_node_with_spec('ed1bbae7-c38a-df2d-1de7-50dbc753fc98', drain This endpoint toggles the eligibility of the node. When a node's "SchedulingEligibility" is ineligible the scheduler will not consider it for new placements. -https://www.nomadproject.io/api/nodes.html#toggle-node-eligibility +https://developer.hashicorp.com/nomad/api-docs/nodes#toggle-node-eligibility Example: @@ -122,7 +122,7 @@ my_nomad.node.eligible_node('ed1bbae7-c38a-df2d-1de7-50dbc753fc98', eligible=Tru This endpoint purges a node from the system. Nodes can still join the cluster if they are alive. -https://www.nomadproject.io/api/nodes.html#purge-node +https://developer.hashicorp.com/nomad/api-docs/nodes#purge-node Example: diff --git a/docs/api/nodes.md b/docs/api/nodes.md index 03cbc78..825957e 100644 --- a/docs/api/nodes.md +++ b/docs/api/nodes.md @@ -4,7 +4,7 @@ This endpoint lists all nodes registered with Nomad. -https://www.nomadproject.io/api/nodes.html#list-nodes +https://developer.hashicorp.com/nomad/api-docs/nodes#list-nodes Example: diff --git a/docs/api/regions.md b/docs/api/regions.md index 54b7754..f68c230 100644 --- a/docs/api/regions.md +++ b/docs/api/regions.md @@ -2,7 +2,7 @@ ### List regions -https://www.nomadproject.io/api/regions.html#list-regions +https://developer.hashicorp.com/nomad/api-docs/regions#list-regions Example: diff --git a/docs/api/sentinel.md b/docs/api/sentinel.md index 2693c28..1fe7148 100644 --- a/docs/api/sentinel.md +++ b/docs/api/sentinel.md @@ -8,7 +8,7 @@ You must have nomad **ENTERPRISE Edition** Get all policies -https://www.nomadproject.io/api/sentinel-policies.html#list-policies +https://developer.hashicorp.com/nomad/api-docs/sentinel-policies#list-policies Example: @@ -24,7 +24,7 @@ policies = my_nomad.sentinel.get_policies() Create a policy -https://www.nomadproject.io/api/sentinel-policies.html#create-or-update-policy +https://developer.hashicorp.com/nomad/api-docs/sentinel-policies#create-or-update-policy Example: ``` @@ -47,7 +47,7 @@ my_nomad.sentinel.create_policy("my-policy", policy) Update specific policy -https://www.nomadproject.io/api/sentinel-policies.html#create-or-update-policy +https://developer.hashicorp.com/nomad/api-docs/sentinel-policies#create-or-update-policy Example: @@ -71,7 +71,7 @@ my_nomad.sentinel.update_policy("my-policy", policy) Get specific policy -https://www.nomadproject.io/api/sentinel-policies.html#read-policy +https://developer.hashicorp.com/nomad/api-docs/sentinel-policies#read-policy Example: @@ -87,7 +87,7 @@ policy = my_nomad.sentinel.get_policy("my-policy") Delete specific policy -https://www.nomadproject.io/api/sentinel-policies.html#delete-policy +https://developer.hashicorp.com/nomad/api-docs/sentinel-policies#delete-policy Example: diff --git a/docs/api/status.md b/docs/api/status.md index ed5cc97..6e30d5d 100644 --- a/docs/api/status.md +++ b/docs/api/status.md @@ -4,7 +4,7 @@ This endpoint returns the address of the current leader in the region. -https://www.nomadproject.io/api/status.html#read-leader +https://developer.hashicorp.com/nomad/api-docs/status#read-leader Example: @@ -20,7 +20,7 @@ leader = my_nomad.status.leader.get_leader() This endpoint returns the set of raft peers in the region. -https://www.nomadproject.io/api/status.html#list-peers +https://developer.hashicorp.com/nomad/api-docs/status#list-peers Example: diff --git a/docs/api/system.md b/docs/api/system.md index ead5bc0..f836fe6 100644 --- a/docs/api/system.md +++ b/docs/api/system.md @@ -4,7 +4,7 @@ This endpoint initializes a garbage collection of jobs, evaluations, allocations, and nodes. This is an asynchronous operation. -https://www.nomadproject.io/api/system.html#force-gc +https://developer.hashicorp.com/nomad/api-docs/system#force-gc Example: @@ -20,7 +20,7 @@ my_nomad.system.initiate_garbage_collection() This endpoint reconciles the summaries of all registered jobs. -https://www.nomadproject.io/api/system.html#reconcile-summaries +https://developer.hashicorp.com/nomad/api-docs/system#reconcile-summaries Example: diff --git a/docs/api/validate.md b/docs/api/validate.md index 8b84022..ce05d91 100644 --- a/docs/api/validate.md +++ b/docs/api/validate.md @@ -4,7 +4,7 @@ This endpoint validates a Nomad job file. The local Nomad agent forwards the request to a server. In the event a server can't be reached the agent verifies the job file locally but skips validating driver configurations. -https://www.nomadproject.io/api/validate.html#validate-job +https://developer.hashicorp.com/nomad/api-docs/validate#validate-job Example: diff --git a/mkdocs.yml b/mkdocs.yml index 4119c91..7f7575b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -29,5 +29,7 @@ pages: - Namespace: 'api/namespace.md' - Namespaces: 'api/namespaces.md' - Sentinel: 'api/sentinel.md' + - Variable: 'api/variable.md' + - Variables: 'api/variables.md' - Validate: 'api/validate.md' - Contributing: 'CONTRIBUTING.md' diff --git a/nomad/__init__.py b/nomad/__init__.py index ca5d767..fdb4f16 100644 --- a/nomad/__init__.py +++ b/nomad/__init__.py @@ -1,55 +1,67 @@ -import nomad.api as api +"""Nomad Python library""" import os - - -class Nomad(object): - - def __init__(self, - host='127.0.0.1', - secure=False, - port=4646, - address=os.getenv('NOMAD_ADDR', None), - namespace=os.getenv('NOMAD_NAMESPACE', None), - token=os.getenv('NOMAD_TOKEN', None), - timeout=5, - region=os.getenv('NOMAD_REGION', None), - version='v1', - verify=False, - cert=(os.getenv('NOMAD_CLIENT_CERT', None), - os.getenv('NOMAD_CLIENT_KEY', None)), - session=None): - """ Nomad api client - - https://github.com/jrxFive/python-nomad/ - - optional arguments: - - host (defaults 127.0.0.1), string ip or name of the nomad api server/agent that will be used. - - port (defaults 4646), integer port that will be used to connect. - - secure (defaults False), define if the protocol is secured or not (https or http) - - version (defaults v1), vesion of the api of nomad. - - verify (defaults False), verify the certificate when tls/ssl is enabled - at nomad. - - cert (defaults empty), cert, or key and cert file to validate the certificate - configured at nomad. - - region (defaults None), version of the region to use. It will be used then - regions of the current agent of the connection. - - namespace (defaults to None), Specifies the enterpise namespace that will - be use to deploy or to ask info to nomad. - - token (defaults to None), Specifies to append ACL token to the headers to - make authentication on secured based nomad environemnts. - - session (defaults to None), allows for injecting a prepared requests.Session object that - all requests to Nomad should use. - returns: Nomad api client object - - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException - - nomad.api.exceptions.URLNotAuthorizedNomadException +from typing import Optional + +import requests + +from nomad import api + + +class Nomad: # pylint: disable=too-many-public-methods,too-many-instance-attributes + """ + Nomad API + """ + + def __init__( # pylint: disable=too-many-arguments + self, + host: str = "127.0.0.1", + secure: bool = False, + port: int = 4646, + address: Optional[str] = os.getenv("NOMAD_ADDR", None), + user_agent: Optional[str] = None, + namespace: Optional[str] = os.getenv("NOMAD_NAMESPACE", None), + token: Optional[str] = os.getenv("NOMAD_TOKEN", None), + timeout: int = 5, + region: Optional[str] = os.getenv("NOMAD_REGION", None), + version: str = "v1", + verify: bool = False, + cert: tuple = (os.getenv("NOMAD_CLIENT_CERT", None), os.getenv("NOMAD_CLIENT_KEY", None)), + session: requests.Session = None, + ): + """Nomad api client + + https://github.com/jrxFive/python-nomad/ + + optional arguments: + - host (defaults 127.0.0.1), string ip or name of the nomad api server/agent that will be used. + - port (defaults 4646), integer port that will be used to connect. + - user_agent (defaults None), custom user agent for requests to Nomad. + - secure (defaults False), define if the protocol is secured or not (https or http) + - version (defaults v1), version of the api of nomad. + - verify (defaults False), verify the certificate when tls/ssl is enabled + at nomad. + - cert (defaults empty), cert, or key and cert file to validate the certificate + configured at nomad. + - region (defaults None), version of the region to use. It will be used then + regions of the current agent of the connection. + - namespace (defaults to None), Specifies the enterprise namespace that will + be use to deploy or to ask info to nomad. + - token (defaults to None), Specifies to append ACL token to the headers to + make authentication on secured based nomad environments. + - session (defaults to None), allows for injecting a prepared requests.Session object that + all requests to Nomad should use. + returns: Nomad api client object + + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException + - nomad.api.exceptions.URLNotAuthorizedNomadException """ self.host = host self.secure = secure self.port = port self.address = address + self.user_agent = user_agent self.region = region self.timeout = timeout self.version = version @@ -63,6 +75,7 @@ def __init__(self, "address": self.address, "uri": self.get_uri(), "port": self.port, + "user_agent": self.user_agent, "namespace": self.__namespace, "token": self.token, "timeout": self.timeout, @@ -102,122 +115,212 @@ def __init__(self, self._variables = api.Variables(**self.requester_settings) def get_uri(self): + """ + Get Nomad host + """ if self.secure: protocol = "https" else: protocol = "http" - return "{protocol}://{host}".format(protocol=protocol, host=self.host) + return f"{protocol}://{self.host}" def get_namespace(self): + """ + Get Nomad namaspace + """ return self.__namespace def get_token(self): + """ + Get Nomad token + """ return self.token @property def jobs(self): + """ + Jobs API + """ return self._jobs @property def job(self): + """ + Job API + """ return self._job @property def nodes(self): + """ + Nodes API + """ return self._nodes @property def node(self): + """ + Node API + """ return self._node @property def allocations(self): + """ + Allocations API + """ return self._allocations @property def allocation(self): + """ + Allocation API + """ return self._allocation @property def evaluations(self): + """ + Evaluations API + """ return self._evaluations @property def evaluation(self): + """ + Evaluation API + """ return self._evaluation @property def event(self): + """ + Event API + """ return self._event @property def agent(self): + """ + Agent API + """ return self._agent @property def client(self): + """ + Client API + """ return self._client @property def deployments(self): + """ + Deployments API + """ return self._deployments @property def deployment(self): + """ + Deployment API + """ return self._deployment @property def regions(self): + """ + Regions API + """ return self._regions @property def scaling(self): + """ + Scaling API + """ return self._scaling @property def status(self): + """ + Status API + """ return self._status @property def system(self): + """ + System API + """ return self._system @property def operator(self): + """ + Operator API + """ return self._operator @property def validate(self): + """ + Validate API + """ return self._validate @property def namespaces(self): + """ + Namespaces API + """ return self._namespaces @property def namespace(self): + """ + Namespace API + """ return self._namespace @property def acl(self): + """ + ACL API + """ return self._acl @property def sentinel(self): + """ + Sentinel API + """ return self._sentinel @property def search(self): + """ + Search API + """ return self._search @property def metrics(self): + """ + Metrics API + """ return self._metrics @property def variable(self): + """ + Variable API + """ return self._variable @property def variables(self): - return self._variables \ No newline at end of file + """ + Variables API + """ + return self._variables diff --git a/nomad/api/__init__.py b/nomad/api/__init__.py index f326865..3886570 100644 --- a/nomad/api/__init__.py +++ b/nomad/api/__init__.py @@ -1,3 +1,4 @@ +"""Nomad Python library""" import nomad.api.exceptions from nomad.api.acl import Acl from nomad.api.agent import Agent @@ -26,4 +27,4 @@ from nomad.api.system import System from nomad.api.validate import Validate from nomad.api.variable import Variable -from nomad.api.variables import Variables \ No newline at end of file +from nomad.api.variables import Variables diff --git a/nomad/api/acl.py b/nomad/api/acl.py index af23e80..9b3b024 100644 --- a/nomad/api/acl.py +++ b/nomad/api/acl.py @@ -1,4 +1,4 @@ -import nomad.api.exceptions +"""Nomad ACL: https://developer.hashicorp.com/nomad/api-docs/acl""" from nomad.api.base import Requester @@ -13,182 +13,182 @@ class Acl(Requester): ENDPOINT = "acl" def __init__(self, **kwargs): - super(Acl, self).__init__(**kwargs) + super().__init__(**kwargs) def __str__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __getattr__(self, item): raise AttributeError def generate_bootstrap(self): - """ Activate bootstrap token. + """Activate bootstrap token. - https://www.nomadproject.io/api/acl-tokens.html + https://www.nomadproject.io/api/acl-tokens.html - returns: dict + returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ return self.request("bootstrap", method="post").json() def get_tokens(self): - """ Get a list of tokens. + """Get a list of tokens. - https://www.nomadproject.io/api/acl-tokens.html + https://www.nomadproject.io/api/acl-tokens.html - returns: list + returns: list - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ return self.request("tokens", method="get").json() - def get_token(self, id): - """ Retrieve specific token. + def get_token(self, id_): + """Retrieve specific token. - https://www.nomadproject.io/api/acl-tokens.html + https://www.nomadproject.io/api/acl-tokens.html - returns: dict + returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request("token", id, method="get").json() + return self.request("token", id_, method="get").json() def get_self_token(self): - """ Retrieve self token used for auth. + """Retrieve self token used for auth. - https://www.nomadproject.io/api/acl-tokens.html + https://www.nomadproject.io/api/acl-tokens.html - returns: dict + returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ return self.request("token", "self", method="get").json() def create_token(self, token): - """ Create token. + """Create token. - https://www.nomadproject.io/api/acl-tokens.html + https://www.nomadproject.io/api/acl-tokens.html - arguments: - token - returns: dict + arguments: + token + returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ return self.request("token", json=token, method="post").json() - def delete_token(self, id): - """ Delete specific token. + def delete_token(self, id_): + """Delete specific token. - https://www.nomadproject.io/api/acl-tokens.html + https://www.nomadproject.io/api/acl-tokens.html - returns: Boolean + returns: Boolean - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request("token", id, method="delete").ok + return self.request("token", id_, method="delete").ok - def update_token(self, id, token): - """ Update token. + def update_token(self, id_, token): + """Update token. - https://www.nomadproject.io/api/acl-tokens.html + https://www.nomadproject.io/api/acl-tokens.html - arguments: - - AccdesorID - - token - returns: dict + arguments: + - AccdesorID + - token + returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request("token", id, json=token, method="post").json() + return self.request("token", id_, json=token, method="post").json() def get_policies(self): - """ Get a list of policies. + """Get a list of policies. - https://www.nomadproject.io/api/acl-policies.html + https://www.nomadproject.io/api/acl-policies.html - returns: list + returns: list - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ return self.request("policies", method="get").json() - def create_policy(self, id, policy): - """ Create policy. + def create_policy(self, id_, policy): + """Create policy. - https://www.nomadproject.io/api/acl-policies.html + https://www.nomadproject.io/api/acl-policies.html - arguments: - - policy - returns: request.Response + arguments: + - policy + returns: request.Response - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request("policy", id, json=policy, method="post") + return self.request("policy", id_, json=policy, method="post") - def get_policy(self, id): - """ Get a spacific. + def get_policy(self, id_): + """Get a spacific. - https://www.nomadproject.io/api/acl-policies.html + https://www.nomadproject.io/api/acl-policies.html - returns: dict + returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request("policy", id, method="get").json() + return self.request("policy", id_, method="get").json() - def update_policy(self, id, policy): - """ Create policy. + def update_policy(self, id_, policy): + """Create policy. - https://www.nomadproject.io/api/acl-policies.html + https://www.nomadproject.io/api/acl-policies.html - arguments: - - name - - policy - returns: request.Response + arguments: + - name + - policy + returns: request.Response - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request("policy", id, json=policy, method="post") + return self.request("policy", id_, json=policy, method="post") - def delete_policy(self, id): - """ Delete specific policy. + def delete_policy(self, id_): + """Delete specific policy. - https://www.nomadproject.io/api/acl-policies.html + https://www.nomadproject.io/api/acl-policies.html - arguments: - - id - returns: Boolean + arguments: + - id + returns: Boolean - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request("policy", id, method="delete").ok + return self.request("policy", id_, method="delete").ok diff --git a/nomad/api/agent.py b/nomad/api/agent.py index c954c29..7ad412c 100644 --- a/nomad/api/agent.py +++ b/nomad/api/agent.py @@ -1,85 +1,84 @@ -import nomad.api.exceptions - +"""Nomad Agent: https://developer.hashicorp.com/nomad/api-docs/agent""" from nomad.api.base import Requester class Agent(Requester): - """The self endpoint is used to query the state of the target agent.""" + ENDPOINT = "agent" def __init__(self, **kwargs): - super(Agent, self).__init__(**kwargs) + super().__init__(**kwargs) def __str__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __getattr__(self, item): - msg = "{0} does not exist".format(item) + msg = f"{item} does not exist" raise AttributeError(msg) def get_agent(self): - """ Query the state of the target agent. + """Query the state of the target agent. - https://www.nomadproject.io/docs/http/agent-self.html + https://www.nomadproject.io/docs/http/agent-self.html - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ return self.request("self", method="get").json() def get_members(self): """Lists the known members of the gossip pool. - https://www.nomadproject.io/docs/http/agent-members.html + https://www.nomadproject.io/docs/http/agent-members.html - returns: list - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + returns: list + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ return self.request("members", method="get").json() def get_servers(self): - """ Lists the known members of the gossip pool. + """Lists the known members of the gossip pool. - https://www.nomadproject.io/docs/http/agent-servers.html + https://www.nomadproject.io/docs/http/agent-servers.html - returns: list - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + returns: list + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ return self.request("servers", method="get").json() def join_agent(self, addresses): """Initiate a join between the agent and target peers. - https://www.nomadproject.io/docs/http/agent-join.html + https://www.nomadproject.io/docs/http/agent-join.html - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ params = {"address": addresses} return self.request("join", params=params, method="post").json() def update_servers(self, addresses): """Updates the list of known servers to the provided list. - Replaces all previous server addresses with the new list. + Replaces all previous server addresses with the new list. - https://www.nomadproject.io/docs/http/agent-servers.html + https://www.nomadproject.io/docs/http/agent-servers.html - returns: 200 status code - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + returns: 200 status code + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ params = {"address": addresses} return self.request("servers", params=params, method="post").status_code @@ -87,12 +86,12 @@ def update_servers(self, addresses): def force_leave(self, node): """Force a failed gossip member into the left state. - https://www.nomadproject.io/docs/http/agent-force-leave.html + https://www.nomadproject.io/docs/http/agent-force-leave.html - returns: 200 status code - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + returns: 200 status code + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ params = {"node": node} return self.request("force-leave", params=params, method="post").status_code diff --git a/nomad/api/allocation.py b/nomad/api/allocation.py index 2967d30..87d64d9 100644 --- a/nomad/api/allocation.py +++ b/nomad/api/allocation.py @@ -1,3 +1,4 @@ +"""Nomad allocation: https://developer.hashicorp.com/nomad/api-docs/allocations""" import nomad.api.exceptions from nomad.api.base import Requester @@ -15,13 +16,13 @@ class Allocation(Requester): ENDPOINT = "allocation" def __init__(self, **kwargs): - super(Allocation, self).__init__(**kwargs) + super().__init__(**kwargs) def __str__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __getattr__(self, item): raise AttributeError @@ -32,6 +33,7 @@ def __contains__(self, item): if response["ID"] == item: return True + return False except nomad.api.exceptions.URLNotFoundNomadException: return False @@ -41,29 +43,30 @@ def __getitem__(self, item): if response["ID"] == item: return response - except nomad.api.exceptions.URLNotFoundNomadException: raise KeyError + except nomad.api.exceptions.URLNotFoundNomadException as exc: + raise KeyError from exc - def get_allocation(self, id): - """ Query a specific allocation. + def get_allocation(self, id_: str): + """Query a specific allocation. - https://www.nomadproject.io/docs/http/alloc.html + https://www.nomadproject.io/docs/http/alloc.html - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request(id, method="get").json() + return self.request(id_, method="get").json() - def stop_allocation(self, id): - """ Stop a specific allocation. + def stop_allocation(self, id_: str): + """Stop a specific allocation. - https://www.nomadproject.io/api-docs/allocations/#stop-allocation + https://www.nomadproject.io/api-docs/allocations/#stop-allocation - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request(id, "stop", method="post").json() + return self.request(id_, "stop", method="post").json() diff --git a/nomad/api/allocations.py b/nomad/api/allocations.py index e532f0e..128b072 100644 --- a/nomad/api/allocations.py +++ b/nomad/api/allocations.py @@ -1,8 +1,10 @@ +"""Nomad allocation: https://developer.hashicorp.com/nomad/api-docs/allocations""" +from typing import Optional + from nomad.api.base import Requester class Allocations(Requester): - """ The allocations endpoint is used to query the status of allocations. By default, the agent's local region is used; another region can be @@ -10,16 +12,17 @@ class Allocations(Requester): https://www.nomadproject.io/docs/http/allocs.html """ + ENDPOINT = "allocations" def __init__(self, **kwargs): - super(Allocations, self).__init__(**kwargs) + super().__init__(**kwargs) def __str__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __getattr__(self, item): raise AttributeError @@ -32,22 +35,48 @@ def __iter__(self): response = self.get_allocations() return iter(response) - def get_allocations(self, prefix=None, namespace=None): - """ Lists all the allocations. - - https://www.nomadproject.io/docs/http/allocs.html - arguments: - - prefix :(str) optional, specifies a string to filter allocations on based on an prefix. - This is specified as a querystring parameter. - - namespace :(str) optional, specifies the target namespace. Specifying * would return all jobs. - This is specified as a querystring parameter. - returns: list - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException - """ - params = {"prefix": prefix} - if namespace: - params["namespace"] = namespace + def get_allocations( # pylint: disable=too-many-arguments + self, + prefix: Optional[str] = None, + next_token: Optional[str] = None, + per_page: Optional[int] = None, + filter_: Optional[str] = None, + namespace: Optional[str] = None, + resources: Optional[bool] = None, + task_states: Optional[bool] = None, + reverse: Optional[bool] = None, + ): + """Lists all the allocations. + https://www.nomadproject.io/docs/http/allocs.html + arguments: + - prefix :(str) optional, specifies a string to filter allocations on based on an prefix. + This is specified as a querystring parameter. + - next_token :(str) optional. + This endpoint supports paging. The next_token parameter accepts a string which identifies the next + expected allocation. This value can be obtained from the X-Nomad-NextToken header from the previous + response. + - per_page :(int) optional + - filter_ :(str) optional + Name has a trailing underscore not to conflict with builtin function. + - namespace :(str) optional, specifies the target namespace. Specifying * would return all jobs. + This is specified as a querystring parameter. + - resources :(bool) optional + - task_states :(bool) optional + - reverse :(bool) optional + returns: list + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException + """ + params = { + "prefix": prefix, + "next_token": next_token, + "per_page": per_page, + "filter": filter_, + "namespace": namespace, + "resources": resources, + "task_states": task_states, + "reverse": reverse, + } return self.request(method="get", params=params).json() diff --git a/nomad/api/base.py b/nomad/api/base.py index e0fae4d..87f3714 100644 --- a/nomad/api/base.py +++ b/nomad/api/base.py @@ -1,17 +1,36 @@ +"""Requester""" +from typing import Optional + import requests -import nomad.api.exceptions -from requests.packages.urllib3.exceptions import InsecureRequestWarning -requests.packages.urllib3.disable_warnings(InsecureRequestWarning) +import nomad.api.exceptions -class Requester(object): +class Requester: # pylint: disable=too-many-instance-attributes,too-few-public-methods + """ + Base object for endpoints + """ ENDPOINT = "" - def __init__(self, address=None, uri='http://127.0.0.1', port=4646, namespace=None, token=None, timeout=5, version='v1', verify=False, cert=(), region=None, session=None, **kwargs): + def __init__( # pylint: disable=too-many-arguments + self, + address: Optional[str] = None, + uri: Optional[str] = "http://127.0.0.1", + port: int = 4646, + user_agent: Optional[str] = None, + namespace: Optional[str] = None, + token: Optional[str] = None, + timeout: int = 5, + version: str = "v1", + verify: bool = False, + cert: tuple = (), + region: Optional[str] = None, + session: requests.Session = None, + ): self.uri = uri self.port = port + self.user_agent = user_agent self.namespace = namespace self.token = token self.timeout = timeout @@ -24,28 +43,32 @@ def __init__(self, address=None, uri='http://127.0.0.1', port=4646, namespace=No def _endpoint_builder(self, *args): if args: - u = "/".join(args) - return "{v}/".format(v=self.version) + u + args_str = "/".join(args) + return f"{self.version}/" + args_str + + return "/" def _required_namespace(self, endpoint): required_namespace = [ - "job", - "jobs", - "allocation", - "allocations", - "deployment", - "deployments", - "acl", - "client", - "node" - ] + "job", + "jobs", + "allocation", + "allocations", + "deployment", + "deployments", + "acl", + "client", + "node", + "variable", + "variables", + ] # split 0 -> Api Version # split 1 -> Working Endpoint - ENDPOINT_NAME = 1 endpoint_split = endpoint.split("/") try: - required = endpoint_split[ENDPOINT_NAME] in required_namespace - except: + endpoint_name = 1 + required = endpoint_split[endpoint_name] in required_namespace + except IndexError: required = False return required @@ -54,27 +77,32 @@ def _url_builder(self, endpoint): url = self.address if self.address is None: - url = "{uri}:{port}".format(uri=self.uri, port=self.port) - - url = "{url}/{endpoint}".format(url=url, endpoint=endpoint) + url = f"{self.uri}:{self.port}" + url = f"{url}/{endpoint}" return url def _query_string_builder(self, endpoint, params=None): - qs = {} + query_string = {} if not isinstance(params, dict): params = {} + # Remove parameters that are None + params = {key: val for key, val in params.items() if val is not None} + if ("namespace" not in params) and (self.namespace and self._required_namespace(endpoint)): - qs["namespace"] = self.namespace + query_string["namespace"] = self.namespace if "region" not in params and self.region: - qs["region"] = self.region + query_string["region"] = self.region - return qs + return query_string def request(self, *args, **kwargs): + """ + Send HTTP Request (wrapper around requests) + """ endpoint = self._endpoint_builder(self.ENDPOINT, *args) response = self._request( endpoint=endpoint, @@ -85,26 +113,40 @@ def request(self, *args, **kwargs): headers=kwargs.get("headers", None), allow_redirects=kwargs.get("allow_redirects", False), timeout=kwargs.get("timeout", self.timeout), - stream=kwargs.get("stream", False) + stream=kwargs.get("stream", False), ) return response - def _request(self, method, endpoint, params=None, data=None, json=None, headers=None, allow_redirects=None, timeout=None, stream=False): + def _request( # pylint: disable=too-many-arguments, too-many-branches + self, + method, + endpoint, + params=None, + data=None, + json=None, + headers=None, + allow_redirects=None, + timeout=None, + stream=False, + ): url = self._url_builder(endpoint) - qs = self._query_string_builder(endpoint=endpoint, params=params) + query_string = self._query_string_builder(endpoint=endpoint, params=params) if params: - params.update(qs) + params.update(query_string) else: - params = qs + params = query_string if self.token: - try: + if headers is not None: headers["X-Nomad-Token"] = self.token - except TypeError: + else: headers = {"X-Nomad-Token": self.token} + if self.user_agent: + headers["User-Agent"] = self.user_agent + response = None try: @@ -156,16 +198,16 @@ def _request(self, method, endpoint, params=None, data=None, json=None, headers= if response.ok: return response - elif response.status_code == 400: + if response.status_code == 400: raise nomad.api.exceptions.BadRequestNomadException(response) - elif response.status_code == 403: + if response.status_code == 403: raise nomad.api.exceptions.URLNotAuthorizedNomadException(response) - elif response.status_code == 404: + if response.status_code == 404: raise nomad.api.exceptions.URLNotFoundNomadException(response) - elif response.status_code == 409: + if response.status_code == 409: raise nomad.api.exceptions.VariableConflict(response) - else: - raise nomad.api.exceptions.BaseNomadException(response) + + raise nomad.api.exceptions.BaseNomadException(response) except requests.exceptions.ConnectionError as error: if all([stream, timeout]): diff --git a/nomad/api/client.py b/nomad/api/client.py index 4178f57..cefbd33 100644 --- a/nomad/api/client.py +++ b/nomad/api/client.py @@ -1,7 +1,13 @@ +# we want to have backward compatibility here +# pylint: disable=invalid-name,too-many-instance-attributes,too-many-arguments +"""Nomad Client: https://developer.hashicorp.com/nomad/api-docs/client""" from nomad.api.base import Requester -class Client(object): +class Client: + """ + The /client endpoints are used to interact with the Nomad clients. + """ def __init__(self, **kwargs): self.ls = ls(**kwargs) @@ -16,13 +22,14 @@ def __init__(self, **kwargs): self.gc_all_allocations = gc_all_allocations(**kwargs) def __str__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __getattr__(self, item): - raise AttributeError + msg = f"{item} does not exist" + raise AttributeError(msg) class ls(Requester): @@ -38,25 +45,25 @@ class ls(Requester): ENDPOINT = "client/fs/ls" def __init__(self, **kwargs): - super(ls, self).__init__(**kwargs) + super().__init__(**kwargs) - def list_files(self, id=None, path="/"): - """ List files in an allocation directory. + def list_files(self, id_=None, path="/"): + """List files in an allocation directory. - https://www.nomadproject.io/docs/http/client-fs-ls.html + https://www.nomadproject.io/docs/http/client-fs-ls.html - arguments: - - id - - path - returns: list - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + - id_ + - path + returns: list + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - if id: - return self.request(id, params={"path": path}, method="get").json() - else: - return self.request(params={"path": path}, method="get").json() + if id_: + return self.request(id_, params={"path": path}, method="get").json() + + return self.request(params={"path": path}, method="get").json() class cat(Requester): @@ -73,25 +80,25 @@ class cat(Requester): ENDPOINT = "client/fs/cat" def __init__(self, **kwargs): - super(cat, self).__init__(**kwargs) + super().__init__(**kwargs) - def read_file(self, id=None, path="/"): - """ Read contents of a file in an allocation directory. + def read_file(self, id_=None, path="/"): + """Read contents of a file in an allocation directory. - https://www.nomadproject.io/docs/http/client-fs-cat.html + https://www.nomadproject.io/docs/http/client-fs-cat.html - arguments: - - id - - path - returns: (str) text - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + - id_ + - path + returns: (str) text + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - if id: - return self.request(id, params={"path": path}, method="get").text - else: - return self.request(params={"path": path}, method="get").text + if id_: + return self.request(id_, params={"path": path}, method="get").text + + return self.request(params={"path": path}, method="get").text class read_at(Requester): @@ -105,29 +112,25 @@ class read_at(Requester): ENDPOINT = "client/fs/readat" def __init__(self, **kwargs): - super(read_at, self).__init__(**kwargs) - - def read_file_offset(self, id, offset, limit, path="/"): - """ Read contents of a file in an allocation directory. - - https://www.nomadproject.io/docs/http/client-fs-cat.html - - arguments: - - id: (str) allocation_id required - - offset: (int) required - - limit: (int) required - - path: (str) optional - returns: (str) text - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.BadRequestNomadException + super().__init__(**kwargs) + + def read_file_offset(self, id_, offset, limit, path="/"): + """Read contents of a file in an allocation directory. + + https://www.nomadproject.io/docs/http/client-fs-cat.html + + arguments: + - id_: (str) allocation_id required + - offset: (int) required + - limit: (int) required + - path: (str) optional + returns: (str) text + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.BadRequestNomadException """ - params = { - "path": path, - "offset": offset, - "limit": limit - } - return self.request(id, params=params, method="get").text + params = {"path": path, "offset": offset, "limit": limit} + return self.request(id_, params=params, method="get").text class stream_file(Requester): @@ -141,29 +144,25 @@ class stream_file(Requester): ENDPOINT = "client/fs/stream" def __init__(self, **kwargs): - super(stream_file, self).__init__(**kwargs) - - def stream(self, id, offset, origin, path="/"): - """ This endpoint streams the contents of a file in an allocation directory. - - https://www.nomadproject.io/api/client.html#stream-file - - arguments: - - id: (str) allocation_id required - - offset: (int) required - - origin: (str) either start|end - - path: (str) optional - returns: (str) text - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.BadRequestNomadException + super().__init__(**kwargs) + + def stream(self, id_, offset, origin, path="/"): + """This endpoint streams the contents of a file in an allocation directory. + + https://www.nomadproject.io/api/client.html#stream-file + + arguments: + - id_: (str) allocation_id required + - offset: (int) required + - origin: (str) either start|end + - path: (str) optional + returns: (str) text + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.BadRequestNomadException """ - params = { - "path": path, - "offset": offset, - "origin": origin - } - return self.request(id, params=params, method="get").text + params = {"path": path, "offset": offset, "origin": origin} + return self.request(id_, params=params, method="get").text class stream_logs(Requester): @@ -177,41 +176,33 @@ class stream_logs(Requester): ENDPOINT = "client/fs/logs" def __init__(self, **kwargs): - super(stream_logs, self).__init__(**kwargs) - - def stream(self, id, task, type, follow=False, offset=0, origin="start", plain=False): - """ This endpoint streams a task's stderr/stdout logs. - - https://www.nomadproject.io/api/client.html#stream-logs - - arguments: - - id: (str) allocation_id required - - task: (str) name of the task inside the allocation to stream logs from - - type: (str) Specifies the stream to stream. Either "stderr|stdout" - - follow: (bool) default false - - offset: (int) default 0 - - origin: (str) either start|end, default "start" - - plain: (bool) Return just the plain text without framing. default False - returns: (str) text - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.BadRequestNomadException + super().__init__(**kwargs) + + def stream(self, id_, task, type_, follow=False, offset=0, origin="start", plain=False): + """This endpoint streams a task's stderr/stdout logs. + + https://www.nomadproject.io/api/client.html#stream-logs + + arguments: + - id_: (str) allocation_id required + - task: (str) name of the task inside the allocation to stream logs from + - type_: (str) Specifies the stream to stream. Either "stderr|stdout" + - follow: (bool) default false + - offset: (int) default 0 + - origin: (str) either start|end, default "start" + - plain: (bool) Return just the plain text without framing. default False + returns: (str) text + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.BadRequestNomadException """ - params = { - "task": task, - "type": type, - "follow": follow, - "offset": offset, - "origin": origin, - "plain": plain - } - return self.request(id, params=params, method="get").text + params = {"task": task, "type": type_, "follow": follow, "offset": offset, "origin": origin, "plain": plain} + return self.request(id_, params=params, method="get").text class stat(Requester): - """ - The /fs/stat endpoint is used to show stat information + The /fs/stat endpoint is used to show stat information This API endpoint is hosted by the Nomad client and requests have to be made to the Nomad client where the particular allocation was placed. @@ -221,29 +212,28 @@ class stat(Requester): ENDPOINT = "client/fs/stat" def __init__(self, **kwargs): - super(stat, self).__init__(**kwargs) + super().__init__(**kwargs) - def stat_file(self, id=None, path="/"): - """ Stat a file in an allocation directory. + def stat_file(self, id_=None, path="/"): + """Stat a file in an allocation directory. - https://www.nomadproject.io/docs/http/client-fs-stat.html + https://www.nomadproject.io/docs/http/client-fs-stat.html - arguments: - - id - - path - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + - id_ + - path + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - if id: - return self.request(id, params={"path": path}, method="get").json() - else: - return self.request(params={"path": path}, method="get").json() + if id_: + return self.request(id_, params={"path": path}, method="get").json() + return self.request(params={"path": path}, method="get").json() -class stats(Requester): +class stats(Requester): """ The /stats endpoint queries the actual resources consumed on a node. The API endpoint is hosted by the Nomad client and requests have to @@ -255,28 +245,28 @@ class stats(Requester): ENDPOINT = "client/stats" def __init__(self, **kwargs): - super(stats, self).__init__(**kwargs) + super().__init__(**kwargs) def read_stats(self, node_id=None): - """ Query the actual resources consumed on a node. + """ + Query the actual resources consumed on a node. - https://www.nomadproject.io/api/client.html#read-stats + https://www.nomadproject.io/api/client.html#read-stats - arguments: - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ return self.request(params={"node_id": node_id}, method="get").json() class allocation(Requester): - """ The allocation/:alloc_id/stats endpoint is used to query the actual - resources consumed by an allocation. The API endpoint is hosted by the - Nomad client and requests have to be made to the nomad client whose + resources consumed by an allocation. The API endpoint is hosted by the + Nomad client and requests have to be made to the nomad client whose resource usage metrics are of interest. https://www.nomadproject.io/api/client.html#read-allocation @@ -285,32 +275,32 @@ class allocation(Requester): ENDPOINT = "client/allocation" def __init__(self, **kwargs): - super(allocation, self).__init__(**kwargs) + super().__init__(**kwargs) - def read_allocation_stats(self, id): - """ Query the actual resources consumed by an allocation. + def read_allocation_stats(self, id_): + """Query the actual resources consumed by an allocation. - https://www.nomadproject.io/api/client.html#read-allocation + https://www.nomadproject.io/api/client.html#read-allocation - arguments: - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request(id, "stats", method="get").json() + return self.request(id_, "stats", method="get").json() - def restart_allocation(self, id): - """ Restart a specific allocation. + def restart_allocation(self, id_): + """Restart a specific allocation. - https://www.nomadproject.io/api-docs/allocations/#restart-allocation + https://www.nomadproject.io/api-docs/allocations/#restart-allocation - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request(id, "restart", method="post").json() + return self.request(id_, "restart", method="post").json() class gc_allocation(Requester): @@ -324,24 +314,23 @@ class gc_allocation(Requester): ENDPOINT = "client/allocation" def __init__(self, **kwargs): - super(gc_allocation, self).__init__(**kwargs) + super().__init__(**kwargs) - def garbage_collect(self, id): - """ This endpoint forces a garbage collection of a particular, stopped allocation on a node. + def garbage_collect(self, id_): + """This endpoint forces a garbage collection of a particular, stopped allocation on a node. - https://www.nomadproject.io/api/client.html#gc-allocation + https://www.nomadproject.io/api/client.html#gc-allocation - arguments: - - id: (str) full allocation_id - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + - id_: (str) full allocation_id + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - self.request(id, "gc", method="get") + self.request(id_, "gc", method="get") class gc_all_allocations(Requester): - """ This endpoint forces a garbage collection of all stopped allocations on a node. @@ -351,16 +340,16 @@ class gc_all_allocations(Requester): ENDPOINT = "client/gc" def __init__(self, **kwargs): - super(gc_all_allocations, self).__init__(**kwargs) + super().__init__(**kwargs) def garbage_collect(self, node_id=None): - """ This endpoint forces a garbage collection of all stopped allocations on a node. + """This endpoint forces a garbage collection of all stopped allocations on a node. - https://www.nomadproject.io/api/client.html#gc-all-allocation + https://www.nomadproject.io/api/client.html#gc-all-allocation - arguments: - - node_id: (str) full allocation_id - raises: - - nomad.api.exceptions.BaseNomadException + arguments: + - node_id: (str) full allocation_id + raises: + - nomad.api.exceptions.BaseNomadException """ self.request(params={"node_id": node_id}, method="get") diff --git a/nomad/api/deployment.py b/nomad/api/deployment.py index 238bf2f..2b2432c 100644 --- a/nomad/api/deployment.py +++ b/nomad/api/deployment.py @@ -1,3 +1,4 @@ +"""Nomad Deployment: https://developer.hashicorp.com/nomad/api-docs/deployments""" import nomad.api.exceptions from nomad.api.base import Requester @@ -10,156 +11,162 @@ class Deployment(Requester): https://www.nomadproject.io/docs/http/deployments.html """ + ENDPOINT = "deployment" def __init__(self, **kwargs): - super(Deployment, self).__init__(**kwargs) + super().__init__(**kwargs) def __str__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __getattr__(self, item): - msg = "{0} does not exist".format(item) + msg = f"{item} does not exist" raise AttributeError(msg) def __contains__(self, item): - try: - d = self.get_deployment(item) + self.get_deployment(item) return True except nomad.api.exceptions.URLNotFoundNomadException: return False def __getitem__(self, item): - try: - d = self.get_deployment(item) - - if d["ID"] == item: - return d - except nomad.api.exceptions.URLNotFoundNomadException: + deployment = self.get_deployment(item) + if deployment["ID"] == item: + return deployment raise KeyError + except nomad.api.exceptions.URLNotFoundNomadException as exp: + raise KeyError from exp - def get_deployment(self, id): - """ This endpoint reads information about a specific deployment by ID. + def get_deployment(self, id_): + """This endpoint reads information about a specific deployment by ID. - https://www.nomadproject.io/docs/http/deployments.html + https://www.nomadproject.io/docs/http/deployments.html - arguments: - - id - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + - id_ + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request(id, method="get").json() + return self.request(id_, method="get").json() - def get_deployment_allocations(self, id): - """ This endpoint lists the allocations created or modified for the given deployment. + def get_deployment_allocations(self, id_): + """This endpoint lists the allocations created or modified for the given deployment. - https://www.nomadproject.io/docs/http/deployments.html + https://www.nomadproject.io/docs/http/deployments.html - arguments: - - id - returns: list of dicts - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + - id_ + returns: list of dicts + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request("allocations", id, method="get").json() + return self.request("allocations", id_, method="get").json() - def fail_deployment(self, id): - """ This endpoint is used to mark a deployment as failed. This should be done to force the scheduler to stop - creating allocations as part of the deployment or to cause a rollback to a previous job version. + def fail_deployment(self, id_): + """This endpoint is used to mark a deployment as failed. This should be done to force the scheduler to stop + creating allocations as part of the deployment or to cause a rollback to a previous job version. - https://www.nomadproject.io/docs/http/deployments.html + https://www.nomadproject.io/docs/http/deployments.html - arguments: - - id - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + - id_ + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - fail_json = {"DeploymentID": id} - return self.request("fail", id, json=fail_json, method="post").json() - - def pause_deployment(self, id, pause): - """ This endpoint is used to pause or unpause a deployment. - This is done to pause a rolling upgrade or resume it. - - https://www.nomadproject.io/docs/http/deployments.html - - arguments: - - id - - pause, Specifies whether to pause or resume the deployment. - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + fail_json = {"DeploymentID": id_} + return self.request("fail", id_, json=fail_json, method="post").json() + + def pause_deployment(self, id_, pause): + """This endpoint is used to pause or unpause a deployment. + This is done to pause a rolling upgrade or resume it. + + https://www.nomadproject.io/docs/http/deployments.html + + arguments: + - id_ + - pause, Specifies whether to pause or resume the deployment. + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - pause_json = {"Pause": pause, - "DeploymentID": id} - return self.request("pause", id, json=pause_json, method="post").json() - - def promote_deployment_all(self, id, all=True): - """ This endpoint is used to promote task groups that have canaries for a deployment. This should be done when - the placed canaries are healthy and the rolling upgrade of the remaining allocations should begin. - - https://www.nomadproject.io/docs/http/deployments.html - - arguments: - - id - - all, Specifies whether all task groups should be promoted. - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + pause_json = {"Pause": pause, "DeploymentID": id_} + return self.request("pause", id_, json=pause_json, method="post").json() + + def promote_deployment_all(self, id_, _all=True): + """This endpoint is used to promote task groups that have canaries for a deployment. This should be done when + the placed canaries are healthy and the rolling upgrade of the remaining allocations should begin. + + https://www.nomadproject.io/docs/http/deployments.html + + arguments: + - id_ + - _all, Specifies whether all task groups should be promoted. + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - promote_all_json = {"All": all, - "DeploymentID": id} - return self.request("promote", id, json=promote_all_json, method="post").json() - - def promote_deployment_groups(self, id, groups=list()): - """ This endpoint is used to promote task groups that have canaries for a deployment. This should be done when - the placed canaries are healthy and the rolling upgrade of the remaining allocations should begin. - - https://www.nomadproject.io/docs/http/deployments.html - - arguments: - - id - - groups, (list) Specifies a particular set of task groups that should be promoted - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + promote_all_json = {"All": _all, "DeploymentID": id_} + return self.request("promote", id_, json=promote_all_json, method="post").json() + + def promote_deployment_groups(self, id_, groups=None): + """This endpoint is used to promote task groups that have canaries for a deployment. This should be done when + the placed canaries are healthy and the rolling upgrade of the remaining allocations should begin. + + https://www.nomadproject.io/docs/http/deployments.html + + arguments: + - id_ + - groups, (list) Specifies a particular set of task groups that should be promoted + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - promote_groups_json = {"Groups": groups, - "DeploymentID": id} - return self.request("promote", id, json=promote_groups_json, method="post").json() - - def deployment_allocation_health(self, id, healthy_allocations=list(), unhealthy_allocations=list()): - """ This endpoint is used to set the health of an allocation that is in the deployment manually. In some use - cases, automatic detection of allocation health may not be desired. As such those task groups can be marked - with an upgrade policy that uses health_check = "manual". Those allocations must have their health marked - manually using this endpoint. Marking an allocation as healthy will allow the rolling upgrade to proceed. - Marking it as failed will cause the deployment to fail. - - https://www.nomadproject.io/docs/http/deployments.html - - arguments: - - id - - healthy_allocations, Specifies the set of allocation that should be marked as healthy. - - unhealthy_allocations, Specifies the set of allocation that should be marked as unhealthy. - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + if groups is None: + groups = [] + promote_groups_json = {"Groups": groups, "DeploymentID": id_} + return self.request("promote", id_, json=promote_groups_json, method="post").json() + + def deployment_allocation_health(self, id_, healthy_allocations=None, unhealthy_allocations=None): + """This endpoint is used to set the health of an allocation that is in the deployment manually. In some use + cases, automatic detection of allocation health may not be desired. As such those task groups can be marked + with an upgrade policy that uses health_check = "manual". Those allocations must have their health marked + manually using this endpoint. Marking an allocation as healthy will allow the rolling upgrade to proceed. + Marking it as failed will cause the deployment to fail. + + https://www.nomadproject.io/docs/http/deployments.html + + arguments: + - id_ + - healthy_allocations, Specifies the set of allocation that should be marked as healthy. + - unhealthy_allocations, Specifies the set of allocation that should be marked as unhealthy. + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - allocations = {"HealthyAllocationIDs": healthy_allocations, - "UnHealthyAllocationIDs": unhealthy_allocations, - "DeploymentID": id} - return self.request("allocation-health", id, json=allocations, method="post").json() + if healthy_allocations is None: + healthy_allocations = [] + + if unhealthy_allocations is None: + unhealthy_allocations = [] + + allocations = { + "HealthyAllocationIDs": healthy_allocations, + "UnHealthyAllocationIDs": unhealthy_allocations, + "DeploymentID": id_, + } + return self.request("allocation-health", id_, json=allocations, method="post").json() diff --git a/nomad/api/deployments.py b/nomad/api/deployments.py index 92b7145..91dd335 100644 --- a/nomad/api/deployments.py +++ b/nomad/api/deployments.py @@ -1,25 +1,26 @@ +"""Nomad Deployment: https://developer.hashicorp.com/nomad/api-docs/deployments""" import nomad.api.exceptions from nomad.api.base import Requester class Deployments(Requester): - """ The /deployment endpoints are used to query for and interact with deployments. https://www.nomadproject.io/docs/http/deployments.html """ + ENDPOINT = "deployments" def __init__(self, **kwargs): - super(Deployments, self).__init__(**kwargs) + super().__init__(**kwargs) def __str__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __getattr__(self, item): raise AttributeError @@ -35,42 +36,39 @@ def __iter__(self): def __contains__(self, item): try: deployments = self.get_deployments() - - for d in deployments: - if d["ID"] == item: + for deployment in deployments: + if deployment["ID"] == item: return True - else: - return False + + return False except nomad.api.exceptions.URLNotFoundNomadException: return False def __getitem__(self, item): try: deployments = self.get_deployments() - - for d in deployments: - if d["ID"] == item: - return d - else: - raise KeyError - except nomad.api.exceptions.URLNotFoundNomadException: + for deployment in deployments: + if deployment["ID"] == item: + return deployment raise KeyError + except nomad.api.exceptions.URLNotFoundNomadException as exc: + raise KeyError from exc def get_deployments(self, prefix="", namespace=None): - """ This endpoint lists all deployments. + """This endpoint lists all deployments. - https://www.nomadproject.io/docs/http/deployments.html + https://www.nomadproject.io/docs/http/deployments.html - optional_arguments: - - prefix, (default "") Specifies a string to filter deployments on based on an index prefix. - This is specified as a querystring parameter. - - namespace :(str) optional, specifies the target namespace. Specifying * would return all jobs. - This is specified as a querystring parameter. + optional_arguments: + - prefix, (default "") Specifies a string to filter deployments on based on an index prefix. + This is specified as a querystring parameter. + - namespace :(str) optional, specifies the target namespace. Specifying * would return all jobs. + This is specified as a querystring parameter. - returns: list of dicts - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + returns: list of dicts + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ params = {"prefix": prefix} if namespace: diff --git a/nomad/api/evaluation.py b/nomad/api/evaluation.py index 2aa6bb2..2f1546a 100644 --- a/nomad/api/evaluation.py +++ b/nomad/api/evaluation.py @@ -1,10 +1,10 @@ +"""Nomad Evaluation: https://developer.hashicorp.com/nomad/api-docs/evaluations""" import nomad.api.exceptions from nomad.api.base import Requester class Evaluation(Requester): - """ The evaluation endpoint is used to query a specific evaluations. By default, the agent's local region is used; another region can @@ -12,63 +12,62 @@ class Evaluation(Requester): https://www.nomadproject.io/docs/http/eval.html """ + ENDPOINT = "evaluation" def __init__(self, **kwargs): - super(Evaluation, self).__init__(**kwargs) + super().__init__(**kwargs) def __str__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __getattr__(self, item): - msg = "{0} does not exist".format(item) + msg = f"{item} does not exist" raise AttributeError(msg) def __contains__(self, item): - try: - e = self.get_evaluation(item) + self.get_evaluation(item) return True except nomad.api.exceptions.URLNotFoundNomadException: return False def __getitem__(self, item): - try: - e = self.get_evaluation(item) - - if e["ID"] == item: - return e - except nomad.api.exceptions.URLNotFoundNomadException: + evaluation = self.get_evaluation(item) + if evaluation["ID"] == item: + return evaluation raise KeyError + except nomad.api.exceptions.URLNotFoundNomadException as exc: + raise KeyError from exc - def get_evaluation(self, id): - """ Query a specific evaluation. + def get_evaluation(self, id_): + """Query a specific evaluation. - https://www.nomadproject.io/docs/http/eval.html + https://www.nomadproject.io/docs/http/eval.html - arguments: - - id - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + - id_ + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request(id, method="get").json() + return self.request(id_, method="get").json() - def get_allocations(self, id): - """ Query the allocations created or modified by an evaluation. + def get_allocations(self, id_): + """Query the allocations created or modified by an evaluation. - https://www.nomadproject.io/docs/http/eval.html + https://www.nomadproject.io/docs/http/eval.html - arguments: - - id - returns: list - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + - id_ + returns: list + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request(id, "allocations", method="get").json() + return self.request(id_, "allocations", method="get").json() diff --git a/nomad/api/evaluations.py b/nomad/api/evaluations.py index 8e581bc..dae0f61 100644 --- a/nomad/api/evaluations.py +++ b/nomad/api/evaluations.py @@ -1,9 +1,10 @@ +"""Nomad Evaluations: https://developer.hashicorp.com/nomad/api-docs/evaluations""" import nomad.api.exceptions from nomad.api.base import Requester -class Evaluations(Requester): +class Evaluations(Requester): """ The evaluations endpoint is used to query the status of evaluations. By default, the agent's local region is used; another region can @@ -11,16 +12,17 @@ class Evaluations(Requester): https://www.nomadproject.io/docs/http/evals.html """ + ENDPOINT = "evaluations" def __init__(self, **kwargs): - super(Evaluations, self).__init__(**kwargs) + super().__init__(**kwargs) def __str__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __getattr__(self, item): raise AttributeError @@ -29,11 +31,11 @@ def __contains__(self, item): try: evaluations = self.get_evaluations() - for e in evaluations: - if e["ID"] == item: + for evaluation in evaluations: + if evaluation["ID"] == item: return True - else: - return False + + return False except nomad.api.exceptions.URLNotFoundNomadException: return False @@ -45,29 +47,28 @@ def __getitem__(self, item): try: evaluations = self.get_evaluations() - for e in evaluations: - if e["ID"] == item: - return e - else: - raise KeyError - except nomad.api.exceptions.URLNotFoundNomadException: + for evaluation in evaluations: + if evaluation["ID"] == item: + return evaluation raise KeyError + except nomad.api.exceptions.URLNotFoundNomadException as exc: + raise KeyError from exc def __iter__(self): evaluations = self.get_evaluations() return iter(evaluations) def get_evaluations(self, prefix=None): - """ Lists all the evaluations. - - https://www.nomadproject.io/docs/http/evals.html - arguments: - - prefix :(str) optional, specifies a string to filter evaluations on based on an prefix. - This is specified as a querystring parameter. - returns: list - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + """Lists all the evaluations. + + https://www.nomadproject.io/docs/http/evals.html + arguments: + - prefix :(str) optional, specifies a string to filter evaluations on based on an prefix. + This is specified as a querystring parameter. + returns: list + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ params = {"prefix": prefix} return self.request(method="get", params=params).json() diff --git a/nomad/api/event.py b/nomad/api/event.py index 658c1ca..cafadb2 100644 --- a/nomad/api/event.py +++ b/nomad/api/event.py @@ -1,24 +1,23 @@ +"""Nomad Events: https://developer.hashicorp.com/nomad/api-docs/events""" import json import threading +import queue import requests from nomad.api.base import Requester -from nomad.api.exceptions import TimeoutNomadException -try: - import queue -except ImportError: - import Queue as queue - -class Event(object): +class Event: + """ + Nomad Event + """ def __str__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __getattr__(self, item): raise AttributeError @@ -27,7 +26,8 @@ def __init__(self, **kwargs): self.stream = stream(**kwargs) -class stream(Requester): +# backward compatibility +class stream(Requester): # pylint: disable=invalid-name """ The /event/stream endpoint is used to stream events generated by Nomad. @@ -37,9 +37,9 @@ class stream(Requester): ENDPOINT = "event/stream" def __init__(self, **kwargs): - super(stream, self).__init__(**kwargs) + super().__init__(**kwargs) - def _get_stream(self, method, params, timeout, event_queue, exit_event): + def _get_stream(self, method, params, timeout, event_queue, exit_event): # pylint: disable=too-many-arguments """ Used as threading target, to obtain json() value Args: @@ -66,7 +66,9 @@ def _get_stream(self, method, params, timeout, event_queue, exit_event): except requests.exceptions.ConnectionError: continue - def get_stream(self, index=0, topic=None, namespace=None, event_queue=None, timeout=None): + def get_stream( + self, index=0, topic=None, namespace=None, event_queue=None, timeout=None + ): # pylint: disable=too-many-arguments """ Usage: stream, stream_exit_event, events = n.event.stream.get_stream() @@ -81,7 +83,8 @@ def get_stream(self, index=0, topic=None, namespace=None, event_queue=None, time index: (int), Specifies the index to start streaming events from. If the requested index is no longer in the buffer the stream will start at the next available index. - topic: (None or dict), Specifies a topic to subscribe to and filter on. The default is to subscribe to all topics. + topic: (None or dict), Specifies a topic to subscribe to and filter on. + The default is to subscribe to all topics. Multiple topics may be specified by passing multiple topic parameters. A valid topic parameter includes a topic type and an optional filter_key separated by a colon :. As an example ?topic=Deployment:redis would subscribe to all Deployment events for a job redis. @@ -122,8 +125,8 @@ def get_stream(self, index=0, topic=None, namespace=None, event_queue=None, time "params": params, "timeout": timeout, "event_queue": event_queue, - "exit_event": stream_exit_event - } + "exit_event": stream_exit_event, + }, ) return _stream, stream_exit_event, event_queue diff --git a/nomad/api/exceptions.py b/nomad/api/exceptions.py index ca5e343..578c16f 100644 --- a/nomad/api/exceptions.py +++ b/nomad/api/exceptions.py @@ -1,16 +1,18 @@ +"""Internal library exceptions""" import requests class BaseNomadException(Exception): """General Error occurred when interacting with nomad API""" + def __init__(self, nomad_resp): self.nomad_resp = nomad_resp def __str__(self): if isinstance(self.nomad_resp, requests.Response) and hasattr(self.nomad_resp, "text"): - return 'The {0} was raised with following response: {1}.'.format(self.__class__.__name__, self.nomad_resp.text) - else: - return 'The {0} was raised due to the following error: {1}'.format(self.__class__.__name__, str(self.nomad_resp)) + return f"The {self.__class__.__name__} was raised with following response: {self.nomad_resp.text}." + + return f"The {self.__class__.__name__} was raised due to the following error: {self.nomad_resp}" class URLNotFoundNomadException(BaseNomadException): diff --git a/nomad/api/job.py b/nomad/api/job.py index b1c0a3a..03288db 100644 --- a/nomad/api/job.py +++ b/nomad/api/job.py @@ -1,304 +1,299 @@ +"""Nomad job: https://developer.hashicorp.com/nomad/api-docs/jobs""" import nomad.api.exceptions from nomad.api.base import Requester class Job(Requester): - """ The job endpoint is used for CRUD on a single job. By default, the agent's local region is used. https://www.nomadproject.io/docs/http/job.html """ + ENDPOINT = "job" def __init__(self, **kwargs): - super(Job, self).__init__(**kwargs) + super().__init__(**kwargs) def __str__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __getattr__(self, item): - msg = "{0} does not exist".format(item) + msg = f"{item} does not exist" raise AttributeError(msg) def __contains__(self, item): - try: - j = self.get_job(item) + self.get_job(item) return True except nomad.api.exceptions.URLNotFoundNomadException: return False def __getitem__(self, item): - try: - j = self.get_job(item) - - if j["ID"] == item: - return j - if j["Name"] == item: - return j - else: - raise KeyError - except nomad.api.exceptions.URLNotFoundNomadException: - raise KeyError - - def get_job(self, id, namespace=None): - """ Query a single job for its specification and status. + job = self.get_job(item) + if job["ID"] == item: + return job + if job["Name"] == item: + return job - https://www.nomadproject.io/docs/http/job.html - - arguments: - - id - - namespace :(str) optional, specifies the target namespace. Specifying * would return all jobs. - This is specified as a querystring parameter. - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + raise KeyError + except nomad.api.exceptions.URLNotFoundNomadException as exc: + raise KeyError from exc + + def get_job(self, id_, namespace=None): + """Query a single job for its specification and status. + + https://www.nomadproject.io/docs/http/job.html + + arguments: + - id_ + - namespace :(str) optional, specifies the target namespace. Specifying * would return all jobs. + This is specified as a querystring parameter. + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ params = {} if namespace: params["namespace"] = namespace - return self.request(id, method="get", params=params).json() + return self.request(id_, method="get", params=params).json() - def get_versions(self, id): - """ This endpoint reads information about all versions of a job. + def get_versions(self, id_): + """This endpoint reads information about all versions of a job. - https://www.nomadproject.io/docs/http/job.html + https://www.nomadproject.io/docs/http/job.html - arguments: - - id - returns: list of dicts - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + - id + returns: list of dicts + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request(id, "versions", method="get").json() + return self.request(id_, "versions", method="get").json() - def get_allocations(self, id): - """ Query the allocations belonging to a single job. + def get_allocations(self, id_): + """Query the allocations belonging to a single job. - https://www.nomadproject.io/docs/http/job.html + https://www.nomadproject.io/docs/http/job.html - arguments: - - id - returns: list - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + - id_ + returns: list + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request(id, "allocations", method="get").json() + return self.request(id_, "allocations", method="get").json() - def get_evaluations(self, id): - """ Query the evaluations belonging to a single job. + def get_evaluations(self, id_): + """Query the evaluations belonging to a single job. - https://www.nomadproject.io/docs/http/job.html + https://www.nomadproject.io/docs/http/job.html - arguments: - - id - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + - id_ + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request(id, "evaluations", method="get").json() + return self.request(id_, "evaluations", method="get").json() - def get_deployments(self, id): - """ This endpoint lists a single job's deployments + def get_deployments(self, id_): + """This endpoint lists a single job's deployments - https://www.nomadproject.io/docs/http/job.html + https://www.nomadproject.io/docs/http/job.html - arguments: - - id - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + - id_ + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request(id, "deployments", method="get").json() + return self.request(id_, "deployments", method="get").json() - def get_deployment(self, id): - """ This endpoint returns a single job's most recent deployment. + def get_deployment(self, id_): + """This endpoint returns a single job's most recent deployment. - https://www.nomadproject.io/docs/http/job.html + https://www.nomadproject.io/docs/http/job.html - arguments: - - id - returns: list of dicts - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + - id_ + returns: list of dicts + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request(id, "deployment", method="get").json() + return self.request(id_, "deployment", method="get").json() - def get_summary(self, id): - """ Query the summary of a job. + def get_summary(self, id_): + """Query the summary of a job. - https://www.nomadproject.io/docs/http/job.html + https://www.nomadproject.io/docs/http/job.html - arguments: - - id - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + - id_ + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request(id, "summary", method="get").json() + return self.request(id_, "summary", method="get").json() - def register_job(self, id, job): - """ Registers a new job or updates an existing job + def register_job(self, id_, job): + """Registers a new job or updates an existing job - https://www.nomadproject.io/docs/http/job.html + https://www.nomadproject.io/docs/http/job.html - arguments: - - id - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + - id_ + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request(id, json=job, method="post").json() + return self.request(id_, json=job, method="post").json() - def evaluate_job(self, id): - """ Creates a new evaluation for the given job. - This can be used to force run the scheduling logic if necessary. + def evaluate_job(self, id_): + """Creates a new evaluation for the given job. + This can be used to force run the scheduling logic if necessary. - https://www.nomadproject.io/docs/http/job.html + https://www.nomadproject.io/docs/http/job.html - arguments: - - id - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + - id_ + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request(id, "evaluate", method="post").json() - - def plan_job(self, id, job, diff=False, policy_override=False): - """ Invoke a dry-run of the scheduler for the job. - - https://www.nomadproject.io/docs/http/job.html - - arguments: - - id - - job, dict - - diff, boolean - - policy_override, boolean - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + return self.request(id_, "evaluate", method="post").json() + + def plan_job(self, id_, job, diff=False, policy_override=False): + """Invoke a dry-run of the scheduler for the job. + + https://www.nomadproject.io/docs/http/job.html + + arguments: + - id_ + - job, dict + - diff, boolean + - policy_override, boolean + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ json_dict = {} json_dict.update(job) - json_dict.setdefault('Diff', diff) - json_dict.setdefault('PolicyOverride', policy_override) - return self.request(id, "plan", json=json_dict, method="post").json() - - def periodic_job(self, id): - """ Forces a new instance of the periodic job. A new instance will be - created even if it violates the job's prohibit_overlap settings. - As such, this should be only used to immediately - run a periodic job. - - https://www.nomadproject.io/docs/http/job.html - - arguments: - - id - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + json_dict.setdefault("Diff", diff) + json_dict.setdefault("PolicyOverride", policy_override) + return self.request(id_, "plan", json=json_dict, method="post").json() + + def periodic_job(self, id_): + """Forces a new instance of the periodic job. A new instance will be + created even if it violates the job's prohibit_overlap settings. + As such, this should be only used to immediately + run a periodic job. + + https://www.nomadproject.io/docs/http/job.html + + arguments: + - id_ + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request(id, "periodic", "force", method="post").json() + return self.request(id_, "periodic", "force", method="post").json() - def dispatch_job(self, id, payload=None, meta=None): - """ Dispatches a new instance of a parameterized job. + def dispatch_job(self, id_, payload=None, meta=None): + """Dispatches a new instance of a parameterized job. - https://www.nomadproject.io/docs/http/job.html + https://www.nomadproject.io/docs/http/job.html - arguments: - - id - - payload - - meta - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + - id_ + - payload + - meta + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ dispatch_json = {"Meta": meta, "Payload": payload} - return self.request(id, "dispatch", json=dispatch_json, method="post").json() - - def revert_job(self, id, version, enforce_prior_version=None): - """ This endpoint reverts the job to an older version. - - https://www.nomadproject.io/docs/http/job.html - - arguments: - - id - - version, Specifies the job version to revert to. - optional_arguments: - - enforce_prior_version, Optional value specifying the current job's version. - This is checked and acts as a check-and-set value before reverting to the - specified job. - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + return self.request(id_, "dispatch", json=dispatch_json, method="post").json() + + def revert_job(self, id_, version, enforce_prior_version=None): + """This endpoint reverts the job to an older version. + + https://www.nomadproject.io/docs/http/job.html + + arguments: + - id_ + - version, Specifies the job version to revert to. + optional_arguments: + - enforce_prior_version, Optional value specifying the current job's version. + This is checked and acts as a check-and-set value before reverting to the + specified job. + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - revert_json = {"JobID": id, - "JobVersion": version, - "EnforcePriorVersion": enforce_prior_version} - return self.request(id, "revert", json=revert_json, method="post").json() - - def stable_job(self, id, version, stable): - """ This endpoint sets the job's stability. - - https://www.nomadproject.io/docs/http/job.html - - arguments: - - id - - version, Specifies the job version to revert to. - - stable, Specifies whether the job should be marked as stable or not. - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + revert_json = {"JobID": id_, "JobVersion": version, "EnforcePriorVersion": enforce_prior_version} + return self.request(id_, "revert", json=revert_json, method="post").json() + + def stable_job(self, id_, version, stable): + """This endpoint sets the job's stability. + + https://www.nomadproject.io/docs/http/job.html + + arguments: + - id_ + - version, Specifies the job version to revert to. + - stable, Specifies whether the job should be marked as stable or not. + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - revert_json = {"JobID": id, - "JobVersion": version, - "Stable": stable} - return self.request(id, "stable", json=revert_json, method="post").json() - - def deregister_job(self, id, purge=None): - """ Deregisters a job, and stops all allocations part of it. - - https://www.nomadproject.io/docs/http/job.html - - arguments: - - id - - purge (bool), optionally specifies whether the job should be - stopped and purged immediately (`purge=True`) or deferred to the - Nomad garbage collector (`purge=False`). - - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException - - nomad.api.exceptions.InvalidParameters + revert_json = {"JobID": id_, "JobVersion": version, "Stable": stable} + return self.request(id_, "stable", json=revert_json, method="post").json() + + def deregister_job(self, id_, purge=None): + """Deregisters a job, and stops all allocations part of it. + + https://www.nomadproject.io/docs/http/job.html + + arguments: + - id_ + - purge (bool), optionally specifies whether the job should be + stopped and purged immediately (`purge=True`) or deferred to the + Nomad garbage collector (`purge=False`). + + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException + - nomad.api.exceptions.InvalidParameters """ params = None if purge is not None: if not isinstance(purge, bool): - raise nomad.api.exceptions.InvalidParameters("purge is invalid " - "(expected type %s but got %s)"%(type(bool()), type(purge))) + raise nomad.api.exceptions.InvalidParameters( + "purge is invalid " f"(expected type {type(bool())} but got {type(purge)})" + ) params = {"purge": purge} - return self.request(id, params=params, method="delete").json() + return self.request(id_, params=params, method="delete").json() diff --git a/nomad/api/jobs.py b/nomad/api/jobs.py index 09e6f3a..c57f31c 100644 --- a/nomad/api/jobs.py +++ b/nomad/api/jobs.py @@ -1,10 +1,11 @@ +"""Nomad job: https://developer.hashicorp.com/nomad/api-docs/jobs""" +from typing import Optional import nomad.api.exceptions from nomad.api.base import Requester class Jobs(Requester): - """ The jobs endpoint is used to query the status of existing jobs in Nomad and to register new jobs. @@ -12,19 +13,20 @@ class Jobs(Requester): https://www.nomadproject.io/docs/http/jobs.html """ + ENDPOINT = "jobs" def __init__(self, **kwargs): - super(Jobs, self).__init__(**kwargs) + super().__init__(**kwargs) def __str__(self): - return "{0}".format(self.__dict__) + return "{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return "{self.__dict__}" def __getattr__(self, item): - msg = "{0} does not exist".format(item) + msg = f"{item} does not exist" raise AttributeError(msg) def __contains__(self, item): @@ -36,8 +38,7 @@ def __contains__(self, item): return True if j["Name"] == item: return True - else: - return False + return False except nomad.api.exceptions.URLNotFoundNomadException: return False @@ -54,56 +55,69 @@ def __getitem__(self, item): return j if j["Name"] == item: return j - else: - raise KeyError - except nomad.api.exceptions.URLNotFoundNomadException: raise KeyError + except nomad.api.exceptions.URLNotFoundNomadException as exc: + raise KeyError from exc def __iter__(self): jobs = self.get_jobs() return iter(jobs) - def get_jobs(self, prefix=None, namespace=None): - """ Lists all the jobs registered with Nomad. - - https://www.nomadproject.io/docs/http/jobs.html - arguments: - - prefix :(str) optional, specifies a string to filter jobs on based on an prefix. - This is specified as a querystring parameter. - - namespace :(str) optional, specifies the target namespace. Specifying * would return all jobs. - This is specified as a querystring parameter. - returns: list - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + def get_jobs( + self, + prefix: Optional[str] = None, + namespace: Optional[str] = None, + filter_: Optional[str] = None, + meta: Optional[bool] = None, + ): + """Lists all the jobs registered with Nomad. + + https://www.nomadproject.io/docs/http/jobs.html + arguments: + - prefix :(str) optional, specifies a string to filter jobs on based on an prefix. + This is specified as a querystring parameter. + - namespace :(str) optional, specifies the target namespace. Specifying * would return all jobs. + This is specified as a querystring parameter. + - filter_ :(str) optional, specifies the expression used to filter the result. + Name has a trailing underscore not to conflict with builtin function. + - meta :(bool) optional, if set, jobs returned will include a meta field containing + key-value pairs provided in the job specification's meta block. + returns: list + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - params = {"prefix": prefix} - if namespace: - params["namespace"] = namespace - + params = { + "prefix": prefix, + "namespace": namespace, + "filter": filter_, + "meta": meta, + } return self.request(method="get", params=params).json() def register_job(self, job): - """ Register a job with Nomad. + """Register a job with Nomad. - https://www.nomadproject.io/docs/http/jobs.html + https://www.nomadproject.io/docs/http/jobs.html - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ return self.request(json=job, method="post").json() def parse(self, hcl, canonicalize=False): - """ Parse a HCL Job file. Returns a dict with the JSON formatted job. - This API endpoint is only supported from Nomad version 0.8.3. + """Parse a HCL Job file. Returns a dict with the JSON formatted job. + This API endpoint is only supported from Nomad version 0.8.3. - https://www.nomadproject.io/api/jobs.html#parse-job + https://www.nomadproject.io/api/jobs.html#parse-job - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request("parse", json={"JobHCL": hcl, "Canonicalize": canonicalize}, method="post", allow_redirects=True).json() + return self.request( + "parse", json={"JobHCL": hcl, "Canonicalize": canonicalize}, method="post", allow_redirects=True + ).json() diff --git a/nomad/api/metrics.py b/nomad/api/metrics.py index beef3c3..0575eff 100644 --- a/nomad/api/metrics.py +++ b/nomad/api/metrics.py @@ -1,8 +1,8 @@ +"""Nomad Metrics: https://developer.hashicorp.com/nomad/api-docs/metrics""" from nomad.api.base import Requester class Metrics(Requester): - """ The /metrics endpoint returns metrics for the current Nomad process. @@ -12,28 +12,30 @@ class Metrics(Requester): https://www.nomadproject.io/docs/agent/telemetry.html """ + ENDPOINT = "metrics" def __init__(self, **kwargs): - super(Metrics, self).__init__(**kwargs) + super().__init__(**kwargs) def __str__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __getattr__(self, item): - raise AttributeError + msg = f"{item} does not exist" + raise AttributeError(msg) def get_metrics(self): - """ Get the metrics + """Get the metrics - https://www.nomadproject.io/api/metrics.html + https://www.nomadproject.io/api/metrics.html - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ return self.request(method="get").json() diff --git a/nomad/api/namespace.py b/nomad/api/namespace.py index 0f51b01..4044e5b 100644 --- a/nomad/api/namespace.py +++ b/nomad/api/namespace.py @@ -1,107 +1,106 @@ +"""Nomad namespace: https://developer.hashicorp.com/nomad/api-docs/namespaces""" import nomad.api.exceptions from nomad.api.base import Requester class Namespace(Requester): - """ The job endpoint is used for CRUD on a single namespace. By default, the agent's local region is used. https://www.nomadproject.io/api/namespaces.html """ + ENDPOINT = "namespace" def __init__(self, **kwargs): - super(Namespace, self).__init__(**kwargs) + super().__init__(**kwargs) def __str__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __getattr__(self, item): - msg = "{0} does not exist".format(item) + msg = f"{item} does not exist" raise AttributeError(msg) def __contains__(self, item): - try: - j = self.get_namespace(item) + self.get_namespace(item) return True except nomad.api.exceptions.URLNotFoundNomadException: return False def __getitem__(self, item): - try: - j = self.get_namespace(item) - - if j["ID"] == item: - return j - if j["Name"] == item: - return j - else: - raise KeyError - except nomad.api.exceptions.URLNotFoundNomadException: + job = self.get_namespace(item) + + if job["ID"] == item: + return job + if job["Name"] == item: + return job + raise KeyError + except nomad.api.exceptions.URLNotFoundNomadException as exc: + raise KeyError from exc - def get_namespace(self, id): - """ Query a single namespace. + def get_namespace(self, id_): + """Query a single namespace. - https://www.nomadproject.io/api/namespaces.html + https://www.nomadproject.io/api/namespaces.html - arguments: - - id - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + - id_ + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request(id, method="get").json() + return self.request(id_, method="get").json() def create_namespace(self, namespace): - """ create namespace + """create namespace - https://www.nomadproject.io/api/namespaces.html + https://www.nomadproject.io/api/namespaces.html - arguments: - - id - - namespace (dict) - returns: requests.Response - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + - id + - namespace (dict) + returns: requests.Response + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ return self.request(json=namespace, method="post") - def update_namespace(self, id, namespace): - """ Update namespace + def update_namespace(self, id_, namespace): + """Update namespace - https://www.nomadproject.io/api/namespaces.html + https://www.nomadproject.io/api/namespaces.html - arguments: - - id - - namespace (dict) - returns: requests.Response - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + - id_ + - namespace (dict) + returns: requests.Response + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request(id, json=namespace, method="post") + return self.request(id_, json=namespace, method="post") - def delete_namespace(self, id): - """ delete namespace. + def delete_namespace(self, id_): + """delete namespace. - https://www.nomadproject.io/api/namespaces.html + https://www.nomadproject.io/api/namespaces.html - arguments: - - id - returns: requests.Response - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + - id_ + returns: requests.Response + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request(id, method="delete") + return self.request(id_, method="delete") diff --git a/nomad/api/namespaces.py b/nomad/api/namespaces.py index 12b39a1..a87108f 100644 --- a/nomad/api/namespaces.py +++ b/nomad/api/namespaces.py @@ -1,38 +1,39 @@ +"""Nomad namespace: https://developer.hashicorp.com/nomad/api-docs/namespaces""" import nomad.api.exceptions from nomad.api.base import Requester class Namespaces(Requester): - """ The namespaces from enterprise solution https://www.nomadproject.io/docs/enterprise/namespaces/index.html """ + ENDPOINT = "namespaces" def __init__(self, **kwargs): - super(Namespaces, self).__init__(**kwargs) + super().__init__(**kwargs) def __str__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __getattr__(self, item): - msg = "{0} does not exist".format(item) + msg = f"{item} does not exist" raise AttributeError(msg) def __contains__(self, item): try: namespaces = self.get_namespaces() - for n in namespaces: - if n["Name"] == item: + for namespace in namespaces: + if namespace["Name"] == item: return True - + return False except nomad.api.exceptions.URLNotFoundNomadException: return False @@ -45,29 +46,29 @@ def __getitem__(self, item): try: namespaces = self.get_namespaces() - for n in namespaces: - if n["Name"] == item: - return n - - raise KeyError - except nomad.api.exceptions.URLNotFoundNomadException: + for namespace in namespaces: + if namespace["Name"] == item: + return namespace + raise KeyError + except nomad.api.exceptions.URLNotFoundNomadException as exc: + raise KeyError from exc def __iter__(self): namespaces = self.get_namespaces() return iter(namespaces) def get_namespaces(self, prefix=None): - """ Lists all the namespaces registered with Nomad. - - https://www.nomadproject.io/docs/enterprise/namespaces/index.html - arguments: - - prefix :(str) optional, specifies a string to filter namespaces on based on an prefix. - This is specified as a querystring parameter. - returns: list - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + """Lists all the namespaces registered with Nomad. + + https://www.nomadproject.io/docs/enterprise/namespaces/index.html + arguments: + - prefix :(str) optional, specifies a string to filter namespaces on based on an prefix. + This is specified as a querystring parameter. + returns: list + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ params = {"prefix": prefix} return self.request(method="get", params=params).json() diff --git a/nomad/api/node.py b/nomad/api/node.py index bdff1a7..86a7462 100644 --- a/nomad/api/node.py +++ b/nomad/api/node.py @@ -1,167 +1,156 @@ +"""Nomad Node: https://developer.hashicorp.com/nomad/api-docs/nodes""" +from typing import Optional import nomad.api.exceptions from nomad.api.base import Requester class Node(Requester): - """ The node endpoint is used to query the a specific client node. By default, the agent's local region is used. https://www.nomadproject.io/docs/http/node.html """ + ENDPOINT = "node" def __init__(self, **kwargs): - super(Node, self).__init__(**kwargs) + super().__init__(**kwargs) def __str__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __getattr__(self, item): - msg = "{0} does not exist".format(item) + msg = f"{item} does not exist" raise AttributeError(msg) def __contains__(self, item): - try: - n = self.get_node(item) + self.get_node(item) return True except nomad.api.exceptions.URLNotFoundNomadException: return False def __getitem__(self, item): - try: - n = self.get_node(item) - - if n["ID"] == item: - return n - if n["Name"] == item: - return n - else: - raise KeyError - except nomad.api.exceptions.URLNotFoundNomadException: + node = self.get_node(item) + + if node["ID"] == item: + return node + if node["Name"] == item: + return node + raise KeyError + except nomad.api.exceptions.URLNotFoundNomadException as exc: + raise KeyError from exc - def get_node(self, id): - """ Query the status of a client node registered with Nomad. + def get_node(self, id_: str): + """Query the status of a client node registered with Nomad. - https://www.nomadproject.io/docs/http/node.html + https://www.nomadproject.io/docs/http/node.html - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request(id, method="get").json() + return self.request(id_, method="get").json() - def get_allocations(self, id): - """ Query the allocations belonging to a single node. + def get_allocations(self, id_: str): + """Query the allocations belonging to a single node. - https://www.nomadproject.io/docs/http/node.html + https://www.nomadproject.io/docs/http/node.html - returns: list - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + returns: list + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request(id, "allocations", method="get").json() + return self.request(id_, "allocations", method="get").json() - def evaluate_node(self, id): - """ Creates a new evaluation for the given node. - This can be used to force run the - scheduling logic if necessary. + def evaluate_node(self, id_: str): + """Creates a new evaluation for the given node. + This can be used to force run the + scheduling logic if necessary. - https://www.nomadproject.io/docs/http/node.html + https://www.nomadproject.io/docs/http/node.html - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request(id, "evaluate", method="post").json() - - def drain_node(self, id, enable=False): - """ Toggle the drain mode of the node. - When enabled, no further allocations will be - assigned and existing allocations will be migrated. - - https://www.nomadproject.io/docs/http/node.html - - arguments: - - id (str uuid): node id - - enable (bool): enable node drain or not to enable node drain - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + return self.request(id_, "evaluate", method="post").json() + + def drain_node(self, id_, enable: bool = False): + """Toggle the drain mode of the node. + When enabled, no further allocations will be + assigned and existing allocations will be migrated. + + https://www.nomadproject.io/docs/http/node.html + + arguments: + - id_ (str uuid): node id + - enable (bool): enable node drain or not to enable node drain + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request(id, "drain", params={"enable": enable}, method="post").json() + return self.request(id_, "drain", params={"enable": enable}, method="post").json() - def drain_node_with_spec(self, id, drain_spec, mark_eligible=None): - """ This endpoint toggles the drain mode of the node. When draining is enabled, - no further allocations will be assigned to this node, and existing allocations - will be migrated to new nodes. + def drain_node_with_spec(self, id_, drain_spec: Optional[dict], mark_eligible: Optional[bool] = None): + """This endpoint toggles the drain mode of the node. When draining is enabled, + no further allocations will be assigned to this node, and existing allocations + will be migrated to new nodes. - If an empty dictionary is given as drain_spec this will disable/toggle the drain. + If an empty dictionary is given as drain_spec this will disable/toggle the drain. - https://www.nomadproject.io/docs/http/node.html + https://www.nomadproject.io/docs/http/node.html - arguments: - - id (str uuid): node id - - drain_spec (dict): https://www.nomadproject.io/api/nodes.html#drainspec - - mark_eligible (bool): https://www.nomadproject.io/api/nodes.html#markeligible - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + - id_ (str uuid): node id + - drain_spec (dict): https://www.nomadproject.io/api/nodes.html#drainspec + - mark_eligible (bool): https://www.nomadproject.io/api/nodes.html#markeligible + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ payload = {} if drain_spec and mark_eligible is not None: - payload = { - "NodeID": id, - "DrainSpec": drain_spec, - "MarkEligible": mark_eligible - } + payload = {"NodeID": id_, "DrainSpec": drain_spec, "MarkEligible": mark_eligible} elif drain_spec and mark_eligible is None: - payload = { - "NodeID": id, - "DrainSpec": drain_spec - } + payload = {"NodeID": id_, "DrainSpec": drain_spec} elif not drain_spec and mark_eligible is not None: - payload = { - "NodeID": id, - "DrainSpec": None, - "MarkEligible": mark_eligible - } + payload = {"NodeID": id_, "DrainSpec": None, "MarkEligible": mark_eligible} elif not drain_spec and mark_eligible is None: payload = { - "NodeID": id, + "NodeID": id_, "DrainSpec": None, } - return self.request(id, "drain", json=payload, method="post").json() + return self.request(id_, "drain", json=payload, method="post").json() - def eligible_node(self, id, eligible=None, ineligible=None): - """ Toggle the eligibility of the node. + def eligible_node(self, id_: str, eligible: Optional[bool] = None, ineligible: Optional[bool] = None): + """Toggle the eligibility of the node. - https://www.nomadproject.io/docs/http/node.html + https://www.nomadproject.io/docs/http/node.html - arguments: - - id (str uuid): node id - - eligible (bool): Set to True to mark node eligible - - ineligible (bool): Set to True to mark node ineligible - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + - id_ (str uuid): node id + - eligible (bool): Set to True to mark node eligible + - ineligible (bool): Set to True to mark node ineligible + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ payload = {} @@ -171,25 +160,24 @@ def eligible_node(self, id, eligible=None, ineligible=None): raise nomad.api.exceptions.InvalidParameters if eligible is not None and eligible: - payload = {"Eligibility": "eligible", "NodeID": id} + payload = {"Eligibility": "eligible", "NodeID": id_} elif eligible is not None and not eligible: - payload = {"Eligibility": "ineligible", "NodeID": id} + payload = {"Eligibility": "ineligible", "NodeID": id_} elif ineligible is not None: - payload = {"Eligibility": "ineligible", "NodeID": id} + payload = {"Eligibility": "ineligible", "NodeID": id_} elif ineligible is not None and not ineligible: - payload = {"Eligibility": "eligible", "NodeID": id} + payload = {"Eligibility": "eligible", "NodeID": id_} - return self.request(id, "eligibility", json=payload, method="post").json() + return self.request(id_, "eligibility", json=payload, method="post").json() - def purge_node(self, id): - """ This endpoint purges a node from the system. Nodes can still join the cluster if they are alive. + def purge_node(self, id_: str): + """This endpoint purges a node from the system. Nodes can still join the cluster if they are alive. arguments: - - id (str uuid): node id + - id_ (str uuid): node id returns: dict raises: - nomad.api.exceptions.BaseNomadException - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request(id, "purge", method="post").json() - + return self.request(id_, "purge", method="post").json() diff --git a/nomad/api/nodes.py b/nomad/api/nodes.py index 30dd1b0..28949e4 100644 --- a/nomad/api/nodes.py +++ b/nomad/api/nodes.py @@ -1,41 +1,44 @@ +"""Nomad Node: https://developer.hashicorp.com/nomad/api-docs/nodes""" +from typing import Optional + import nomad.api.exceptions from nomad.api.base import Requester class Nodes(Requester): - """ The nodes endpoint is used to query the status of client nodes. By default, the agent's local region is used https://www.nomadproject.io/docs/http/nodes.html """ + ENDPOINT = "nodes" def __init__(self, **kwargs): - super(Nodes, self).__init__(**kwargs) + super().__init__(**kwargs) def __str__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __getattr__(self, item): - raise AttributeError + msg = f"{item} does not exist" + raise AttributeError(msg) def __contains__(self, item): try: nodes = self.get_nodes() - for n in nodes: - if n["ID"] == item: + for node in nodes: + if node["ID"] == item: return True - if n["Name"] == item: + if node["Name"] == item: return True - else: - return False + return False except nomad.api.exceptions.URLNotFoundNomadException: return False @@ -47,31 +50,45 @@ def __getitem__(self, item): try: nodes = self.get_nodes() - for n in nodes: - if n["ID"] == item: - return n - if n["Name"] == item: - return n - else: - raise KeyError - except nomad.api.exceptions.URLNotFoundNomadException: + for node in nodes: + if node["ID"] == item: + return node + if node["Name"] == item: + return node raise KeyError + except nomad.api.exceptions.URLNotFoundNomadException as exc: + raise KeyError from exc def __iter__(self): nodes = self.get_nodes() return iter(nodes) - def get_nodes(self, prefix=None): - """ Lists all the client nodes registered with Nomad. - - https://www.nomadproject.io/docs/http/nodes.html - arguments: - - prefix :(str) optional, specifies a string to filter nodes on based on an prefix. - This is specified as a querystring parameter. - returns: list - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + def get_nodes( # pylint: disable=too-many-arguments + self, + prefix: Optional[str] = None, + next_token: Optional[str] = None, + per_page: Optional[str] = None, + filter_: Optional[str] = None, + resources: Optional[bool] = None, + os: Optional[bool] = None, # pylint: disable=invalid-name + ): + """Lists all the client nodes registered with Nomad. + + https://www.nomadproject.io/docs/http/nodes.html + arguments: + - prefix :(str) optional, specifies a string to filter nodes on based on an prefix. + This is specified as a querystring parameter. + returns: list + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - params = {"prefix": prefix} + params = { + "prefix": prefix, + "next_token": next_token, + "per_page": per_page, + "filter_": filter_, + "resources": resources, + "os": os, + } return self.request(method="get", params=params).json() diff --git a/nomad/api/operator.py b/nomad/api/operator.py index 52cef1f..8fa2146 100644 --- a/nomad/api/operator.py +++ b/nomad/api/operator.py @@ -1,8 +1,8 @@ +"""Nomad Operator: https://developer.hashicorp.com/nomad/api-docs/operator""" from nomad.api.base import Requester class Operator(Requester): - """ The Operator endpoint provides cluster-level tools for Nomad operators, such as interacting with the Raft subsystem. @@ -13,49 +13,50 @@ class Operator(Requester): ENDPOINT = "operator" def __init__(self, **kwargs): - super(Operator, self).__init__(**kwargs) + super().__init__(**kwargs) def __str__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __getattr__(self, item): - raise AttributeError + msg = f"{item} does not exist" + raise AttributeError(msg) def get_configuration(self, stale=False): - """ Query the status of a client node registered with Nomad. + """Query the status of a client node registered with Nomad. - https://www.nomadproject.io/docs/http/operator.html + https://www.nomadproject.io/docs/http/operator.html - returns: dict - optional arguments: - - stale, (defaults to False), Specifies if the cluster should respond without an active leader. - This is specified as a querystring parameter. - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + returns: dict + optional arguments: + - stale, (defaults to False), Specifies if the cluster should respond without an active leader. + This is specified as a querystring parameter. + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ params = {"stale": stale} return self.request("raft", "configuration", params=params, method="get").json() def delete_peer(self, peer_address, stale=False): - """ Remove the Nomad server with given address from the Raft configuration. - The return code signifies success or failure. - - https://www.nomadproject.io/docs/http/operator.html - - arguments: - - peer_address, The address specifies the server to remove and is given as an IP:port - optional arguments: - - stale, (defaults to False), Specifies if the cluster should respond without an active leader. - This is specified as a querystring parameter. - returns: Boolean - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + """Remove the Nomad server with given address from the Raft configuration. + The return code signifies success or failure. + + https://www.nomadproject.io/docs/http/operator.html + + arguments: + - peer_address, The address specifies the server to remove and is given as an IP:port + optional arguments: + - stale, (defaults to False), Specifies if the cluster should respond without an active leader. + This is specified as a querystring parameter. + returns: Boolean + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ params = {"address": peer_address, "stale": stale} diff --git a/nomad/api/regions.py b/nomad/api/regions.py index 49bc765..bc89989 100644 --- a/nomad/api/regions.py +++ b/nomad/api/regions.py @@ -1,36 +1,37 @@ +"""Nomad region: https://developer.hashicorp.com/nomad/api-docs/regions""" import nomad.api.exceptions from nomad.api.base import Requester class Regions(Requester): - """ https://www.nomadproject.io/docs/http/regions.html """ + ENDPOINT = "regions" def __init__(self, **kwargs): - super(Regions, self).__init__(**kwargs) + super().__init__(**kwargs) def __str__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __getattr__(self, item): - raise AttributeError + msg = f"{item} does not exist" + raise AttributeError(msg) def __contains__(self, item): try: regions = self.get_regions() - for r in regions: - if r == item: + for region in regions: + if region == item: return True - else: - return False + return False except nomad.api.exceptions.URLNotFoundNomadException: return False @@ -42,26 +43,25 @@ def __getitem__(self, item): try: regions = self.get_regions() - for r in regions: - if r == item: - return r - else: - raise KeyError - except nomad.api.exceptions.URLNotFoundNomadException: + for region in regions: + if region == item: + return region raise KeyError + except nomad.api.exceptions.URLNotFoundNomadException as exc: + raise KeyError from exc def __iter__(self): regions = self.get_regions() return iter(regions) def get_regions(self): - """ Returns the known region names. + """Returns the known region names. - https://www.nomadproject.io/docs/http/regions.html + https://www.nomadproject.io/docs/http/regions.html - returns: list - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + returns: list + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ return self.request(method="get").json() diff --git a/nomad/api/scaling.py b/nomad/api/scaling.py index 56776a2..a05fa8a 100644 --- a/nomad/api/scaling.py +++ b/nomad/api/scaling.py @@ -1,3 +1,4 @@ +"""Nomad Scalling API: https://developer.hashicorp.com/nomad/api-docs/scaling-policies""" import nomad.api.exceptions from nomad.api.base import Requester @@ -9,60 +10,64 @@ class Scaling(Requester): https://developer.hashicorp.com/nomad/api-docs/scaling-policies """ + ENDPOINT = "scaling" def __init__(self, **kwargs): - super(Scaling, self).__init__(**kwargs) + super().__init__(**kwargs) def __str__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __getattr__(self, item): - raise AttributeError + msg = f"{item} does not exist" + raise AttributeError(msg) - def get_scaling_policies(self, job="", type=""): + # we want to have common arguments name with Nomad API + def get_scaling_policies(self, job="", type_=""): # pylint: disable=redefined-builtin """ This endpoint returns the scaling policies from all jobs. https://developer.hashicorp.com/nomad/api-docs/scaling-policies#list-scaling-policies arguments: - - job - - type + - job + - type_ returns: list of dicts raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ type_of_scaling_policies = [ "horizontal", "vertical_mem", "vertical_cpu", "", - ] # we have only horizontal in OSS + ] # we have only horizontal in OSS - if type not in type_of_scaling_policies: - raise nomad.api.exceptions.InvalidParameters("type is invalid " - "(expected values are {} but got {})".format(type_of_scaling_policies, type)) + if type_ not in type_of_scaling_policies: + raise nomad.api.exceptions.InvalidParameters( + "type is invalid " f"(expected values are {type_of_scaling_policies} but got {type_})" + ) - params = {"job": job, "type": type} + params = {"job": job, "type": type_} return self.request("policies", method="get", params=params).json() - def get_scaling_policy(self, id): + def get_scaling_policy(self, id_): """ This endpoint reads a specific scaling policy. https://developer.hashicorp.com/nomad/api-docs/scaling-policies#read-scaling-policy arguments: - - id + - id_ returns: list of dicts raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request("policy/{}".format(id), method="get").json() + return self.request(f"policy/{id_}", method="get").json() diff --git a/nomad/api/search.py b/nomad/api/search.py index 66e4dc9..e373ee8 100644 --- a/nomad/api/search.py +++ b/nomad/api/search.py @@ -1,3 +1,4 @@ +"""Nomad Search API: https://developer.hashicorp.com/nomad/api-docs/search""" import nomad.api.exceptions from nomad.api.base import Requester @@ -12,72 +13,76 @@ class Search(Requester): https://developer.hashicorp.com/nomad/api-docs/search """ + ENDPOINT = "search" def __init__(self, **kwargs): - super(Search, self).__init__(**kwargs) + super().__init__(**kwargs) def __str__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __getattr__(self, item): - raise AttributeError + msg = f"{item} does not exist" + raise AttributeError(msg) def search(self, prefix, context): - """ The endpoint returns matches for a given prefix and context, where a context can be jobs, - allocations, evaluations, nodes, deployments, plugins, namespaces, or volumes. - - https://developer.hashicorp.com/nomad/api-docs/search - arguments: - - prefix:(str) required, specifies the identifier against which matches will be found. - For example, if the given prefix were "a", potential matches might be "abcd", or "aabb". - - context:(str) defines the scope in which a search for a prefix operates. - Contexts can be: "jobs", "evals", "allocs", "nodes", "deployment", "plugins", - "volumes" or "all", where "all" means every context will be searched. - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException - - nomad.api.exceptions.InvalidParameters + """The endpoint returns matches for a given prefix and context, where a context can be jobs, + allocations, evaluations, nodes, deployments, plugins, namespaces, or volumes. + + https://developer.hashicorp.com/nomad/api-docs/search + arguments: + - prefix:(str) required, specifies the identifier against which matches will be found. + For example, if the given prefix were "a", potential matches might be "abcd", or "aabb". + - context:(str) defines the scope in which a search for a prefix operates. + Contexts can be: "jobs", "evals", "allocs", "nodes", "deployment", "plugins", + "volumes" or "all", where "all" means every context will be searched. + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException + - nomad.api.exceptions.InvalidParameters """ accetaple_contexts = ("jobs", "evals", "allocs", "nodes", "deployment", "plugins", "volumes", "all") if context not in accetaple_contexts: - raise nomad.api.exceptions.InvalidParameters("context is invalid " - "(expected values are {} but got {})".format(accetaple_contexts, context)) + raise nomad.api.exceptions.InvalidParameters( + "context is invalid " f"(expected values are {accetaple_contexts} but got {context})" + ) params = {"Prefix": prefix, "Context": context} return self.request(json=params, method="post").json() def fuzzy_search(self, text, context): - """ The /search/fuzzy endpoint returns partial substring matches for a given search term and context, - where a context can be jobs, allocations, nodes, plugins, or namespaces. Additionally, - fuzzy searching can be done across all contexts. - - https://developer.hashicorp.com/nomad/api-docs/search#fuzzy-searching - arguments: - - text:(str) required, specifies the identifier against which matches will be found. - For example, if the given text were "py", potential fuzzy matches might be "python", "spying", - or "happy". - - context:(str) defines the scope in which a search for a prefix operates. Contexts can be: - "jobs", "allocs", "nodes", "plugins", or "all", where "all" means every context will - be searched. - When "all" is selected, additional prefix matches will be included for the "deployments", - "evals", and "volumes" types. When searching in the "jobs" context, results that fuzzy match - "groups", "services", "tasks", "images", "commands", and "classes" are also included in the results. - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + """The /search/fuzzy endpoint returns partial substring matches for a given search term and context, + where a context can be jobs, allocations, nodes, plugins, or namespaces. Additionally, + fuzzy searching can be done across all contexts. + + https://developer.hashicorp.com/nomad/api-docs/search#fuzzy-searching + arguments: + - text:(str) required, specifies the identifier against which matches will be found. + For example, if the given text were "py", potential fuzzy matches might be "python", "spying", + or "happy". + - context:(str) defines the scope in which a search for a prefix operates. Contexts can be: + "jobs", "allocs", "nodes", "plugins", or "all", where "all" means every context will + be searched. + When "all" is selected, additional prefix matches will be included for the "deployments", + "evals", and "volumes" types. When searching in the "jobs" context, results that fuzzy match + "groups", "services", "tasks", "images", "commands", and "classes" are also included in the results. + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ params = {"Text": text, "Context": context} accetaple_contexts = ("jobs", "allocs", "nodes", "plugins", "all") if context not in accetaple_contexts: - raise nomad.api.exceptions.InvalidParameters("context is invalid " - "(expected values are {} but got {})".format(accetaple_contexts,context)) + raise nomad.api.exceptions.InvalidParameters( + "context is invalid " f"(expected values are {accetaple_contexts} but got {context})" + ) return self.request("fuzzy", json=params, method="post").json() diff --git a/nomad/api/sentinel.py b/nomad/api/sentinel.py index 29d91a4..eaf7c20 100644 --- a/nomad/api/sentinel.py +++ b/nomad/api/sentinel.py @@ -1,8 +1,8 @@ +"""Nomad Sentinel API: https://developer.hashicorp.com/nomad/api-docs/sentinel-policies""" from nomad.api.base import Requester class Sentinel(Requester): - """ The endpoint manage sentinel policies (Enterprise Only) @@ -12,85 +12,86 @@ class Sentinel(Requester): ENDPOINT = "sentinel" def __init__(self, **kwargs): - super(Sentinel, self).__init__(**kwargs) + super().__init__(**kwargs) def __str__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __getattr__(self, item): - raise AttributeError + msg = f"{item} does not exist" + raise AttributeError(msg) def get_policies(self): - """ Get a list of policies. + """Get a list of policies. - https://www.nomadproject.io/api/sentinel-policies.html + https://www.nomadproject.io/api/sentinel-policies.html - returns: list + returns: list - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ return self.request("policies", method="get").json() - def create_policy(self, id, policy): - """ Create policy. + def create_policy(self, id_, policy): + """Create policy. - https://www.nomadproject.io/api/sentinel-policies.html + https://www.nomadproject.io/api/sentinel-policies.html - arguments: - - policy - returns: requests.Response + arguments: + - policy + returns: requests.Response - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request("policy", id, json=policy, method="post") + return self.request("policy", id_, json=policy, method="post") - def get_policy(self, id): - """ Get a spacific policy. + def get_policy(self, id_): + """Get a spacific policy. - https://www.nomadproject.io/api/sentinel-policies.html + https://www.nomadproject.io/api/sentinel-policies.html - returns: dict + returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request("policy", id, method="get").json() + return self.request("policy", id_, method="get").json() - def update_policy(self, id, policy): - """ Create policy. + def update_policy(self, id_, policy): + """Create policy. - https://www.nomadproject.io/api/sentinel-policies.html + https://www.nomadproject.io/api/sentinel-policies.html - arguments: - - name - - policy - returns: requests.Response + arguments: + - name + - policy + returns: requests.Response - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request("policy", id, json=policy, method="post") + return self.request("policy", id_, json=policy, method="post") - def delete_policy(self, id): - """ Delete specific policy. + def delete_policy(self, id_): + """Delete specific policy. - https://www.nomadproject.io/api/sentinel-policies.html + https://www.nomadproject.io/api/sentinel-policies.html - arguments: - - id - returns: Boolean + arguments: + - id_ + returns: Boolean - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ - return self.request("policy", id, method="delete").ok + return self.request("policy", id_, method="delete").ok diff --git a/nomad/api/status.py b/nomad/api/status.py index ba598e0..85d8a42 100644 --- a/nomad/api/status.py +++ b/nomad/api/status.py @@ -1,10 +1,10 @@ +"""Nomad Status API: https://developer.hashicorp.com/nomad/api-docs/status""" import nomad.api.exceptions from nomad.api.base import Requester -class Status(object): - +class Status: """ By default, the agent's local region is used @@ -16,16 +16,18 @@ def __init__(self, **kwargs): self.peers = Peers(**kwargs) def __str__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __getattr__(self, item): - raise AttributeError + msg = f"{item} does not exist" + raise AttributeError(msg) class Leader(Requester): + """This endpoint returns the address of the current leader in the region.""" ENDPOINT = "status/leader" @@ -35,8 +37,8 @@ def __contains__(self, item): if leader == item: return True - else: - return False + + return False except nomad.api.exceptions.URLNotFoundNomadException: return False @@ -45,19 +47,20 @@ def __len__(self): return len(leader) def get_leader(self): - """ Returns the address of the current leader in the region. + """Returns the address of the current leader in the region. - https://www.nomadproject.io/docs/http/status.html + https://www.nomadproject.io/docs/http/status.html - returns: string - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + returns: string + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ return self.request(method="get").json() class Peers(Requester): + """This endpoint returns the set of raft peers in the region.""" ENDPOINT = "status/peers" @@ -65,11 +68,10 @@ def __contains__(self, item): try: peers = self.get_peers() - for p in peers: - if p == item: + for peer in peers: + if peer == item: return True - else: - return False + return False except nomad.api.exceptions.URLNotFoundNomadException: return False @@ -81,26 +83,25 @@ def __getitem__(self, item): try: peers = self.get_peers() - for p in peers: - if p == item: - return p - else: - raise KeyError - except nomad.api.exceptions.URLNotFoundNomadException: + for peer in peers: + if peer == item: + return peer raise KeyError + except nomad.api.exceptions.URLNotFoundNomadException as exc: + raise KeyError from exc def __iter__(self): peers = self.get_peers() return iter(peers) def get_peers(self): - """ Returns the set of raft peers in the region. + """Returns the set of raft peers in the region. - https://www.nomadproject.io/docs/http/status.html + https://www.nomadproject.io/docs/http/status.html - returns: list - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + returns: list + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ return self.request(method="get").json() diff --git a/nomad/api/system.py b/nomad/api/system.py index 923d587..4255ab4 100644 --- a/nomad/api/system.py +++ b/nomad/api/system.py @@ -1,8 +1,8 @@ +"""Nomad System API: https://developer.hashicorp.com/nomad/api-docs/system""" from nomad.api.base import Requester class System(Requester): - """ The system endpoint is used to for system maintenance and should not be necessary for most users. @@ -14,37 +14,38 @@ class System(Requester): ENDPOINT = "system" def __init__(self, **kwargs): - super(System, self).__init__(**kwargs) + super().__init__(**kwargs) def __str__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __getattr__(self, item): - raise AttributeError + msg = f"{item} does not exist" + raise AttributeError(msg) def initiate_garbage_collection(self): - """ Initiate garbage collection of jobs, evals, allocations and nodes. + """Initiate garbage collection of jobs, evals, allocations and nodes. - https://www.nomadproject.io/docs/http/system.html + https://www.nomadproject.io/docs/http/system.html - returns: Boolean - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + returns: Boolean + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ return self.request("gc", method="put").ok def reconcile_summaries(self): - """ This endpoint reconciles the summaries of all registered jobs. + """This endpoint reconciles the summaries of all registered jobs. - https://www.nomadproject.io/docs/http/system.html + https://www.nomadproject.io/docs/http/system.html - returns: Boolean - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + returns: Boolean + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ return self.request("reconcile", "summaries", method="put").ok diff --git a/nomad/api/validate.py b/nomad/api/validate.py index a0c3d7d..ea17fda 100644 --- a/nomad/api/validate.py +++ b/nomad/api/validate.py @@ -1,3 +1,4 @@ +"""Nomad Validate API: https://developer.hashicorp.com/nomad/api-docs/validate""" from nomad.api.base import Requester @@ -14,29 +15,30 @@ class Validate(Requester): ENDPOINT = "validate" def __init__(self, **kwargs): - super(Validate, self).__init__(**kwargs) + super().__init__(**kwargs) def __str__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __getattr__(self, item): - raise AttributeError + msg = f"{item} does not exist" + raise AttributeError(msg) def validate_job(self, nomad_job_dict): - """ This endpoint validates a Nomad job file. The local Nomad agent forwards the request to a server. + """This endpoint validates a Nomad job file. The local Nomad agent forwards the request to a server. In the event a server can't be reached the agent verifies the job file locally but skips validating driver configurations. - https://www.nomadproject.io/api/validate.html + https://www.nomadproject.io/api/validate.html - arguments: - - nomad_job_json, any valid nomad job IN dict FORMAT - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + arguments: + - nomad_job_json, any valid nomad job IN dict FORMAT + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ return self.request("job", json=nomad_job_dict, method="post") diff --git a/nomad/api/variable.py b/nomad/api/variable.py index 434d543..7df2446 100644 --- a/nomad/api/variable.py +++ b/nomad/api/variable.py @@ -1,10 +1,10 @@ +"""Nomad Valiables API: https://developer.hashicorp.com/nomad/api-docs/variables""" import nomad.api.exceptions from nomad.api.base import Requester class Variable(Requester): - """ The /var endpoints are used to read or create variables. https://developer.hashicorp.com/nomad/api-docs/variables @@ -13,16 +13,17 @@ class Variable(Requester): ENDPOINT = "var" def __init__(self, **kwargs): - super(Variable, self).__init__(**kwargs) + super().__init__(**kwargs) def __str__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __getattr__(self, item): - raise AttributeError + msg = f"{item} does not exist" + raise AttributeError(msg) def __contains__(self, item): try: @@ -34,8 +35,8 @@ def __contains__(self, item): def __getitem__(self, item): try: return self.get_variable(item) - except nomad.api.exceptions.URLNotFoundNomadException: - raise KeyError + except nomad.api.exceptions.URLNotFoundNomadException as exc: + raise KeyError from exc def get_variable(self, var_path, namespace=None): """ @@ -43,11 +44,11 @@ def get_variable(self, var_path, namespace=None): https://developer.hashicorp.com/nomad/api-docs/variables#read-variable arguments: - - var_path :(str), path to variable + - var_path :(str), path to variable returns: dict raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ params = {} if namespace: @@ -61,18 +62,18 @@ def create_variable(self, var_path, payload, namespace=None, cas=None): https://developer.hashicorp.com/nomad/api-docs/variables#create-variable arguments: - - var_path :(str), path to variable - - payload :(dict), variable object. Example: + - var_path :(str), path to variable + - payload :(dict), variable object. Example: https://developer.hashicorp.com/nomad/api-docs/variables#sample-payload - - namespace :(str) optional, specifies the target namespace. Specifying * would return all jobs. - This is specified as a querystring parameter. - - cas :(int) optional, If set, the variable will only be deleted if the cas value matches the - current variables ModifyIndex. + - namespace :(str) optional, specifies the target namespace. Specifying * would return all jobs. + This is specified as a querystring parameter. + - cas :(int) optional, If set, the variable will only be deleted if the cas value matches the + current variables ModifyIndex. returns: dict raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException - - nomad.api.exceptions.VariableConflict + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException + - nomad.api.exceptions.VariableConflict """ params = {} if cas is not None: @@ -82,23 +83,22 @@ def create_variable(self, var_path, payload, namespace=None, cas=None): return self.request(var_path, params=params, json=payload, method="put").json() - def delete_variable(self, var_path, namespace=None, cas=None): """ This endpoint reads a specific variable by path. This API returns the decrypted variable body. https://developer.hashicorp.com/nomad/api-docs/variables#delete-variable arguments: - - var_path :(str), path to variable - - namespace :(str) optional, specifies the target namespace. Specifying * would return all jobs. - This is specified as a querystring parameter. - - cas :(int) optional, If set, the variable will only be deleted if the cas value matches the - current variables ModifyIndex. + - var_path :(str), path to variable + - namespace :(str) optional, specifies the target namespace. Specifying * would return all jobs. + This is specified as a querystring parameter. + - cas :(int) optional, If set, the variable will only be deleted if the cas value matches the + current variables ModifyIndex. returns: dict raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException - - nomad.api.exceptions.VariableConflict + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException + - nomad.api.exceptions.VariableConflict """ params = {} if cas is not None: diff --git a/nomad/api/variables.py b/nomad/api/variables.py index 75338ec..d75f482 100644 --- a/nomad/api/variables.py +++ b/nomad/api/variables.py @@ -1,10 +1,8 @@ -import nomad.api.exceptions - +"""Nomad Valiables API: https://developer.hashicorp.com/nomad/api-docs/variables""" from nomad.api.base import Requester class Variables(Requester): - """ The /vars endpoints are used to query for and interact with variables. https://developer.hashicorp.com/nomad/api-docs/variables @@ -13,16 +11,17 @@ class Variables(Requester): ENDPOINT = "vars" def __init__(self, **kwargs): - super(Variables, self).__init__(**kwargs) + super().__init__(**kwargs) def __str__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __repr__(self): - return "{0}".format(self.__dict__) + return f"{self.__dict__}" def __getattr__(self, item): - raise AttributeError + msg = f"{item} does not exist" + raise AttributeError(msg) def __contains__(self, item): variables = self.get_variables() @@ -30,8 +29,7 @@ def __contains__(self, item): for var in variables: if var["Path"] == item: return True - else: - return False + return False def __getitem__(self, item): variables = self.get_variables() @@ -39,32 +37,29 @@ def __getitem__(self, item): for var in variables: if var["Path"] == item: return var - else: - raise KeyError + raise KeyError def __iter__(self): variables = self.get_variables() return iter(variables) def get_variables(self, prefix="", namespace=None): - """ + """ This endpoint lists variables. https://developer.hashicorp.com/nomad/api-docs/variables optional_arguments: - - prefix, (default "") Specifies a string to filter variables on based on an index prefix. - This is specified as a query string parameter. - - namespace :(str) optional, Specifies the target namespace. - Specifying * will return all variables across all the authorized namespaces. + - prefix, (default "") Specifies a string to filter variables on based on an index prefix. + This is specified as a query string parameter. + - namespace :(str) optional, Specifies the target namespace. + Specifying * will return all variables across all the authorized namespaces. returns: list of dicts raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ params = {"prefix": prefix} if namespace: params["namespace"] = namespace return self.request(params=params, method="get").json() - - diff --git a/requirements-dev-py27.txt b/requirements-dev-py27.txt deleted file mode 100644 index 21de22f..0000000 --- a/requirements-dev-py27.txt +++ /dev/null @@ -1,7 +0,0 @@ -coverage==5.2.1 -pytest==4.6.11 -pytest-cov==2.12.1 -mkdocs==1.0.4 -mock==1.2.0 -flaky==3.7.0 -responses==0.13.4 diff --git a/requirements-dev.txt b/requirements-dev.txt index eac8c93..6e3596d 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,7 +1,7 @@ -coverage==5.2.1 -pytest==6.2.4 -pytest-cov==2.12.1 -mkdocs==1.2.3 -mock==1.2.0 +coverage==6.5.0 +pytest==7.2.0 +pytest-cov==4.0.0 +mkdocs==1.4.2 +mock==4.0.3 flaky==3.7.0 -responses==0.13.4 +responses==0.22.0 \ No newline at end of file diff --git a/requirements-lint.txt b/requirements-lint.txt new file mode 100644 index 0000000..ad9fd7e --- /dev/null +++ b/requirements-lint.txt @@ -0,0 +1,2 @@ +pylint==2.15.10 +black==22.12.0 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index a743bbe..2c24336 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -requests==2.27.1 +requests==2.31.0 diff --git a/run_tests.sh b/run_tests.sh index 61c8cfa..0318587 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -6,9 +6,9 @@ set -ueo pipefail if [ "${1-}" == "init" ]; then virtualenv .venv pip install -r requirements-dev.txt + source .venv/bin/activate fi -source .venv/bin/activate NOMAD_VERSION=`nomad --version | awk '{print $2}' | cut -c2-` echo "Run Nomad in dev mode" diff --git a/setup.py b/setup.py index 76f9e97..88d6a72 100644 --- a/setup.py +++ b/setup.py @@ -1,11 +1,12 @@ +"""Nomad Python Library""" import setuptools -with open("README.md", "r") as fh: +with open("README.md", "r", encoding='utf-8') as fh: long_description = fh.read() setuptools.setup( name='python-nomad', - version='1.5.0', + version='2.0.0', install_requires=['requests'], packages=['nomad', 'nomad.api'], url='http://github.com/jrxfive/python-nomad', @@ -19,8 +20,6 @@ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/tests/conftest.py b/tests/conftest.py index a871f3b..8630b01 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,12 +2,16 @@ import pytest import tests.common as common + @pytest.fixture def nomad_setup(): n = nomad.Nomad(host=common.IP, port=common.NOMAD_PORT, verify=False, token=common.NOMAD_TOKEN) return n + @pytest.fixture def nomad_setup_with_namespace(): - n = nomad.Nomad(host=common.IP, port=common.NOMAD_PORT, verify=False, token=common.NOMAD_TOKEN, namespace=common.NOMAD_NAMESPACE) + n = nomad.Nomad( + host=common.IP, port=common.NOMAD_PORT, verify=False, token=common.NOMAD_TOKEN, namespace=common.NOMAD_NAMESPACE + ) return n diff --git a/tests/test_acl.py b/tests/test_acl.py index ec7c151..863959d 100644 --- a/tests/test_acl.py +++ b/tests/test_acl.py @@ -7,7 +7,10 @@ # integration tests requires nomad Vagrant VM or Binary running # IMPORTANT: without token activated -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported" +) @pytest.mark.run(order=0) def test_create_bootstrap(nomad_setup): bootstrap = nomad_setup.acl.generate_bootstrap() @@ -15,45 +18,59 @@ def test_create_bootstrap(nomad_setup): common.NOMAD_TOKEN = bootstrap["SecretID"] -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported" +) @pytest.mark.run(order=1) def test_list_tokens(nomad_setup): assert "Bootstrap Token" in nomad_setup.acl.get_tokens()[0]["Name"] -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported" +) @pytest.mark.run(order=2) def test_create_token(nomad_setup): - token_example='{"Name": "Readonly token","Type": "client","Policies": ["readonly"],"Global": false}' + token_example = '{"Name": "Readonly token","Type": "client","Policies": ["readonly"],"Global": false}' json_token = json.loads(token_example) created_token = nomad_setup.acl.create_token(json_token) assert "Readonly token" in created_token["Name"] -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported" +) @pytest.mark.run(order=3) def test_list_all_tokens(nomad_setup): tokens = nomad_setup.acl.get_tokens() assert isinstance(tokens, list) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported" +) @pytest.mark.run(order=4) def test_update_token(nomad_setup): - token_example='{"Name": "CreatedForUpdate","Type": "client","Policies": ["readonly"],"Global": false}' + token_example = '{"Name": "CreatedForUpdate","Type": "client","Policies": ["readonly"],"Global": false}' json_token = json.loads(token_example) created_token = nomad_setup.acl.create_token(json_token) - token_update ='{"AccessorID":"' + created_token["AccessorID"] + '","Name": "Updated" ,"Type": "client","Policies": ["readonly"]}' + token_update = ( + '{"AccessorID":"' + + created_token["AccessorID"] + + '","Name": "Updated" ,"Type": "client","Policies": ["readonly"]}' + ) json_token_update = json.loads(token_update) - update_token = nomad_setup.acl.update_token(id=created_token["AccessorID"],token=json_token_update) + update_token = nomad_setup.acl.update_token(id_=created_token["AccessorID"], token=json_token_update) assert "Updated" in update_token["Name"] -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported" +) @pytest.mark.run(order=5) def test_get_token(nomad_setup): - token_example='{"Name": "GetToken","Type": "client","Policies": ["readonly"],"Global": false}' + token_example = '{"Name": "GetToken","Type": "client","Policies": ["readonly"],"Global": false}' json_token = json.loads(token_example) created_token = nomad_setup.acl.create_token(json_token) @@ -61,10 +78,12 @@ def test_get_token(nomad_setup): assert "GetToken" in created_token["Name"] -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported" +) @pytest.mark.run(order=6) def test_delete_token(nomad_setup): - token_example='{"Name": "DeleteToken","Type": "client","Policies": ["readonly"],"Global": false}' + token_example = '{"Name": "DeleteToken","Type": "client","Policies": ["readonly"],"Global": false}' json_token = json.loads(token_example) created_token = nomad_setup.acl.create_token(json_token) assert "DeleteToken" in created_token["Name"] @@ -73,41 +92,53 @@ def test_delete_token(nomad_setup): assert False == any("DeleteToken" in x for x in nomad_setup.acl.get_tokens()) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported" +) def test_get_self_token(nomad_setup): current_token = nomad_setup.acl.get_self_token() assert nomad_setup.get_token() in current_token["SecretID"] -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported" +) def test_get_policies(nomad_setup): policies = nomad_setup.acl.get_policies() assert isinstance(policies, list) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported" +) def test_create_policy(nomad_setup): policy_example = '{ "Name": "my-policy", "Description": "This is a great policy", "Rules": "" }' json_policy = json.loads(policy_example) - nomad_setup.acl.create_policy(id="my-policy", policy=json_policy) + nomad_setup.acl.create_policy(id_="my-policy", policy=json_policy) assert False == any("my-policy" in x for x in nomad_setup.acl.get_policies()) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported" +) def test_get_policy(nomad_setup): policy = nomad_setup.acl.get_policy("my-policy") assert "This is a great policy" in policy["Description"] -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported" +) def test_update_policy(nomad_setup): policy_update = '{"Name": "my-policy","Description": "Updated","Rules": ""}' json_policy_update = json.loads(policy_update) - nomad_setup.acl.update_policy(id="my-policy", policy=json_policy_update) + nomad_setup.acl.update_policy(id_="my-policy", policy=json_policy_update) assert False == any("Updated" in x for x in nomad_setup.acl.get_policies()) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported" +) def test_delete_policy(nomad_setup): - nomad_setup.acl.delete_policy(id="my-policy") + nomad_setup.acl.delete_policy(id_="my-policy") assert False == any("my-policy" in x for x in nomad_setup.acl.get_policies()) diff --git a/tests/test_allocation.py b/tests/test_allocation.py index 0d02137..1aca38c 100644 --- a/tests/test_allocation.py +++ b/tests/test_allocation.py @@ -20,7 +20,10 @@ def test_get_allocation(nomad_setup): assert isinstance(nomad_setup.allocation.get_allocation(id), dict) == True -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 9, 2), reason="Nomad alloc stop not supported") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 9, 2), + reason="Nomad alloc stop not supported", +) def test_stop_allocation(nomad_setup): id = nomad_setup.job.get_allocations("example")[0]["ID"] assert isinstance(nomad_setup.allocation.stop_allocation(id), dict) == True @@ -69,8 +72,21 @@ def test_dunder_getattr(nomad_setup): def test_get_allocation_with_namespace(nomad_setup_with_namespace): responses.add( responses.GET, - "http://{ip}:{port}/v1/allocation/a8198d79-cfdb-6593-a999-1e9adabcba2e?namespace={namespace}".format(ip=common.IP, port=common.NOMAD_PORT, namespace=common.NOMAD_NAMESPACE), + "http://{ip}:{port}/v1/allocation/a8198d79-cfdb-6593-a999-1e9adabcba2e?namespace={namespace}".format( + ip=common.IP, port=common.NOMAD_PORT, namespace=common.NOMAD_NAMESPACE + ), status=200, - json={"ID": "a8198d79-cfdb-6593-a999-1e9adabcba2e","EvalID": "5456bd7a-9fc0-c0dd-6131-cbee77f57577","Namespace": common.NOMAD_NAMESPACE, "Name": "example.cache[0]","NodeID": "fb2170a8-257d-3c64-b14d-bc06cc94e34c","PreviousAllocation": "516d2753-0513-cfc7-57ac-2d6fac18b9dc","NextAllocation": "cd13d9b9-4f97-7184-c88b-7b451981616b"} + json={ + "ID": "a8198d79-cfdb-6593-a999-1e9adabcba2e", + "EvalID": "5456bd7a-9fc0-c0dd-6131-cbee77f57577", + "Namespace": common.NOMAD_NAMESPACE, + "Name": "example.cache[0]", + "NodeID": "fb2170a8-257d-3c64-b14d-bc06cc94e34c", + "PreviousAllocation": "516d2753-0513-cfc7-57ac-2d6fac18b9dc", + "NextAllocation": "cd13d9b9-4f97-7184-c88b-7b451981616b", + }, + ) + assert ( + common.NOMAD_NAMESPACE + in nomad_setup_with_namespace.allocation.get_allocation("a8198d79-cfdb-6593-a999-1e9adabcba2e")["Namespace"] ) - assert common.NOMAD_NAMESPACE in nomad_setup_with_namespace.allocation.get_allocation("a8198d79-cfdb-6593-a999-1e9adabcba2e")["Namespace"] diff --git a/tests/test_allocations.py b/tests/test_allocations.py index b35c445..186a41d 100644 --- a/tests/test_allocations.py +++ b/tests/test_allocations.py @@ -22,6 +22,9 @@ def test_get_allocations_prefix(nomad_setup): prefix = allocations[0]["ID"][:4] nomad_setup.allocations.get_allocations(prefix=prefix) +def test_get_allocations_resouces(nomad_setup): + allocations = nomad_setup.allocations.get_allocations(resources=True) + assert "AllocatedResources" in allocations[0] def test_dunder_str(nomad_setup): assert isinstance(str(nomad_setup.allocations), str) @@ -38,7 +41,7 @@ def test_dunder_getattr(nomad_setup): def test_dunder_iter(nomad_setup): - assert hasattr(nomad_setup.allocations, '__iter__') + assert hasattr(nomad_setup.allocations, "__iter__") for j in nomad_setup.allocations: pass @@ -54,20 +57,47 @@ def test_dunder_len(nomad_setup): def test_get_allocations_with_namespace(nomad_setup_with_namespace): responses.add( responses.GET, - "http://{ip}:{port}/v1/allocations?namespace={namespace}".format(ip=common.IP, port=common.NOMAD_PORT, namespace=common.NOMAD_NAMESPACE), + "http://{ip}:{port}/v1/allocations?namespace={namespace}".format( + ip=common.IP, port=common.NOMAD_PORT, namespace=common.NOMAD_NAMESPACE + ), status=200, - json=[{"ID": "a8198d79-cfdb-6593-a999-1e9adabcba2e","EvalID": "5456bd7a-9fc0-c0dd-6131-cbee77f57577","Namespace": common.NOMAD_NAMESPACE, "Name": "example.cache[0]","NodeID": "fb2170a8-257d-3c64-b14d-bc06cc94e34c","PreviousAllocation": "516d2753-0513-cfc7-57ac-2d6fac18b9dc","NextAllocation": "cd13d9b9-4f97-7184-c88b-7b451981616b"}] + json=[ + { + "ID": "a8198d79-cfdb-6593-a999-1e9adabcba2e", + "EvalID": "5456bd7a-9fc0-c0dd-6131-cbee77f57577", + "Namespace": common.NOMAD_NAMESPACE, + "Name": "example.cache[0]", + "NodeID": "fb2170a8-257d-3c64-b14d-bc06cc94e34c", + "PreviousAllocation": "516d2753-0513-cfc7-57ac-2d6fac18b9dc", + "NextAllocation": "cd13d9b9-4f97-7184-c88b-7b451981616b", + } + ], ) assert common.NOMAD_NAMESPACE in nomad_setup_with_namespace.allocations.get_allocations()[0]["Namespace"] + @responses.activate def test_get_allocations_with_namespace_override_namespace_declared_on_create(nomad_setup_with_namespace): override_namespace_name = "namespace=override-namespace" responses.add( responses.GET, - "http://{ip}:{port}/v1/allocations?prefix=a8198d79-cfdb-6593-a999-1e9adabcba2e&namespace={namespace}".format(ip=common.IP, port=common.NOMAD_PORT, namespace=override_namespace_name), + "http://{ip}:{port}/v1/allocations?prefix=a8198d79-cfdb-6593-a999-1e9adabcba2e&namespace={namespace}".format( + ip=common.IP, port=common.NOMAD_PORT, namespace=override_namespace_name + ), status=200, - json=[{"ID": "a8198d79-cfdb-6593-a999-1e9adabcba2e","EvalID": "5456bd7a-9fc0-c0dd-6131-cbee77f57577","Namespace": override_namespace_name, "Name": "example.cache[0]","NodeID": "fb2170a8-257d-3c64-b14d-bc06cc94e34c","PreviousAllocation": "516d2753-0513-cfc7-57ac-2d6fac18b9dc","NextAllocation": "cd13d9b9-4f97-7184-c88b-7b451981616b"}] + json=[ + { + "ID": "a8198d79-cfdb-6593-a999-1e9adabcba2e", + "EvalID": "5456bd7a-9fc0-c0dd-6131-cbee77f57577", + "Namespace": override_namespace_name, + "Name": "example.cache[0]", + "NodeID": "fb2170a8-257d-3c64-b14d-bc06cc94e34c", + "PreviousAllocation": "516d2753-0513-cfc7-57ac-2d6fac18b9dc", + "NextAllocation": "cd13d9b9-4f97-7184-c88b-7b451981616b", + } + ], ) - nomad_setup_with_namespace.allocations.get_allocations("a8198d79-cfdb-6593-a999-1e9adabcba2e", namespace=override_namespace_name) \ No newline at end of file + nomad_setup_with_namespace.allocations.get_allocations( + "a8198d79-cfdb-6593-a999-1e9adabcba2e", namespace=override_namespace_name + ) diff --git a/tests/test_base.py b/tests/test_base.py index 08b5711..d1501a0 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -18,7 +18,14 @@ def test_base_region_qs(): def test_base_region_and_namespace_qs(): - n = nomad.Nomad(host=common.IP, port=common.NOMAD_PORT, verify=False, token=common.NOMAD_TOKEN, region="random", namespace="test") + n = nomad.Nomad( + host=common.IP, + port=common.NOMAD_PORT, + verify=False, + token=common.NOMAD_TOKEN, + region="random", + namespace="test", + ) qs = n.jobs._query_string_builder("v1/jobs") assert "region" in qs @@ -29,7 +36,14 @@ def test_base_region_and_namespace_qs(): def test_base_region_and_namespace_qs_namespace_override(): - n = nomad.Nomad(host=common.IP, port=common.NOMAD_PORT, verify=False, token=common.NOMAD_TOKEN, region="random", namespace="test") + n = nomad.Nomad( + host=common.IP, + port=common.NOMAD_PORT, + verify=False, + token=common.NOMAD_TOKEN, + region="random", + namespace="test", + ) qs = n.jobs._query_string_builder("v1/jobs", {"namespace": "new-namespace"}) assert "namespace" not in qs @@ -38,7 +52,14 @@ def test_base_region_and_namespace_qs_namespace_override(): def test_base_region_and_namespace_qs_region_override(): - n = nomad.Nomad(host=common.IP, port=common.NOMAD_PORT, verify=False, token=common.NOMAD_TOKEN, region="random", namespace="test") + n = nomad.Nomad( + host=common.IP, + port=common.NOMAD_PORT, + verify=False, + token=common.NOMAD_TOKEN, + region="random", + namespace="test", + ) qs = n.jobs._query_string_builder("v1/jobs", {"region": "new-region"}) assert "region" not in qs @@ -47,7 +68,14 @@ def test_base_region_and_namespace_qs_region_override(): def test_base_region_and_namespace_qs_overrides_via_params(): - n = nomad.Nomad(host=common.IP, port=common.NOMAD_PORT, verify=False, token=common.NOMAD_TOKEN, region="random", namespace="test") + n = nomad.Nomad( + host=common.IP, + port=common.NOMAD_PORT, + verify=False, + token=common.NOMAD_TOKEN, + region="random", + namespace="test", + ) qs = n.jobs._query_string_builder("v1/jobs", {"namespace": "new-namespace", "region": "new-region"}) assert qs == {} @@ -55,22 +83,19 @@ def test_base_region_and_namespace_qs_overrides_via_params(): # integration tests requires nomad Vagrant VM or Binary running def test_base_get_connection_error(): - n = nomad.Nomad( - host="162.16.10.102", port=common.NOMAD_PORT, timeout=0.001, verify=False) + n = nomad.Nomad(host="162.16.10.102", port=common.NOMAD_PORT, timeout=0.001, verify=False) with pytest.raises(nomad.api.exceptions.BaseNomadException): j = n.evaluations["nope"] def test_base_put_connection_error(): - n = nomad.Nomad( - host="162.16.10.102", port=common.NOMAD_PORT, timeout=0.001, verify=False) + n = nomad.Nomad(host="162.16.10.102", port=common.NOMAD_PORT, timeout=0.001, verify=False) with pytest.raises(nomad.api.exceptions.BaseNomadException): j = n.system.initiate_garbage_collection() def test_base_delete_connection_error(): - n = nomad.Nomad( - host="162.16.10.102", port=common.NOMAD_PORT, timeout=0.001, verify=False) + n = nomad.Nomad(host="162.16.10.102", port=common.NOMAD_PORT, timeout=0.001, verify=False) with pytest.raises(nomad.api.exceptions.BaseNomadException): j = n.job.deregister_job("example") @@ -80,12 +105,7 @@ def test_base_raise_exception_not_requests_response_object(mock_requests): mock_requests().delete.side_effect = [requests.RequestException()] with pytest.raises(nomad.api.exceptions.BaseNomadException) as excinfo: - n = nomad.Nomad( - host="162.16.10.102", - port=common.NOMAD_PORT, - timeout=0.001, - verify=False - ) + n = nomad.Nomad(host="162.16.10.102", port=common.NOMAD_PORT, timeout=0.001, verify=False) _ = n.job.deregister_job("example") @@ -109,23 +129,35 @@ def test_base_raise_exception_is_requests_response_object(nomad_setup): assert "raised with" in str(excinfo.value) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 0), reason="Nomad dispatch not supported" +) def test_base_get_connnection_not_authorized(): - n = nomad.Nomad( - host=common.IP, port=common.NOMAD_PORT, token='aed2fc63-c155-40d5-b58a-18deed4b73e5', verify=False) + n = nomad.Nomad(host=common.IP, port=common.NOMAD_PORT, token="aed2fc63-c155-40d5-b58a-18deed4b73e5", verify=False) with pytest.raises(nomad.api.exceptions.URLNotAuthorizedNomadException): j = n.job.get_job("example") @responses.activate def test_base_use_address_instead_on_host_port(): - responses.add( - responses.GET, - 'https://nomad.service.consul:4646/v1/jobs', - status=200, - json=[] + responses.add(responses.GET, "https://nomad.service.consul:4646/v1/jobs", status=200, json=[]) + + nomad_address = "https://nomad.service.consul:4646" + n = nomad.Nomad( + address=nomad_address, host=common.IP, port=common.NOMAD_PORT, verify=False, token=common.NOMAD_TOKEN ) + n.jobs.get_jobs() + +@responses.activate +def test_use_custom_user_agent(): + custom_agent_name = "custom_agent" + responses.add(responses.GET, "https://nomad.service.consul:4646/v1/jobs", status=200, json=[]) nomad_address = "https://nomad.service.consul:4646" - n = nomad.Nomad(address=nomad_address, host=common.IP, port=common.NOMAD_PORT, verify=False, token=common.NOMAD_TOKEN) + n = nomad.Nomad( + address=nomad_address, host=common.IP, port=common.NOMAD_PORT, verify=False, + token=common.NOMAD_TOKEN, user_agent=custom_agent_name + ) n.jobs.get_jobs() + + assert responses.calls[0].request.headers["User-Agent"] == custom_agent_name diff --git a/tests/test_client.py b/tests/test_client.py index 19c24a1..84bd076 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -26,41 +26,53 @@ def test_register_job(nomad_setup): max_iterations -= 1 -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 5, 6), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 5, 6), reason="Not supported in version" +) def test_ls_list_files(nomad_setup): a = nomad_setup.allocations.get_allocations()[0]["ID"] f = nomad_setup.client.ls.list_files(a) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 5, 6), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 5, 6), reason="Not supported in version" +) def test_stat_stat_file(nomad_setup): a = nomad_setup.allocations.get_allocations()[0]["ID"] f = nomad_setup.client.stat.stat_file(a) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 8, 1), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 8, 1), reason="Not supported in version" +) def test_streamfile_fail(nomad_setup): with pytest.raises(nomad.api.exceptions.BadRequestNomadException): a = nomad_setup.allocations.get_allocations()[0]["ID"] - _ = nomad_setup.client.stream_file.stream(a, 1, "start", "/redis/executor") #invalid file name + _ = nomad_setup.client.stream_file.stream(a, 1, "start", "/redis/executor") # invalid file name -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 5, 6), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 5, 6), reason="Not supported in version" +) def test_read_stats(nomad_setup): f = nomad_setup.client.stats.read_stats() -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 5, 6), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 5, 6), reason="Not supported in version" +) def test_read_allocation_stats(nomad_setup): a = nomad_setup.allocations.get_allocations()[0]["ID"] f = nomad_setup.client.allocation.read_allocation_stats(a) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 8, 1), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 8, 1), reason="Not supported in version" +) def test_gc_all_allocations(nomad_setup): node_id = nomad_setup.nodes.get_nodes()[0]["ID"] diff --git a/tests/test_deployment.py b/tests/test_deployment.py index d27bab8..8e0d1ca 100644 --- a/tests/test_deployment.py +++ b/tests/test_deployment.py @@ -16,14 +16,18 @@ def test_register_job(nomad_setup): # integration tests requires nomad Vagrant VM or Binary running -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version" +) def test_get_deployment(nomad_setup): deploymentID = nomad_setup.deployments.get_deployments()[0]["ID"] assert isinstance(nomad_setup.deployment.get_deployment(deploymentID), dict) assert deploymentID == nomad_setup.deployment.get_deployment(deploymentID)["ID"] -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version" +) def test_get_deployment_allocations(nomad_setup): deploymentID = nomad_setup.deployments.get_deployments()[0]["ID"] assert isinstance(nomad_setup.deployment.get_deployment_allocations(deploymentID), list) @@ -31,7 +35,9 @@ def test_get_deployment_allocations(nomad_setup): assert "example" == nomad_setup.deployment.get_deployment_allocations(deploymentID)[0]["JobID"] -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version" +) def test_fail_deployment(nomad_setup): deploymentID = nomad_setup.deployments.get_deployments()[0]["ID"] try: @@ -40,7 +46,9 @@ def test_fail_deployment(nomad_setup): assert err.nomad_resp.text == "can't fail terminal deployment" -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version" +) def test_pause_deployment(nomad_setup): deploymentID = nomad_setup.deployments.get_deployments()[0]["ID"] try: @@ -49,7 +57,9 @@ def test_pause_deployment(nomad_setup): assert err.nomad_resp.text == "can't resume terminal deployment" -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version" +) def test_promote_all_deployment(nomad_setup): deploymentID = nomad_setup.deployments.get_deployments()[0]["ID"] try: @@ -58,7 +68,9 @@ def test_promote_all_deployment(nomad_setup): assert err.nomad_resp.text == "can't promote terminal deployment" -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version" +) def test_promote_all_deployment(nomad_setup): deploymentID = nomad_setup.deployments.get_deployments()[0]["ID"] try: @@ -67,7 +79,9 @@ def test_promote_all_deployment(nomad_setup): assert err.nomad_resp.text == "can't promote terminal deployment" -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version" +) def test_deployment_allocation_health(nomad_setup): deploymentID = nomad_setup.deployments.get_deployments()[0]["ID"] allocationID = nomad_setup.deployment.get_deployment(deploymentID)["ID"] @@ -111,6 +125,7 @@ def test_dunder_getattr(nomad_setup): with pytest.raises(AttributeError): _ = nomad_setup.deployment.does_not_exist + @responses.activate # # fix No data when you are using namespaces #82 @@ -118,20 +133,48 @@ def test_dunder_getattr(nomad_setup): def test_get_deployment_with_namespace(nomad_setup_with_namespace): responses.add( responses.GET, - "http://{ip}:{port}/v1/deployment/a8198d79-cfdb-6593-a999-1e9adabcba2e?namespace={namespace}".format(ip=common.IP, port=common.NOMAD_PORT, namespace=common.NOMAD_NAMESPACE), + "http://{ip}:{port}/v1/deployment/a8198d79-cfdb-6593-a999-1e9adabcba2e?namespace={namespace}".format( + ip=common.IP, port=common.NOMAD_PORT, namespace=common.NOMAD_NAMESPACE + ), status=200, - json={"ID": "70638f62-5c19-193e-30d6-f9d6e689ab8e","JobID": "example", "JobVersion": 1, "JobModifyIndex": 17, "JobSpecModifyIndex": 17, "JobCreateIndex": 7,"Namespace": common.NOMAD_NAMESPACE, "Name": "example.cache[0]"} + json={ + "ID": "70638f62-5c19-193e-30d6-f9d6e689ab8e", + "JobID": "example", + "JobVersion": 1, + "JobModifyIndex": 17, + "JobSpecModifyIndex": 17, + "JobCreateIndex": 7, + "Namespace": common.NOMAD_NAMESPACE, + "Name": "example.cache[0]", + }, + ) + assert ( + common.NOMAD_NAMESPACE + in nomad_setup_with_namespace.deployment.get_deployment("a8198d79-cfdb-6593-a999-1e9adabcba2e")["Namespace"] ) - assert common.NOMAD_NAMESPACE in nomad_setup_with_namespace.deployment.get_deployment("a8198d79-cfdb-6593-a999-1e9adabcba2e")["Namespace"] + @responses.activate def test_get_deployments_with_namespace_override_namespace_declared_on_create(nomad_setup_with_namespace): override_namespace_name = "override-namespace" responses.add( responses.GET, - "http://{ip}:{port}/v1/deployments?prefix=a8198d79-cfdb-6593-a999-1e9adabcba2e&namespace={namespace}".format(ip=common.IP, port=common.NOMAD_PORT, namespace=override_namespace_name), + "http://{ip}:{port}/v1/deployments?prefix=a8198d79-cfdb-6593-a999-1e9adabcba2e&namespace={namespace}".format( + ip=common.IP, port=common.NOMAD_PORT, namespace=override_namespace_name + ), status=200, - json={"ID": "70638f62-5c19-193e-30d6-f9d6e689ab8e","JobID": "example", "JobVersion": 1, "JobModifyIndex": 17, "JobSpecModifyIndex": 17, "JobCreateIndex": 7,"Namespace": override_namespace_name, "Name": "example.cache[0]"} + json={ + "ID": "70638f62-5c19-193e-30d6-f9d6e689ab8e", + "JobID": "example", + "JobVersion": 1, + "JobModifyIndex": 17, + "JobSpecModifyIndex": 17, + "JobCreateIndex": 7, + "Namespace": override_namespace_name, + "Name": "example.cache[0]", + }, ) - nomad_setup_with_namespace.deployments.get_deployments("a8198d79-cfdb-6593-a999-1e9adabcba2e", namespace=override_namespace_name) \ No newline at end of file + nomad_setup_with_namespace.deployments.get_deployments( + "a8198d79-cfdb-6593-a999-1e9adabcba2e", namespace=override_namespace_name + ) diff --git a/tests/test_deployments.py b/tests/test_deployments.py index b361d71..258aedd 100644 --- a/tests/test_deployments.py +++ b/tests/test_deployments.py @@ -14,48 +14,64 @@ def test_register_job(nomad_setup): # integration tests requires nomad Vagrant VM or Binary running -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version" +) def test_get_evaluation(nomad_setup): assert "example" == nomad_setup.deployments.get_deployments()[0]["JobID"] -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version" +) def test_get_deployments_prefix(nomad_setup): deployments = nomad_setup.deployments.get_deployments() prefix = deployments[0]["ID"][:4] nomad_setup.deployments.get_deployments(prefix=prefix) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version" +) def test_dunder_getitem_exist(nomad_setup): jobID = nomad_setup.deployments.get_deployments()[0]["ID"] d = nomad_setup.deployment[jobID] assert isinstance(d, dict) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version" +) def test_dunder_getitem_not_exist(nomad_setup): with pytest.raises(KeyError): _ = nomad_setup.deployments["nope"] -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version" +) def test_dunder_contain_exists(nomad_setup): jobID = nomad_setup.deployments.get_deployments()[0]["ID"] assert jobID in nomad_setup.deployments -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version" +) def test_dunder_contain_not_exist(nomad_setup): assert "nope" not in nomad_setup.deployments -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version" +) def test_dunder_len(nomad_setup): assert len(nomad_setup.deployments) == 1 -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version" +) def test_dunder_iter(nomad_setup): for d in nomad_setup.deployments: pass @@ -74,6 +90,7 @@ def test_dunder_getattr(nomad_setup): with pytest.raises(AttributeError): _ = nomad_setup.deployments.does_not_exist + @responses.activate # # fix No data when you are using namespaces #82 @@ -81,8 +98,21 @@ def test_dunder_getattr(nomad_setup): def test_get_deployments_with_namespace(nomad_setup_with_namespace): responses.add( responses.GET, - "http://{ip}:{port}/v1/deployments?namespace={namespace}".format(ip=common.IP, port=common.NOMAD_PORT, namespace=common.NOMAD_NAMESPACE), + "http://{ip}:{port}/v1/deployments?namespace={namespace}".format( + ip=common.IP, port=common.NOMAD_PORT, namespace=common.NOMAD_NAMESPACE + ), status=200, - json=[{"ID": "70638f62-5c19-193e-30d6-f9d6e689ab8e","JobID": "example", "JobVersion": 1, "JobModifyIndex": 17, "JobSpecModifyIndex": 17, "JobCreateIndex": 7,"Namespace": common.NOMAD_NAMESPACE, "Name": "example.cache[0]"}] + json=[ + { + "ID": "70638f62-5c19-193e-30d6-f9d6e689ab8e", + "JobID": "example", + "JobVersion": 1, + "JobModifyIndex": 17, + "JobSpecModifyIndex": 17, + "JobCreateIndex": 7, + "Namespace": common.NOMAD_NAMESPACE, + "Name": "example.cache[0]", + } + ], ) assert common.NOMAD_NAMESPACE in nomad_setup_with_namespace.deployments.get_deployments()[0]["Namespace"] diff --git a/tests/test_evaluation.py b/tests/test_evaluation.py index 8a80e43..ec16dac 100644 --- a/tests/test_evaluation.py +++ b/tests/test_evaluation.py @@ -14,8 +14,7 @@ def test_register_job(nomad_setup): # integration tests requires nomad Vagrant VM or Binary running def test_get_evaluation(nomad_setup): evalID = nomad_setup.job.get_allocations("example")[0]["EvalID"] - assert isinstance( - nomad_setup.evaluation.get_evaluation(evalID), dict) == True + assert isinstance(nomad_setup.evaluation.get_evaluation(evalID), dict) == True def test_get_allocations(nomad_setup): diff --git a/tests/test_evaluations.py b/tests/test_evaluations.py index 4ca4362..e3befa8 100644 --- a/tests/test_evaluations.py +++ b/tests/test_evaluations.py @@ -57,7 +57,7 @@ def test_dunder_getattr(nomad_setup): def test_dunder_iter(nomad_setup): - assert hasattr(nomad_setup.evaluations, '__iter__') + assert hasattr(nomad_setup.evaluations, "__iter__") for j in nomad_setup.evaluations: pass diff --git a/tests/test_event.py b/tests/test_event.py index 33a805f..3a2fd3b 100644 --- a/tests/test_event.py +++ b/tests/test_event.py @@ -39,6 +39,12 @@ def test_get_event_stream_with_customized_topic(nomad_setup): event = events.get(timeout=5) assert event assert "Index" in event - assert event["Events"][0]["Type"] in ("NodeRegistration", "NodeDeregistration", "NodeEligibility", "NodeDrain", "NodeEvent") + assert event["Events"][0]["Type"] in ( + "NodeRegistration", + "NodeDeregistration", + "NodeEligibility", + "NodeDrain", + "NodeEvent", + ) stream_exit.set() diff --git a/tests/test_job.py b/tests/test_job.py index a5019e1..486a101 100644 --- a/tests/test_job.py +++ b/tests/test_job.py @@ -30,37 +30,73 @@ def test_get_job(nomad_setup): def test_get_jobs_with_namespace_override_no_namespace_declared_on_create_incorrect_declared_namespace(nomad_setup): responses.add( responses.GET, - "http://{ip}:{port}/v1/job/18a0f501-41d5-ae43-ff61-1d8ec3ec8314?namespace={namespace}".format(ip=common.IP, port=common.NOMAD_PORT, namespace=common.NOMAD_NAMESPACE), + "http://{ip}:{port}/v1/job/18a0f501-41d5-ae43-ff61-1d8ec3ec8314?namespace={namespace}".format( + ip=common.IP, port=common.NOMAD_PORT, namespace=common.NOMAD_NAMESPACE + ), status=200, - json=[{"Region": "global","ID": "my-job", "ParentID": "", "Name": "my-job","Namespace": common.NOMAD_NAMESPACE, "Type": "batch", "Priority": 50}] + json=[ + { + "Region": "global", + "ID": "my-job", + "ParentID": "", + "Name": "my-job", + "Namespace": common.NOMAD_NAMESPACE, + "Type": "batch", + "Priority": 50, + } + ], ) with pytest.raises(exceptions.BaseNomadException): - nomad_setup.job.get_job(id=str(uuid.uuid4())) + nomad_setup.job.get_job(id_=str(uuid.uuid4())) @responses.activate def test_get_jobs_with_namespace_override_no_namespace_declared_on_create(nomad_setup): responses.add( responses.GET, - "http://{ip}:{port}/v1/job/18a0f501-41d5-ae43-ff61-1d8ec3ec8314?namespace={namespace}".format(ip=common.IP, port=common.NOMAD_PORT, namespace=common.NOMAD_NAMESPACE), + "http://{ip}:{port}/v1/job/18a0f501-41d5-ae43-ff61-1d8ec3ec8314?namespace={namespace}".format( + ip=common.IP, port=common.NOMAD_PORT, namespace=common.NOMAD_NAMESPACE + ), status=200, - json=[{"Region": "global","ID": "my-job", "ParentID": "", "Name": "my-job","Namespace": common.NOMAD_NAMESPACE, "Type": "batch", "Priority": 50}] + json=[ + { + "Region": "global", + "ID": "my-job", + "ParentID": "", + "Name": "my-job", + "Namespace": common.NOMAD_NAMESPACE, + "Type": "batch", + "Priority": 50, + } + ], ) - nomad_setup.job.get_job(id="18a0f501-41d5-ae43-ff61-1d8ec3ec8314", namespace=common.NOMAD_NAMESPACE) + nomad_setup.job.get_job(id_="18a0f501-41d5-ae43-ff61-1d8ec3ec8314", namespace=common.NOMAD_NAMESPACE) @responses.activate def test_get_jobs_with_namespace_override_namespace_declared_on_create(nomad_setup_with_namespace): responses.add( responses.GET, - "http://{ip}:{port}/v1/job/18a0f501-41d5-ae43-ff61-1d8ec3ec8314?namespace={namespace}".format(ip=common.IP, port=common.NOMAD_PORT, namespace="override-namespace"), + "http://{ip}:{port}/v1/job/18a0f501-41d5-ae43-ff61-1d8ec3ec8314?namespace={namespace}".format( + ip=common.IP, port=common.NOMAD_PORT, namespace="override-namespace" + ), status=200, - json=[{"Region": "global","ID": "my-job", "ParentID": "", "Name": "my-job","Namespace": common.NOMAD_NAMESPACE, "Type": "batch", "Priority": 50}] + json=[ + { + "Region": "global", + "ID": "my-job", + "ParentID": "", + "Name": "my-job", + "Namespace": common.NOMAD_NAMESPACE, + "Type": "batch", + "Priority": 50, + } + ], ) - nomad_setup_with_namespace.job.get_job(id="18a0f501-41d5-ae43-ff61-1d8ec3ec8314", namespace="override-namespace") + nomad_setup_with_namespace.job.get_job(id_="18a0f501-41d5-ae43-ff61-1d8ec3ec8314", namespace="override-namespace") def test_get_allocations(nomad_setup): @@ -78,6 +114,7 @@ def test_get_evaluations(nomad_setup): def test_evaluate_job(nomad_setup): assert "EvalID" in nomad_setup.job.evaluate_job("example") + # def test_periodic_job(nomad_setup): # assert "EvalID" in nomad_setup.job.periodic_job("example") @@ -88,73 +125,93 @@ def test_delete_job(nomad_setup): @flaky(max_runs=5, min_passes=1) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 5, 3), reason="Nomad dispatch not supported") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 5, 3), reason="Nomad dispatch not supported" +) def test_dispatch_job(nomad_setup): with open("example_batch_parameterized.json") as fh: job = json.loads(fh.read()) nomad_setup.job.register_job("example-batch", job) try: nomad_setup.job.dispatch_job("example-batch", meta={"time": "500"}) - except (exceptions.URLNotFoundNomadException, - exceptions.BaseNomadException) as e: + except (exceptions.URLNotFoundNomadException, exceptions.BaseNomadException) as e: print(e.nomad_resp.text) raise e assert "example-batch" in nomad_setup.job -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 5, 3), reason="Nomad dispatch not supported") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 5, 3), reason="Nomad dispatch not supported" +) def test_summary_job(nomad_setup): j = nomad_setup.job["example"] assert "JobID" in nomad_setup.job.get_summary(j["ID"]) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 4, 0), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 4, 0), reason="Not supported in version" +) def test_plan_job(nomad_setup): with open("example.json") as fh: job = json.loads(fh.read()) - assert "Index" in nomad_setup.job.plan_job(nomad_setup.job["example"]["ID"],job) + assert "Index" in nomad_setup.job.plan_job(nomad_setup.job["example"]["ID"], job) + -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version" +) def test_versions_job(nomad_setup): assert "Versions" in nomad_setup.job.get_versions("example") -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version" +) def test_versions_job_missing(nomad_setup): with pytest.raises(nomad.api.exceptions.URLNotFoundNomadException): assert "Versions" in nomad_setup.job.get_versions("example1") -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version" +) def test_get_job_deployments(nomad_setup): assert "JobID" in nomad_setup.job.get_deployments("example")[0] assert isinstance(nomad_setup.job.get_deployments("example"), list) assert isinstance(nomad_setup.job.get_deployments("example")[0], dict) assert "example" == nomad_setup.job.get_deployments("example")[0]["JobID"] -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version" +) def test_get_job_deployment(nomad_setup): assert "JobID" in nomad_setup.job.get_deployment("example") assert isinstance(nomad_setup.job.get_deployment("example"), dict) assert "example" == nomad_setup.job.get_deployment("example")["JobID"] -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version") -def test_get_job_deployment(nomad_setup): + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version" +) +def test_get_summary(nomad_setup): assert "JobID" in nomad_setup.job.get_summary("example") assert isinstance(nomad_setup.job.get_summary("example"), dict) assert "example" == nomad_setup.job.get_summary("example")["JobID"] -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version") -def test_revert_job(nomad_setup): - current_job_version = nomad_setup.job.get_deployment("example")["JobVersion"] - prior_job_version = current_job_version - 1 - nomad_setup.job.revert_job("example", prior_job_version, current_job_version) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version" +) def test_revert_job(nomad_setup): current_job_version = nomad_setup.job.get_deployment("example")["JobVersion"] prior_job_version = current_job_version - 1 nomad_setup.job.revert_job("example", prior_job_version, current_job_version) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version" +) def test_stable_job(nomad_setup): current_job_version = nomad_setup.job.get_deployment("example")["JobVersion"] nomad_setup.job.stable_job("example", current_job_version, True) @@ -192,9 +249,11 @@ def test_dunder_getattr(nomad_setup): with pytest.raises(AttributeError): d = nomad_setup.job.does_not_exist + def test_delete_job_with_invalid_purge_param_raises(nomad_setup): with pytest.raises(exceptions.InvalidParameters): - nomad_setup.job.deregister_job("example", purge='True') + nomad_setup.job.deregister_job("example", purge="True") + def test_delete_job_with_purge(nomad_setup): # Run this last since it will purge the job completely, resetting things like diff --git a/tests/test_jobs.py b/tests/test_jobs.py index 860bf58..05d5895 100644 --- a/tests/test_jobs.py +++ b/tests/test_jobs.py @@ -25,7 +25,9 @@ def test_get_jobs_prefix(nomad_setup): nomad_setup.jobs.get_jobs(prefix="ex") -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 8, 3), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 8, 3), reason="Not supported in version" +) def test_parse_job(nomad_setup): with open("example.nomad") as fh: hcl = fh.read() @@ -68,7 +70,7 @@ def test_dunder_getattr(nomad_setup): def test_dunder_iter(nomad_setup): - assert hasattr(nomad_setup.jobs, '__iter__') + assert hasattr(nomad_setup.jobs, "__iter__") for j in nomad_setup.jobs: pass @@ -82,9 +84,21 @@ def test_dunder_len(nomad_setup): def test_get_jobs_with_namespace(nomad_setup_with_namespace): responses.add( responses.GET, - "http://{ip}:{port}/v1/jobs?namespace={namespace}".format(ip=common.IP, port=common.NOMAD_PORT, namespace=common.NOMAD_NAMESPACE), + "http://{ip}:{port}/v1/jobs?namespace={namespace}".format( + ip=common.IP, port=common.NOMAD_PORT, namespace=common.NOMAD_NAMESPACE + ), status=200, - json=[{"Region": "global","ID": "my-job", "ParentID": "", "Name": "my-job","Namespace": common.NOMAD_NAMESPACE, "Type": "batch", "Priority": 50}] + json=[ + { + "Region": "global", + "ID": "my-job", + "ParentID": "", + "Name": "my-job", + "Namespace": common.NOMAD_NAMESPACE, + "Type": "batch", + "Priority": 50, + } + ], ) assert common.NOMAD_NAMESPACE in nomad_setup_with_namespace.jobs.get_jobs()[0]["Namespace"] @@ -93,9 +107,21 @@ def test_get_jobs_with_namespace(nomad_setup_with_namespace): def test_get_jobs_with_namespace_override_no_namespace_declared_on_create_incorrect_declared_namespace(nomad_setup): responses.add( responses.GET, - "http://{ip}:{port}/v1/jobs?namespace={namespace}".format(ip=common.IP, port=common.NOMAD_PORT, namespace=common.NOMAD_NAMESPACE), + "http://{ip}:{port}/v1/jobs?namespace={namespace}".format( + ip=common.IP, port=common.NOMAD_PORT, namespace=common.NOMAD_NAMESPACE + ), status=200, - json=[{"Region": "global","ID": "my-job", "ParentID": "", "Name": "my-job","Namespace": common.NOMAD_NAMESPACE, "Type": "batch", "Priority": 50}] + json=[ + { + "Region": "global", + "ID": "my-job", + "ParentID": "", + "Name": "my-job", + "Namespace": common.NOMAD_NAMESPACE, + "Type": "batch", + "Priority": 50, + } + ], ) with pytest.raises(BaseNomadException): @@ -106,9 +132,21 @@ def test_get_jobs_with_namespace_override_no_namespace_declared_on_create_incorr def test_get_jobs_with_namespace_override_no_namespace_declared_on_create(nomad_setup): responses.add( responses.GET, - "http://{ip}:{port}/v1/jobs?namespace={namespace}".format(ip=common.IP, port=common.NOMAD_PORT, namespace=common.NOMAD_NAMESPACE), + "http://{ip}:{port}/v1/jobs?namespace={namespace}".format( + ip=common.IP, port=common.NOMAD_PORT, namespace=common.NOMAD_NAMESPACE + ), status=200, - json=[{"Region": "global","ID": "my-job", "ParentID": "", "Name": "my-job","Namespace": common.NOMAD_NAMESPACE, "Type": "batch", "Priority": 50}] + json=[ + { + "Region": "global", + "ID": "my-job", + "ParentID": "", + "Name": "my-job", + "Namespace": common.NOMAD_NAMESPACE, + "Type": "batch", + "Priority": 50, + } + ], ) nomad_setup.jobs.get_jobs(namespace=common.NOMAD_NAMESPACE) @@ -118,9 +156,21 @@ def test_get_jobs_with_namespace_override_no_namespace_declared_on_create(nomad_ def test_get_jobs_with_namespace_override_namespace_declared_on_create(nomad_setup_with_namespace): responses.add( responses.GET, - "http://{ip}:{port}/v1/jobs?namespace={namespace}".format(ip=common.IP, port=common.NOMAD_PORT, namespace="override-namespace"), + "http://{ip}:{port}/v1/jobs?namespace={namespace}".format( + ip=common.IP, port=common.NOMAD_PORT, namespace="override-namespace" + ), status=200, - json=[{"Region": "global","ID": "my-job", "ParentID": "", "Name": "my-job","Namespace": common.NOMAD_NAMESPACE, "Type": "batch", "Priority": 50}] + json=[ + { + "Region": "global", + "ID": "my-job", + "ParentID": "", + "Name": "my-job", + "Namespace": common.NOMAD_NAMESPACE, + "Type": "batch", + "Priority": 50, + } + ], ) - nomad_setup_with_namespace.jobs.get_jobs(namespace="override-namespace") \ No newline at end of file + nomad_setup_with_namespace.jobs.get_jobs(namespace="override-namespace") diff --git a/tests/test_metrics.py b/tests/test_metrics.py index 9d7bc00..618db14 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -3,7 +3,9 @@ # integration tests requires nomad Vagrant VM or Binary running -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 1), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 7, 1), reason="Not supported in version" +) def test_metrics(nomad_setup): nomad_setup.metrics.get_metrics() @@ -19,4 +21,4 @@ def test_dunder_repr(nomad_setup): def test_dunder_getattr(nomad_setup): with pytest.raises(AttributeError): - d = nomad_setup.metrics.does_not_exist \ No newline at end of file + d = nomad_setup.metrics.does_not_exist diff --git a/tests/test_namespace.py b/tests/test_namespace.py index 57077bf..53a3924 100644 --- a/tests/test_namespace.py +++ b/tests/test_namespace.py @@ -9,9 +9,7 @@ def test_create_namespace(nomad_setup): responses.add( - responses.POST, - "http://{ip}:{port}/v1/namespace".format(ip=common.IP, port=common.NOMAD_PORT), - status=200 + responses.POST, "http://{ip}:{port}/v1/namespace".format(ip=common.IP, port=common.NOMAD_PORT), status=200 ) namespace_api = '{"Name":"api","Description":"api server namespace"}' @@ -23,9 +21,7 @@ def test_create_namespace(nomad_setup): def test_update_namespace(nomad_setup): responses.add( - responses.POST, - "http://{ip}:{port}/v1/namespace/api".format(ip=common.IP, port=common.NOMAD_PORT), - status=200 + responses.POST, "http://{ip}:{port}/v1/namespace/api".format(ip=common.IP, port=common.NOMAD_PORT), status=200 ) namespace_api = '{"Name":"api","Description":"updated namespace"}' @@ -40,7 +36,7 @@ def test_get_namespace(nomad_setup): responses.GET, "http://{ip}:{port}/v1/namespace/api".format(ip=common.IP, port=common.NOMAD_PORT), status=200, - json={"Name": "api", "Description": "api server namespace"} + json={"Name": "api", "Description": "api server namespace"}, ) assert "api" in nomad_setup.namespace.get_namespace("api")["Name"] @@ -57,7 +53,6 @@ def test_delete_namespace(nomad_setup): nomad_setup.namespace.delete_namespace("api") - ######### ENTERPRISE TEST ########### # def test_apply_namespace(nomad_setup): # namespace_api='{"Name":"api","Description":"api server namespace"}' diff --git a/tests/test_namespaces.py b/tests/test_namespaces.py index 393baa8..46e51f2 100644 --- a/tests/test_namespaces.py +++ b/tests/test_namespaces.py @@ -12,19 +12,9 @@ def test_get_namespaces(nomad_setup): "http://{ip}:{port}/v1/namespaces".format(ip=common.IP, port=common.NOMAD_PORT), status=200, json=[ - { - "CreateIndex": 31, - "Description": "Production API Servers", - "ModifyIndex": 31, - "Name": "api-prod" - }, - { - "CreateIndex": 5, - "Description": "Default shared namespace", - "ModifyIndex": 5, - "Name": "default" - } - ] + {"CreateIndex": 31, "Description": "Production API Servers", "ModifyIndex": 31, "Name": "api-prod"}, + {"CreateIndex": 5, "Description": "Default shared namespace", "ModifyIndex": 5, "Name": "default"}, + ], ) assert isinstance(nomad_setup.namespaces.get_namespaces(), list) == True @@ -37,13 +27,8 @@ def test_get_namespaces_prefix(nomad_setup): "http://{ip}:{port}/v1/namespaces?prefix=api-".format(ip=common.IP, port=common.NOMAD_PORT), status=200, json=[ - { - "CreateIndex": 31, - "Description": "Production API Servers", - "ModifyIndex": 31, - "Name": "api-prod" - }, - ] + {"CreateIndex": 31, "Description": "Production API Servers", "ModifyIndex": 31, "Name": "api-prod"}, + ], ) assert isinstance(nomad_setup.namespaces.get_namespaces(prefix="api-"), list) == True @@ -56,19 +41,9 @@ def test_namespaces_iter(nomad_setup): "http://{ip}:{port}/v1/namespaces".format(ip=common.IP, port=common.NOMAD_PORT), status=200, json=[ - { - "CreateIndex": 31, - "Description": "Production API Servers", - "ModifyIndex": 31, - "Name": "api-prod" - }, - { - "CreateIndex": 5, - "Description": "Default shared namespace", - "ModifyIndex": 5, - "Name": "default" - } - ] + {"CreateIndex": 31, "Description": "Production API Servers", "ModifyIndex": 31, "Name": "api-prod"}, + {"CreateIndex": 5, "Description": "Default shared namespace", "ModifyIndex": 5, "Name": "default"}, + ], ) assert "api-prod" in nomad_setup.namespaces @@ -81,19 +56,9 @@ def test_namespaces_len(nomad_setup): "http://{ip}:{port}/v1/namespaces".format(ip=common.IP, port=common.NOMAD_PORT), status=200, json=[ - { - "CreateIndex": 31, - "Description": "Production API Servers", - "ModifyIndex": 31, - "Name": "api-prod" - }, - { - "CreateIndex": 5, - "Description": "Default shared namespace", - "ModifyIndex": 5, - "Name": "default" - } - ] + {"CreateIndex": 31, "Description": "Production API Servers", "ModifyIndex": 31, "Name": "api-prod"}, + {"CreateIndex": 5, "Description": "Default shared namespace", "ModifyIndex": 5, "Name": "default"}, + ], ) assert 2 == len(nomad_setup.namespaces) diff --git a/tests/test_node.py b/tests/test_node.py index d63274b..055b1f5 100644 --- a/tests/test_node.py +++ b/tests/test_node.py @@ -23,7 +23,9 @@ def test_evaluate_node(nomad_setup): assert "EvalIDs" in nomad_setup.node.evaluate_node(nodeID) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) > (1, 1, 0), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) > (1, 1, 0), reason="Not supported in version" +) def test_drain_node(nomad_setup): nodeID = nomad_setup.nodes["pynomad1"]["ID"] assert "EvalIDs" in nomad_setup.node.drain_node(nodeID) @@ -33,7 +35,9 @@ def test_drain_node(nomad_setup): assert nomad_setup.node[nodeID]["Drain"] is False -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 8, 1), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 8, 1), reason="Not supported in version" +) def test_drain_node_with_spec(nomad_setup): nodeID = nomad_setup.nodes["pynomad1"]["ID"] assert "EvalIDs" in nomad_setup.node.drain_node_with_spec(nodeID, drain_spec={"Duration": "-100000000"}) @@ -42,7 +46,9 @@ def test_drain_node_with_spec(nomad_setup): assert nomad_setup.node[nodeID]["Drain"] is False -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 8, 1), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 8, 1), reason="Not supported in version" +) def test_eligible_node(nomad_setup): nodeID = nomad_setup.nodes["pynomad1"]["ID"] diff --git a/tests/test_nodes.py b/tests/test_nodes.py index f708682..96087e4 100644 --- a/tests/test_nodes.py +++ b/tests/test_nodes.py @@ -1,16 +1,30 @@ import pytest +import os # integration tests requires nomad Vagrant VM or Binary running def test_get_nodes(nomad_setup): assert isinstance(nomad_setup.nodes.get_nodes(), list) == True - +def test_get_node(nomad_setup): + node = nomad_setup.nodes.get_nodes()[0] + print(node) + assert node["ID"] in nomad_setup.nodes def test_get_nodes_prefix(nomad_setup): nodes = nomad_setup.nodes.get_nodes() prefix = nodes[0]["ID"][:4] nomad_setup.nodes.get_nodes(prefix=prefix) - +def test_get_nodes_resouces(nomad_setup): + nodes = nomad_setup.nodes.get_nodes(resources=True) + print(nodes) + assert "NodeResources" in nodes[0] + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 3, 0), reason="Not supported in version" +) +def test_get_nodes_os(nomad_setup): + nodes = nomad_setup.nodes.get_nodes(os=True) + assert "os.name" in nodes[0]["Attributes"] def test_dunder_getitem_exist(nomad_setup): n = nomad_setup.nodes["pynomad1"] @@ -46,7 +60,7 @@ def test_dunder_getattr(nomad_setup): def test_dunder_iter(nomad_setup): - assert hasattr(nomad_setup.nodes, '__iter__') + assert hasattr(nomad_setup.nodes, "__iter__") for j in nomad_setup.nodes: pass diff --git a/tests/test_operator.py b/tests/test_operator.py index 85747e4..85d94f3 100644 --- a/tests/test_operator.py +++ b/tests/test_operator.py @@ -4,17 +4,23 @@ # integration tests requires nomad Vagrant VM or Binary running -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 5, 5), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 5, 5), reason="Not supported in version" +) def test_get_configuration_default(nomad_setup): assert isinstance(nomad_setup.operator.get_configuration(), dict) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 5, 5), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 5, 5), reason="Not supported in version" +) def test_get_configuration_stale(nomad_setup): assert isinstance(nomad_setup.operator.get_configuration(stale=True), dict) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 5, 5), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 5, 5), reason="Not supported in version" +) def test_delete_peer(nomad_setup): with pytest.raises(exceptions.BaseNomadException): nomad_setup.operator.delete_peer("192.168.33.10:4646") diff --git a/tests/test_regions.py b/tests/test_regions.py index 4a16139..5654419 100644 --- a/tests/test_regions.py +++ b/tests/test_regions.py @@ -44,7 +44,7 @@ def test_dunder_getattr(nomad_setup): def test_dunder_iter(nomad_setup): - assert hasattr(nomad_setup.regions, '__iter__') + assert hasattr(nomad_setup.regions, "__iter__") for j in nomad_setup.regions: pass diff --git a/tests/test_scaling.py b/tests/test_scaling.py index 686ad3b..ffc3ff2 100644 --- a/tests/test_scaling.py +++ b/tests/test_scaling.py @@ -2,10 +2,12 @@ from nomad.api import exceptions + def test_scaling_list(nomad_setup): result = nomad_setup.scaling.get_scaling_policies() assert not result + def test_scaling_policy_not_exist(nomad_setup): with pytest.raises(exceptions.URLNotFoundNomadException): nomad_setup.scaling.get_scaling_policy("example") diff --git a/tests/test_search.py b/tests/test_search.py index 6b291ae..04812b3 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -3,32 +3,50 @@ from nomad.api import exceptions -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 1, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 1, 0), reason="Not supported in version" +) def test_search(nomad_setup): result = nomad_setup.search.search("example", "jobs") assert "example" in result["Matches"]["jobs"] -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 1, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 1, 0), reason="Not supported in version" +) def test_search_incorrect_context(nomad_setup): # job context doesn't exist with pytest.raises(exceptions.InvalidParameters): nomad_setup.search.search("example", "job") -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 1, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 1, 0), reason="Not supported in version" +) def test_search_fuzzy(nomad_setup): result = nomad_setup.search.fuzzy_search("example", "jobs") - assert any(r['ID'] == 'example' for r in result["Matches"]["jobs"]) + assert any(r["ID"] == "example" for r in result["Matches"]["jobs"]) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 1, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 1, 0), reason="Not supported in version" +) def test_search_fuzzy_incorrect_context(nomad_setup): # job context doesn't exist with pytest.raises(exceptions.InvalidParameters): nomad_setup.search.fuzzy_search("example", "job") -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 1, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 1, 0), reason="Not supported in version" +) def test_search_str(nomad_setup): assert isinstance(str(nomad_setup.search), str) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 1, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 1, 0), reason="Not supported in version" +) def test_search_repr(nomad_setup): - assert isinstance(repr(nomad_setup.search), str) \ No newline at end of file + assert isinstance(repr(nomad_setup.search), str) diff --git a/tests/test_sentinel.py b/tests/test_sentinel.py index 46dc07a..99de2fb 100644 --- a/tests/test_sentinel.py +++ b/tests/test_sentinel.py @@ -19,9 +19,9 @@ def test_list_policies(nomad_setup): "EnforcementLevel": "advisory", "Hash": "CIs8aNX5OfFvo4D7ihWcQSexEJpHp+Za+dHSncVx5+8=", "CreateIndex": 8, - "ModifyIndex": 8 + "ModifyIndex": 8, } - ] + ], ) policies = nomad_setup.sentinel.get_policies() @@ -35,26 +35,22 @@ def test_create_policy(nomad_setup): responses.add( responses.POST, "http://{ip}:{port}/v1/sentinel/policy/my-policy".format(ip=common.IP, port=common.NOMAD_PORT), - status=200 + status=200, ) policy_example = '{"Name": "my-policy", "Description": "This is a great policy", "Scope": "submit-job", "EnforcementLevel": "advisory", "Policy": "main = rule { true }"}' json_policy = json.loads(policy_example) - nomad_setup.sentinel.create_policy(id="my-policy", policy=json_policy) + nomad_setup.sentinel.create_policy(id_="my-policy", policy=json_policy) @responses.activate def test_update_policy(nomad_setup): - responses.add( - responses.POST, - "http://{ip}:{port}/v1/sentinel/policy/my-policy".format(ip=common.IP, port=common.NOMAD_PORT), - status=200 - ) + responses.add(responses.POST, f"http://{common.IP}:{common.NOMAD_PORT}/v1/sentinel/policy/my-policy", status=200) policy_example = '{"Name": "my-policy", "Description": "Update", "Scope": "submit-job", "EnforcementLevel": "advisory", "Policy": "main = rule { true }"}' json_policy = json.loads(policy_example) - nomad_setup.sentinel.update_policy(id="my-policy", policy=json_policy) + nomad_setup.sentinel.update_policy(id_="my-policy", policy=json_policy) @responses.activate @@ -71,8 +67,8 @@ def test_get_policy(nomad_setup): "Policy": "main = rule { true }\n", "Hash": "CIs8aNX5OfFvo4D7ihWcQSexEJpHp+Za+dHSncVx5+8=", "CreateIndex": 8, - "ModifyIndex": 8 - } + "ModifyIndex": 8, + }, ) policy = nomad_setup.sentinel.get_policy("foo") @@ -93,8 +89,8 @@ def test_delete_policy(nomad_setup): "Policy": "main = rule { true }\n", "Hash": "CIs8aNX5OfFvo4D7ihWcQSexEJpHp+Za+dHSncVx5+8=", "CreateIndex": 8, - "ModifyIndex": 8 - } + "ModifyIndex": 8, + }, ) - nomad_setup.sentinel.delete_policy(id="my-policy") + nomad_setup.sentinel.delete_policy(id_="my-policy") diff --git a/tests/test_status.py b/tests/test_status.py index f29494b..dde1a39 100644 --- a/tests/test_status.py +++ b/tests/test_status.py @@ -8,8 +8,7 @@ def test_get_leader(nomad_setup): if int(sys.version[0]) == 3: assert isinstance(nomad_setup.status.leader.get_leader(), str) == True else: - assert isinstance( - nomad_setup.status.leader.get_leader(), unicode) == True + assert isinstance(nomad_setup.status.leader.get_leader(), unicode) == True def test_get_peers(nomad_setup): @@ -35,8 +34,7 @@ def test_peers_dunder_contain_exists(nomad_setup): def test_peers_dunder_contain_not_exist(nomad_setup): - assert "{IP}:4647".format( - IP="172.16.10.100") not in nomad_setup.status.peers + assert "{IP}:4647".format(IP="172.16.10.100") not in nomad_setup.status.peers def test_leader_dunder_contain_exists(nomad_setup): @@ -44,8 +42,7 @@ def test_leader_dunder_contain_exists(nomad_setup): def test_leader_dunder_contain_not_exist(nomad_setup): - assert "{IP}:4647".format( - IP="172.16.10.100") not in nomad_setup.status.leader + assert "{IP}:4647".format(IP="172.16.10.100") not in nomad_setup.status.leader def test_dunder_str(nomad_setup): @@ -67,7 +64,7 @@ def test_dunder_getattr(nomad_setup): def test_peers_dunder_iter(nomad_setup): - assert hasattr(nomad_setup.status.peers, '__iter__') + assert hasattr(nomad_setup.status.peers, "__iter__") for p in nomad_setup.status.peers: pass diff --git a/tests/test_validate.py b/tests/test_validate.py index 1efde82..9888369 100644 --- a/tests/test_validate.py +++ b/tests/test_validate.py @@ -5,14 +5,18 @@ # integration tests requires nomad Vagrant VM or Binary running -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version" +) def test_validate_job(nomad_setup): with open("example.json") as job: nomad_setup.validate.validate_job(json.loads(job.read())) # integration tests requires nomad Vagrant VM or Binary running -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 6, 0), reason="Not supported in version" +) def test_invalid_job(nomad_setup): with pytest.raises(nomad.api.exceptions.BadRequestNomadException): nomad_setup.validate.validate_job({}) diff --git a/tests/test_variable.py b/tests/test_variable.py index 66ff38a..a1d1056 100644 --- a/tests/test_variable.py +++ b/tests/test_variable.py @@ -1,10 +1,13 @@ import pytest import os + # Nomad doesn't have any variables by default from nomad.api import exceptions -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_create_variable(nomad_setup): payload = { "Items": {"user": "test", "password": "test123"}, @@ -12,7 +15,10 @@ def test_create_variable(nomad_setup): nomad_setup.variable.create_variable("example/first", payload) assert "example/first" in nomad_setup.variables -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_create_variable_in_namespace(nomad_setup): payload = { "Items": {"user": "test2", "password": "321tset"}, @@ -20,7 +26,10 @@ def test_create_variable_in_namespace(nomad_setup): nomad_setup.variable.create_variable("example/second", payload, namespace="default") assert "example/second" in nomad_setup.variables -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_create_variable_with_cas(nomad_setup): payload = { "Items": {"user": "test3", "password": "321tset123"}, @@ -28,67 +37,106 @@ def test_create_variable_with_cas(nomad_setup): nomad_setup.variable.create_variable("example/third", payload, cas=0) assert "example/third" in nomad_setup.variables -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_get_variable_and_check_value(nomad_setup): var = nomad_setup.variable.get_variable("example/first") assert var["Items"]["user"] == "test" -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_get_variable_in_namespace(nomad_setup): var = nomad_setup.variable.get_variable("example/first", namespace="default") assert var["Items"]["user"] == "test" -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_get_no_exist_variable(nomad_setup): with pytest.raises(KeyError): assert nomad_setup.variable["no_exist"] -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_variable_getitem_exist(nomad_setup): var = nomad_setup.variable["example/first"] assert isinstance(var, dict) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_variable_str(nomad_setup): assert isinstance(str(nomad_setup.variable), str) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_variable_repr(nomad_setup): assert isinstance(repr(nomad_setup.variable), str) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_variable_getattr(nomad_setup): with pytest.raises(AttributeError): nomad_setup.variable.does_not_exist -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_variable_exist(nomad_setup): assert "example/second" in nomad_setup.variable -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_variable_no_exist(nomad_setup): assert "no_exist" not in nomad_setup.variable -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_variable_getitem_not_exist(nomad_setup): with pytest.raises(KeyError): nomad_setup.variable["no_exists"] -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_delete_variable(nomad_setup): assert 3 == len(nomad_setup.variables.get_variables()) nomad_setup.variable.delete_variable("example/third") assert "example/third" not in nomad_setup.variables assert 2 == len(nomad_setup.variables.get_variables()) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_delete_variable_in_namespace(nomad_setup): assert 2 == len(nomad_setup.variables.get_variables()) nomad_setup.variable.delete_variable("example/second", namespace="default") assert "example/third" not in nomad_setup.variables assert 1 == len(nomad_setup.variables.get_variables()) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_delete_variable_with_cas(nomad_setup): variable_path = "variable_with_cas" payload = { diff --git a/tests/test_variables.py b/tests/test_variables.py index cf096e2..c39d31b 100644 --- a/tests/test_variables.py +++ b/tests/test_variables.py @@ -1,55 +1,91 @@ import pytest import os -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_get_variables(nomad_setup): assert 1 == len(nomad_setup.variables.get_variables()) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_get_variables_with_prefix(nomad_setup): assert 1 == len(nomad_setup.variables.get_variables("example/first")) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_get_variables_with_prefix_no_exist(nomad_setup): assert 0 == len(nomad_setup.variables.get_variables("no_exist_var")) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_get_variables_from_namespace(nomad_setup): assert 1 == len(nomad_setup.variables.get_variables(namespace="default")) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_iter_variables(nomad_setup): - assert hasattr(nomad_setup.variables, '__iter__') + assert hasattr(nomad_setup.variables, "__iter__") for _ in nomad_setup.variables: pass -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_variables_str(nomad_setup): assert isinstance(str(nomad_setup.variables), str) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_variables_repr(nomad_setup): assert isinstance(repr(nomad_setup.variables), str) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_variables_not_exist(nomad_setup): assert "no_exist" not in nomad_setup.variables -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_variables_exist(nomad_setup): assert "example/first" in nomad_setup.variables -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_variables_getitem_exist(nomad_setup): var = nomad_setup.variables["example/first"] assert isinstance(var, dict) -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_variables_getitem_not_exist(nomad_setup): with pytest.raises(KeyError): nomad_setup.variables["no_exists"] -@pytest.mark.skipif(tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version") + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (1, 4, 0), reason="Not supported in version" +) def test_variables_getattr(nomad_setup): with pytest.raises(AttributeError): - nomad_setup.variables.does_not_exist \ No newline at end of file + nomad_setup.variables.does_not_exist