-
Notifications
You must be signed in to change notification settings - Fork 6
Infrahubctl repo Init command #371
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
Changes from 24 commits
5c8e9eb
212653d
705cda2
25cf197
e5bfa55
b826d89
5972713
0d56b9b
88c19f4
935c020
687c572
b7e870b
7a8508c
8ffa5de
7ce53cf
76cb167
083ef96
52b4a07
49835aa
eb17a92
428923c
3e6aa58
0afd59b
8be8f26
3fb79ef
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 |
|---|---|---|
|
|
@@ -19,6 +19,7 @@ $ infrahubctl repository [OPTIONS] COMMAND [ARGS]... | |
| **Commands**: | ||
|
|
||
| * `add`: Add a new repository. | ||
| * `init`: Initialize a new Infrahub repository. | ||
| * `list` | ||
|
|
||
| ## `infrahubctl repository add` | ||
|
|
@@ -47,6 +48,26 @@ $ infrahubctl repository add [OPTIONS] NAME LOCATION | |
| * `--config-file TEXT`: [env var: INFRAHUBCTL_CONFIG; default: infrahubctl.toml] | ||
| * `--help`: Show this message and exit. | ||
|
|
||
| ## `infrahubctl repository init` | ||
|
|
||
| Initialize a new Infrahub repository. | ||
|
|
||
| **Usage**: | ||
|
|
||
| ```console | ||
| $ infrahubctl repository init [OPTIONS] DST | ||
| ``` | ||
|
|
||
| **Arguments**: | ||
|
|
||
| * `DST`: [required] | ||
|
|
||
| **Options**: | ||
|
|
||
| * `--data PATH` | ||
|
||
| * `--config-file TEXT`: [env var: INFRAHUBCTL_CONFIG; default: infrahubctl.toml] | ||
| * `--help`: Show this message and exit. | ||
|
|
||
| ## `infrahubctl repository list` | ||
|
|
||
| **Usage**: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| --- | ||
| schemas: | ||
| - schemas |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| # Infrahub Repository | ||
|
|
||
| Welcome! This repository was initialized via the `infrahubctl repo init` command. That bootstraps a repository for use with some example data. | ||
|
|
||
| ## Installation | ||
|
|
||
| Running `poetry install` will install all the main dependencies you need to interact with this repository. | ||
|
|
||
| ## Starting Infrahub | ||
|
|
||
| Included in the repository are a set of helper commands to get Infrahub up and running using `invoke`. | ||
|
|
||
| ```bash | ||
| Available tasks: | ||
|
|
||
| destroy Stop and remove containers, networks, and volumes. | ||
| download-compose-file Download docker-compose.yml from InfraHub if missing or override is True. | ||
| load-schema Load schemas into InfraHub using infrahubctl. | ||
| restart Restart all services or a specific one using docker-compose. | ||
| start Start the services using docker-compose in detached mode. | ||
| stop Stop containers and remove networks. | ||
| test Run tests using pytest. | ||
| ``` | ||
|
|
||
| To start infrahub simply use `invoke start` | ||
|
|
||
| ## Tests | ||
|
|
||
| By default there are some integration tests that will spin up Infrahub and its dependencies in docker and load the repository and schema. This can be run using the following: | ||
|
|
||
| ```bash | ||
| poetry install --with=dev | ||
| pytest tests/integration | ||
| ``` | ||
|
|
||
| To change the version of infrahub being used you can use an environment variable: `export INFRAHUB_TESTING_IMAGE_VERSION=1.2.5`. |
|
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. Can we make this options for the CLI command? 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. This is what |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| --- | ||
| project_name: | ||
| type: str | ||
| help: What is your project name? | ||
| generators: | ||
| type: bool | ||
| help: Would you like to use generators? | ||
| default: false | ||
| transforms: | ||
| type: bool | ||
| help: Would you like to use transforms? | ||
| default: false | ||
| scripts: | ||
| type: bool | ||
| help: Would you like to have local scripts? | ||
| default: false | ||
| queries: | ||
| type: bool | ||
| help: Would you like to store queries? | ||
| default: false | ||
| menus: | ||
| type: bool | ||
| help: Would you like to store menus? | ||
| default: false | ||
| tests: | ||
| type: bool | ||
| help: Would you like to have testing? | ||
| default: false | ||
| package_mode: | ||
| type: bool | ||
| help: Would you like to have a python library initialized? | ||
| default: false |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| [tool.poetry] | ||
| name = "{{ project_name }}" | ||
| version = "0.1.0" | ||
| description = "Infrahub Repository" | ||
| authors = [] | ||
| readme = "README.md" | ||
| {% if package_mode %} | ||
| packages = [ | ||
| { include = "lib" } | ||
| ] | ||
| {% else %} | ||
| package-mode = false | ||
| {% endif %} | ||
|
|
||
| [tool.poetry.dependencies] | ||
| python = ">=3.9,<=3.13.1" | ||
| infrahub-sdk = { extras = ["all"], version = "*" } | ||
| invoke = "*" | ||
|
|
||
| [tool.poetry.group.dev.dependencies] | ||
| ruff = "*" | ||
| pytest = "*" | ||
| infrahub-testcontainers = "*" | ||
| pytest-asyncio = "*" | ||
|
|
||
| [build-system] | ||
| requires = ["poetry-core"] | ||
| build-backend = "poetry.core.masonry.api" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| # yaml-language-server: $schema=https://schema.infrahub.app/infrahub/schema/latest.json | ||
| --- | ||
| version: "1.0" | ||
| nodes: | ||
| - name: Device | ||
| namespace: Network | ||
| human_friendly_id: ['hostname__value'] | ||
| attributes: | ||
| - name: hostname | ||
| kind: Text | ||
| unique: true | ||
| - name: model | ||
| kind: Text | ||
| relationships: | ||
| - name: interfaces | ||
| cardinality: many | ||
| peer: NetworkInterface | ||
| kind: Component | ||
| - name: Interface | ||
| namespace: Network | ||
| attributes: | ||
| - name: name | ||
| kind: Text | ||
| - name: description | ||
| kind: Text | ||
| optional: true | ||
| relationships: | ||
| - name: device | ||
| cardinality: one | ||
| peer: NetworkDevice | ||
| optional: false | ||
| kind: Parent |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| import os | ||
| from pathlib import Path | ||
|
|
||
| import httpx | ||
| from invoke import Context, task | ||
|
|
||
| # If no version is indicated, we will take the latest | ||
| VERSION = os.getenv("INFRAHUB_IMAGE_VER", None) | ||
|
|
||
|
|
||
| @task | ||
| def start(context: Context) -> None: | ||
| """ | ||
| Start the services using docker-compose in detached mode. | ||
| """ | ||
| download_compose_file(context, override=False) | ||
| context.run("docker compose up -d") | ||
|
|
||
|
|
||
| @task | ||
| def destroy(context: Context) -> None: | ||
| """ | ||
| Stop and remove containers, networks, and volumes. | ||
| """ | ||
| download_compose_file(context, override=False) | ||
| context.run("docker compose down -v") | ||
|
|
||
|
|
||
| @task | ||
| def stop(context: Context) -> None: | ||
| """ | ||
| Stop containers and remove networks. | ||
| """ | ||
| download_compose_file(context, override=False) | ||
| context.run("docker compose down") | ||
|
|
||
|
|
||
| @task(help={"component": "Optional name of a specific service to restart."}) | ||
| def restart(context: Context, component: str = "") -> None: | ||
| """ | ||
| Restart all services or a specific one using docker-compose. | ||
| """ | ||
| download_compose_file(context, override=False) | ||
| if component: | ||
| context.run(f"docker compose restart {component}") | ||
| return | ||
|
|
||
| context.run("docker compose restart") | ||
|
|
||
|
|
||
| @task | ||
| def load_schema(ctx: Context) -> None: | ||
| """ | ||
| Load schemas into InfraHub using infrahubctl. | ||
| """ | ||
| ctx.run("infrahubctl schema load schemas") | ||
|
|
||
|
|
||
| @task | ||
| def test(ctx: Context) -> None: | ||
| """ | ||
| Run tests using pytest. | ||
| """ | ||
| ctx.run("pytest tests") | ||
|
|
||
|
|
||
| @task(help={"override": "Redownload the compose file even if it already exists."}) | ||
| def download_compose_file(context: Context, override: bool = False) -> Path: # noqa ARG001 | ||
| """ | ||
| Download docker-compose.yml from InfraHub if missing or override is True. | ||
| """ | ||
| compose_file = Path("./docker-compose.yml") | ||
|
|
||
| if compose_file.exists() and not override: | ||
| return compose_file | ||
|
|
||
| response = httpx.get("https://infrahub.opsmill.io") | ||
| response.raise_for_status() | ||
|
|
||
| with compose_file.open("w") as f: | ||
| f.write(response.content.decode()) | ||
|
|
||
| return compose_file |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| import logging | ||
|
|
||
| from infrahub_sdk.node import InfrahubNode | ||
|
|
||
|
|
||
| def print_nodes(log: logging.Logger, nodes: list[InfrahubNode]): | ||
| for node in nodes.keys(): | ||
| log.info(f"{node} present.") |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| import logging | ||
|
|
||
| from lib.example import print_nodes | ||
|
|
||
| from infrahub_sdk import InfrahubClient | ||
|
|
||
|
|
||
| async def run( | ||
| client: InfrahubClient, | ||
| log: logging.Logger, | ||
| branch: str, | ||
| ): | ||
| log.info(f"Running example script on {branch}...") | ||
| nodes = await client.schema.all() | ||
| print_nodes(log, nodes) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| from pathlib import Path | ||
| from typing import Any | ||
|
|
||
| import pytest | ||
|
|
||
| from infrahub_sdk.yaml import SchemaFile | ||
|
|
||
| CURRENT_DIRECTORY = Path(__file__).parent.resolve() | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| def root_directory() -> Path: | ||
| """ | ||
| Return the path of the root directory of the repository. | ||
| """ | ||
| return CURRENT_DIRECTORY.parent.parent | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| def schemas_directory(root_directory: Path) -> Path: | ||
| return root_directory / "schemas" | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| def schemas(schemas_directory: Path) -> list[dict[str, Any]]: | ||
| schema_files = SchemaFile.load_from_disk(paths=[schemas_directory]) | ||
| return [item.content for item in schema_files if item.content] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| from pathlib import Path | ||
|
|
||
| import pytest | ||
|
|
||
| from infrahub_sdk import InfrahubClient | ||
| from infrahub_sdk.protocols import CoreGenericRepository | ||
| from infrahub_sdk.testing.docker import TestInfrahubDockerClient | ||
| from infrahub_sdk.testing.repository import GitRepo | ||
|
|
||
|
|
||
| class TestInfrahub(TestInfrahubDockerClient): | ||
| @pytest.mark.asyncio | ||
| async def test_load_schema(self, default_branch: str, client: InfrahubClient, schemas: list[dict]): | ||
| await client.schema.wait_until_converged(branch=default_branch) | ||
|
|
||
| resp = await client.schema.load(schemas=schemas, branch=default_branch, wait_until_converged=True) | ||
| assert resp.errors == {} | ||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_load_repository( | ||
| self, | ||
| client: InfrahubClient, | ||
| remote_repos_dir: Path, | ||
| root_directory: Path, | ||
| ) -> None: | ||
| """Add the local directory as a repository in Infrahub and wait for the import to be complete""" | ||
|
|
||
| repo = GitRepo( | ||
| name="local-repository", | ||
| src_directory=root_directory, | ||
| dst_directory=remote_repos_dir, | ||
| ) | ||
| await repo.add_to_infrahub(client=client) | ||
| in_sync = await repo.wait_for_sync_to_complete(client=client) | ||
| assert in_sync | ||
|
|
||
| repos = await client.all(kind=CoreGenericRepository) | ||
|
|
||
| # A breakpoint can be added to pause the tests from running and keep the test containers active | ||
| # breakpoint() | ||
|
|
||
| assert repos |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| # Changes here will be overwritten by Copier | ||
| {{ _copier_answers|to_nice_yaml -}} |
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.
It's not clear what DST is, or what it is that we are supposed to provide.
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.
Should DST be optional? If not provided, we could make a directory from the project name that we prompt for.
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.
Unfortunately from what I read copier requires the destination to be known upfront before the prompt appears using the
run_copyfunction. By default copier will usecwdif nothing is passed in. which would require this workflow. We are using package name more for thepyproject.tomlpackage name.Rather than just
infrahubctl repository init infrahub-repoThere 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.
DST now also has help to explain what it is.