New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Simple first steps to create a framework on which to hang real functionality #1
Changes from all commits
1f0cd16
b2f727d
d990116
1caacd5
9ba6b77
215d625
6e663d4
f5eaa2a
da85cfa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[run] | ||
branch = True | ||
include = */txkube/* |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# | ||
# This is the Travis-CI configuration. | ||
# | ||
|
||
language: "python" | ||
|
||
# This is how you get container-based environments on Travis-CI. And | ||
# container-based environments are how you get fast test runs. | ||
sudo: false | ||
|
||
# Only build master; for "push" builds, this is when the branch pushed | ||
# to is master, for "pr" builds, this is when the merge base of the PR | ||
# is master. | ||
branches: | ||
only: | ||
- "master" | ||
|
||
cache: | ||
directories: | ||
# Cache the pip download cache across runs to avoid having to | ||
# repeatedly download packages over the network. | ||
- "$HOME/.cache/pip" | ||
|
||
install: | ||
- "pip install --upgrade pip setuptools wheel coverage codecov" | ||
- "pip install .[dev]" | ||
|
||
script: | ||
- "coverage run --rcfile=${PWD}/.coveragerc $(type -p trial) txkube" | ||
|
||
after_success: | ||
- "codecov" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
#!/usr/bin/env python | ||
|
||
# Copyright Least Authority Enterprises. | ||
# See LICENSE for details. | ||
|
||
import setuptools | ||
|
||
_metadata = {} | ||
with open("src/txkube/_metadata.py") as f: | ||
exec(f.read(), _metadata) | ||
|
||
setuptools.setup( | ||
name="txkube", | ||
version=_metadata["version_string"], | ||
description="A Twisted-based Kubernetes client.", | ||
author="txkube Developers", | ||
url="https://github.com/leastauthority.com/txkube", | ||
license="MIT", | ||
package_dir={"": "src"}, | ||
packages=setuptools.find_packages(where="src"), | ||
install_requires=[ | ||
"incremental", "twisted[tls]", | ||
], | ||
extras_require={ | ||
"dev": [ | ||
"treq", | ||
], | ||
}, | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Copyright Least Authority Enterprises. | ||
# See LICENSE for details. | ||
|
||
""" | ||
A Kubernetes client. | ||
""" | ||
|
||
__all__ = [ | ||
"version", | ||
"IKubernetesClient", | ||
"network_client", "memory_client", | ||
] | ||
|
||
from incremental import Version | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❓ |
||
|
||
from ._metadata import version_tuple as _version_tuple | ||
version = Version("txkube", *_version_tuple) | ||
|
||
from ._interface import IKubernetes, IKubernetesClient | ||
from ._network import network_kubernetes | ||
from ._memory import memory_kubernetes |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# Copyright Least Authority Enterprises. | ||
# See LICENSE for details. | ||
|
||
""" | ||
Explicit interface definitions for txkube. | ||
""" | ||
|
||
from zope.interface import Attribute, Interface | ||
|
||
class IKubernetes(Interface): | ||
""" | ||
An ``IKubernetes`` provider represents a particular Kubernetes deployment. | ||
""" | ||
base_url = Attribute( | ||
"The root of the Kubernetes HTTP API for this deployment " | ||
"(``twisted.python.url.URL``)." | ||
) | ||
credentials = Attribute( | ||
"The credentials which will grant access to use the " | ||
"deployment's API." | ||
) | ||
|
||
def client(): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❓ Missing docstring. |
||
""" | ||
Create a client which will interact with the Kubernetes deployment | ||
represented by this object. | ||
|
||
:return IKubernetesClient: The client. | ||
""" | ||
|
||
|
||
class IKubernetesClient(Interface): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❓ Missing docstring. |
||
""" | ||
An ``IKubernetesClient`` provider allows access to the API of a particular | ||
Kubernetes deployment. | ||
""" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
# Copyright Least Authority Enterprises. | ||
# See LICENSE for details. | ||
|
||
""" | ||
An in-memory implementation of the Kubernetes client interface. | ||
""" | ||
|
||
from zope.interface import implementer | ||
|
||
from twisted.python.url import URL | ||
|
||
from twisted.web.resource import Resource | ||
|
||
from treq.testing import RequestTraversalAgent | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When I attempt to run the tests I get this error:
|
||
|
||
from . import IKubernetes, network_kubernetes | ||
|
||
|
||
def memory_kubernetes(): | ||
""" | ||
Create an in-memory Kubernetes-alike service. | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing docstring. |
||
This serves as a places to hold state for stateful Kubernetes interactions | ||
allowed by ``IKubernetesClient``. Only clients created against the same | ||
instance will all share state. | ||
|
||
:return IKubernetes: The new Kubernetes-alike service. | ||
""" | ||
return _MemoryKubernetes() | ||
|
||
|
||
@implementer(IKubernetes) | ||
class _MemoryKubernetes(object): | ||
""" | ||
``_MemoryKubernetes`` maintains state in-memory which approximates | ||
the state of a real Kubernetes deployment sufficiently to expose a | ||
subset of the external Kubernetes API. | ||
""" | ||
def __init__(self): | ||
base_url = URL.fromText(u"https://kubernetes.example.invalid./") | ||
self._resource = _kubernetes_resource() | ||
self._kubernetes = network_kubernetes( | ||
base_url=base_url, | ||
credentials=None, | ||
agent=RequestTraversalAgent(self._resource), | ||
) | ||
|
||
def client(self, *args, **kwargs): | ||
""" | ||
:return IKubernetesClient: A new client which interacts with this | ||
object rather than a real Kubernetes deployment. | ||
""" | ||
return self._kubernetes.client(*args, **kwargs) | ||
|
||
|
||
def _kubernetes_resource(): | ||
return Resource() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# Copyright Least Authority Enterprises. | ||
# See LICENSE for details. | ||
|
||
""" | ||
txkube package metadata definitions. | ||
""" | ||
|
||
version_tuple = (17, 1, 0) | ||
version_string = ".".join(map(str, version_tuple)) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# Copyright Least Authority Enterprises. | ||
# See LICENSE for details. | ||
|
||
""" | ||
A Kubernetes client which uses Twisted to interact with Kubernetes | ||
via HTTP. | ||
""" | ||
|
||
from zope.interface import implementer | ||
|
||
import attr | ||
from attr import validators | ||
|
||
from twisted.python.reflect import namedAny | ||
from twisted.python.url import URL | ||
|
||
from twisted.web.iweb import IAgent | ||
from twisted.web.client import Agent | ||
|
||
from . import IKubernetes, IKubernetesClient | ||
|
||
def network_kubernetes(**kw): | ||
return _NetworkKubernetes(**kw) | ||
|
||
|
||
@implementer(IKubernetesClient) | ||
@attr.s(frozen=True) | ||
class _NetworkClient(object): | ||
kubernetes = attr.ib(validator=validators.provides(IKubernetes)) | ||
agent = attr.ib(validator=validators.provides(IAgent)) | ||
|
||
|
||
@implementer(IKubernetes) | ||
@attr.s(frozen=True) | ||
class _NetworkKubernetes(object): | ||
""" | ||
``_NetworkKubernetes`` knows the location of a particular | ||
Kubernetes deployment and gives out clients which speak to that | ||
deployment. | ||
""" | ||
base_url = attr.ib(validator=validators.instance_of(URL)) | ||
credentials = attr.ib() | ||
_agent = attr.ib( | ||
default=attr.Factory(lambda: Agent(namedAny("twisted.internet.reactor"))), | ||
) | ||
|
||
def client(self): | ||
return _NetworkClient(self, self._agent) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# Copyright Least Authority Enterprises. | ||
# See LICENSE for details. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Copyright Least Authority Enterprises. | ||
# See LICENSE for details. | ||
|
||
""" | ||
Tests for ``txkube.memory_kubernetes``. | ||
""" | ||
|
||
from ..testing.integration import kubernetes_client_tests | ||
|
||
from .. import memory_kubernetes | ||
|
||
def get_kubernetes(case): | ||
""" | ||
Create an in-memory test double provider of ``IKubernetes``. | ||
""" | ||
return memory_kubernetes() | ||
|
||
|
||
class KubernetesClientIntegrationTests(kubernetes_client_tests(get_kubernetes)): | ||
""" | ||
Integration tests which interact with an in-memory-only Kubernetes | ||
deployment via ``txkube.memory_kubernetes``. | ||
""" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# Copyright Least Authority Enterprises. | ||
# See LICENSE for details. | ||
|
||
""" | ||
Tests for ``txkube.network_kubernetes``. | ||
|
||
See ``get_kubernetes`` for pre-requisites. | ||
""" | ||
|
||
from os import environ | ||
|
||
from twisted.python.url import URL | ||
|
||
from ..testing.integration import kubernetes_client_tests | ||
|
||
from .. import network_kubernetes | ||
|
||
def get_kubernetes(case): | ||
""" | ||
Create a real ``IKubernetes`` provider, taking necessary | ||
configuration details from the environment. | ||
|
||
To use this set: | ||
|
||
- TXKUBE_INTEGRATION_KUBERNETES_BASE_URL | ||
""" | ||
try: | ||
base_url = environ["TXKUBE_INTEGRATION_KUBERNETES_BASE_URL"] | ||
except KeyError: | ||
case.skipTest("Cannot find TXKUBE_INTEGRATION_KUBERNETES_BASE_URL in environment.") | ||
else: | ||
return network_kubernetes( | ||
base_url=URL.fromText(base_url.decode("ascii")), | ||
credentials=None, | ||
) | ||
|
||
|
||
class KubernetesClientIntegrationTests(kubernetes_client_tests(get_kubernetes)): | ||
""" | ||
Integration tests which interact with a network-accessible | ||
Kubernetes deployment via ``txkube.network_kubernetes``. | ||
""" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# Copyright Least Authority Enterprises. | ||
# See LICENSE for details. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# Copyright Least Authority Enterprises. | ||
# See LICENSE for details. | ||
|
||
""" | ||
Integration test generator for ``txkube.IKubernetesClient``. | ||
""" | ||
|
||
from zope.interface.verify import verifyObject | ||
|
||
from twisted.trial.unittest import TestCase | ||
|
||
from .. import IKubernetesClient | ||
|
||
|
||
def kubernetes_client_tests(get_kubernetes): | ||
class KubernetesClientIntegrationTests(TestCase): | ||
def test_interfaces(self): | ||
""" | ||
The client provides ``txkube.IKubernetesClient``. | ||
""" | ||
kubernetes = get_kubernetes(self) | ||
client = kubernetes.client() | ||
verifyObject(IKubernetesClient, client) | ||
|
||
return KubernetesClientIntegrationTests | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❓ Not sure why this module is called integration? To me it implies a module containing slow integration tests. We'd call it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's fast and local-only right now but I anticipate adding real-Kubernetes-interacting tests here once IKubernetesClient has expanded to support any such things. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't read this carefully.
Add a note to README about how to run the tests.