Skip to content

Commit

Permalink
Merge pull request #7 from Shackelford-Arden/as_updates
Browse files Browse the repository at this point in the history
Adding Nomad Allocation ID Property & OTel Work
  • Loading branch information
Shackelford-Arden authored Feb 10, 2023
2 parents fd78f65 + 90142de commit de69cc7
Show file tree
Hide file tree
Showing 13 changed files with 278 additions and 90 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Add GitHub Action to push package to PyPi

## [0.3.0] - 2023-01-13

### Added

- A little context awareness when working with services running in Nomad.
- Example, `ServiceHealth` now has the `alloc_id` property

### Changed

- Limiting usage of imports from `typing`
- For example, moving more hinting of lists from `List` to `list`

### Internal

- Added `Makefile` to make a few things easier to call all the time.

## [0.2.0] - 2022-10-27

### Added
Expand Down
25 changes: 25 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
lint:
poetry run pylint hc_pyconsul/
poetry run flake8 .
poetry run mypy hc_pyconsul/

test: tests
poetry run pytest --cov=hc_pyconsul tests/ --junitxml=report.xml --cov-report xml:coverage.xml

pre-commit:
make lint
make test

dev: pyproject.toml
poetry install --no-root --no-interaction

lint-ci:
make dev
make lint

test-ci:
make dev
make test

dev-pip:
pip install . && pip install ".[testing]"
Empty file added hc_pyconsul/helpers/__init__.py
Empty file.
37 changes: 37 additions & 0 deletions hc_pyconsul/helpers/services.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import re

from hc_pyconsul.models.helpers import NomadAllocation


def extract_alloc_id_from_service_name(service_id: str) -> NomadAllocation:
"""
Extracts the Nomad allocation ID from a Consul service name.
Parameters
----------
service_id: str
Returns
-------
alloc_id: NomadAllocation
Raises
------
FailedExtractingAllocID
"""

alloc_id = NomadAllocation()

full_id = re.match(r'^_nomad-task-(\w+-\w+-\w+-\w+-\w+)', service_id)

if not full_id:
return alloc_id

try:
full_id_groups = full_id.groups()[0].split('-')
alloc_id = NomadAllocation(id=full_id_groups[0], id_long='-'.join(full_id_groups))
except AttributeError:
# Gracefully exit and allow default values of empty strings be provided.
pass

return alloc_id
13 changes: 6 additions & 7 deletions hc_pyconsul/lib/catalog.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
from typing import Dict
from typing import List

from pydantic.dataclasses import dataclass

from hc_pyconsul.lib.consul import ConsulAPI
Expand All @@ -9,10 +6,11 @@

@dataclass
class ConsulCatalog(ConsulAPI):
endpoint = 'catalog'

# pylint: disable=invalid-name
@tracing('List Services')
def list_services(self, dc: str = None, node_meta: List[str] = None, namespace: str = None) -> Dict[str, List[str]]:
def list_services(self, dc: str = None, node_meta: list[str] = None, namespace: str = None) -> dict[str, list[str]]:
"""
Link to official docs:
https://developer.hashicorp.com/consul/api-docs/catalog#list-services
Expand All @@ -22,7 +20,7 @@ def list_services(self, dc: str = None, node_meta: List[str] = None, namespace:
dc: str = None
Specifies the datacenter to query.
This will default to the datacenter of the agent being queried.
node_meta: List[str] = None
node_meta: list[str] = None
Specifies a desired node metadata key/value in the form of key:value.
This parameter can be specified multiple times,
and filters the results to nodes with the specified key/value pairs.
Expand All @@ -32,7 +30,8 @@ def list_services(self, dc: str = None, node_meta: List[str] = None, namespace:
Returns
-------
services: Dict[str, List[str]]
services: dict[str, list[str]]
The list[str] is the tags for the given service.
"""
params = {}
Expand All @@ -51,6 +50,6 @@ def list_services(self, dc: str = None, node_meta: List[str] = None, namespace:
'ns': namespace
})

results = self.call_api(endpoint='/catalog/services', verb='GET', params=params)
results = self.call_api(endpoint=f'/{self.endpoint}/services', verb='GET', params=params)

return results
11 changes: 2 additions & 9 deletions hc_pyconsul/lib/tracing.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,11 @@

def tracing(name):
"""Used to instrument pieces of the library with OpenTelemetry"""

def outter_wrap(func):
@functools.wraps(func)
def wrapper(self, *args, **kwargs):
context = kwargs.get('context', None)
with tracer.start_as_current_span(name=f'Consul - {name}', context=context, kind=trace.SpanKind.CLIENT) as span:

# Remove context from the kwargs as the receiving
# method won't be looking for it.
try:
del kwargs['context']
except KeyError:
pass
with tracer.start_as_current_span(name=f'Consul - {name}', kind=trace.SpanKind.CLIENT) as span:

try:
results = func(self, *args, **kwargs)
Expand Down
9 changes: 9 additions & 0 deletions hc_pyconsul/models/health.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from pydantic import BaseModel
from pydantic import Field

from hc_pyconsul.helpers.services import extract_alloc_id_from_service_name
from hc_pyconsul.models.helpers import NomadAllocation


class HealthCheck(BaseModel):
node: str = Field(..., alias='Node')
Expand Down Expand Up @@ -60,3 +63,9 @@ class ServiceHealth(BaseModel):
node: ServiceNode = Field(..., alias='Node')
service: Service = Field(..., alias='Service')
checks: list[HealthCheck] = Field(default_factory=list, alias='Checks')

@property
def alloc_id(self) -> NomadAllocation:
"""Attempts to extract out the Nomad allocation ID for the given service check."""

return extract_alloc_id_from_service_name(service_id=self.service.id)
9 changes: 9 additions & 0 deletions hc_pyconsul/models/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from typing import Optional

from pydantic import BaseModel
from pydantic import Field


class NomadAllocation(BaseModel):
id: Optional[str] = Field(default_factory=str)
id_long: Optional[str] = Field(default_factory=str)
14 changes: 7 additions & 7 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "hc_pyconsul"
version = "0.2.0"
version = "0.3.0"
description = "API client for HashiCorp Consul"
authors = ["Arden Shackelford <[email protected]>"]
license = "Apache 2.0"
Expand All @@ -11,21 +11,21 @@ packages = [


[tool.poetry.dependencies]
python = ">=3.8,<4.0"
python = ">=3.8.1,<4.0"
httpx = "^0.23.0"
pydantic = "^1.9.0"
opentelemetry-api = "^1.13.0"

[tool.poetry.group.testing.dependencies]
pytest-cov = "^3.0.0"
pylint = "^2.15.0"
flake8 = "^4.0.1"
pylint = "^2.16.1"
flake8 = "^6.0.0"
mypy = "^0.950"
respx = "^0.19.2"
pytest = "^7.1.3"
respx = "^0.20.1"
pytest = "^7.2.1"

[build-system]
requires = ["poetry-core>=1.0.0"]
requires = ["poetry-core>=1.4.0"]
build-backend = "poetry.core.masonry.api"

[tool.pylint.'MESSAGES CONTROL']
Expand Down
Loading

0 comments on commit de69cc7

Please sign in to comment.