Skip to content
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

🎉 octavia-cli: Add ability to import existing resources #14137

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
aa1ff16
init
danieldiamond May 26, 2022
19a52a2
Update docs and add tests
danieldiamond May 27, 2022
0150ae9
Revert docker run docs
danieldiamond May 27, 2022
7748d63
Add "update" commands
danieldiamond May 29, 2022
58303ea
Add "update sources" and "update destinations" to create yaml files f…
danieldiamond May 29, 2022
d66efbc
Merge branch 'master' into danieldiamond/octavia-cli-generate-existin…
danieldiamond Jun 24, 2022
48676c1
WIP
danieldiamond Jun 24, 2022
89549dc
Revert "WIP"
danieldiamond Jun 24, 2022
87f6b48
Remove update method
danieldiamond Jun 24, 2022
a41fd9b
Merge branch 'master' into danieldiamond/octavia-cli-generate-existin…
danieldiamond Jun 24, 2022
29c3a64
Remove update from tests
danieldiamond Jun 24, 2022
35d9cdd
Remove update related methods in generate_renderers
danieldiamond Jun 24, 2022
a4b03ed
Merge branch 'master' into danieldiamond/octavia-cli-generate-existin…
danieldiamond Jun 26, 2022
528afc1
Reformat get commands
danieldiamond Jun 26, 2022
e376f4e
Remove DuplicateResourceError from apply
danieldiamond Jun 26, 2022
3d96529
Remove ConnectorRenderer from generate
danieldiamond Jun 26, 2022
6f3944d
Update unit tests for commands and resources
danieldiamond Jun 26, 2022
c44903e
Update docs and setup
danieldiamond Jun 26, 2022
c31f2bc
init import commands
danieldiamond Jun 26, 2022
810b089
Add quotes to handle yaml characters
danieldiamond Jun 26, 2022
f147e27
Add source and destination commands
danieldiamond Jun 26, 2022
18f6967
Remove ConnectorRenderer from generate
danieldiamond Jun 26, 2022
3ec8ce3
Merge branch 'master' into danieldiamond/octavia-cli-import
alafanechere Jun 27, 2022
9cc897e
Remove commands for import of multiple resources
danieldiamond Jun 27, 2022
da2e0b5
Improve writes: Avoid intermediate yaml file saved to disk, check if …
danieldiamond Jun 27, 2022
42d37a5
Manage connections and store state
danieldiamond Jun 27, 2022
a55547d
Make resource_requirements an optional field in apply.resources
danieldiamond Jun 28, 2022
654e3a3
Slugify resource_name in get_output_path method in generate.renderers
danieldiamond Jun 28, 2022
108d8a4
Add docstring to import commands
danieldiamond Jun 28, 2022
e1dc6fd
Merge branch 'master' into danieldiamond/octavia-cli-import
danieldiamond Jun 28, 2022
57371e3
Add user warning message to update secrets in source or destination
danieldiamond Jun 28, 2022
8779a00
add slugify dependency
alafanechere Jun 29, 2022
678f8db
write unit tests
alafanechere Jun 29, 2022
cbd183b
wip integration tests
alafanechere Jun 29, 2022
938eef0
fix connection config for integration tests
alafanechere Jun 30, 2022
305bafe
improve connection config cleaning on import
alafanechere Jun 30, 2022
efaa21f
finish integration tests
alafanechere Jun 30, 2022
fa69f09
Merge branch 'master' into danieldiamond/octavia-cli-import
alafanechere Jun 30, 2022
488dc01
update readme
alafanechere Jun 30, 2022
b62796c
update readme
alafanechere Jun 30, 2022
e38c422
update readme
alafanechere Jun 30, 2022
1e26425
update readme
alafanechere Jun 30, 2022
269ffdc
update readme
alafanechere Jun 30, 2022
470824b
Merge branch 'master' into danieldiamond/octavia-cli-import
danieldiamond Jun 30, 2022
3c359fe
Iterate on import_configuration in ConnectionRenderer
danieldiamond Jun 30, 2022
36904d2
fix docstring + clean
alafanechere Jul 1, 2022
2c7dfbb
bump to the right version
alafanechere Jul 1, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Improve writes: Avoid intermediate yaml file saved to disk, check if …
…file exists & make user confirm overwrite
  • Loading branch information
danieldiamond committed Jun 27, 2022
commit da2e0b5b24b5a40a742f0dc661203b33a825e326
9 changes: 5 additions & 4 deletions octavia-cli/octavia_cli/_import/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,18 @@ def import_resource(
Returns:
str: The resource's JSON representation.
"""
config = json.loads(get_json_representation(api_client, workspace_id, ResourceCls, resource_to_get))
remote_configuration = json.loads(get_json_representation(api_client, workspace_id, ResourceCls, resource_to_get))

resource_type = ResourceCls.__name__.lower()

definition = definitions.factory(resource_type, api_client, workspace_id, config[f"{resource_type}_definition_id"])
definition = definitions.factory(resource_type, api_client, workspace_id, remote_configuration[f"{resource_type}_definition_id"])

renderer = ConnectorSpecificationRenderer(config["name"], definition)
renderer = ConnectorSpecificationRenderer(remote_configuration["name"], definition)

output_path = renderer.import_configuration(project_path=".", configuration=config["connection_configuration"])
output_path = renderer.import_configuration(project_path=".", configuration=remote_configuration["connection_configuration"])
message = f"✅ - Imported {resource_type} in {output_path}."
click.echo(click.style(message, fg="green"))
# TODO add message to ask users to update secrets


@click.group(
Expand Down
63 changes: 28 additions & 35 deletions octavia-cli/octavia_cli/generate/renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

import abc
import os
from pathlib import Path
from typing import Any, Callable, List

import click
import yaml
from airbyte_api_client.model.airbyte_catalog import AirbyteCatalog
from jinja2 import Environment, PackageLoader, Template, select_autoescape
Expand All @@ -20,7 +22,6 @@
class FieldToRender:
def __init__(self, name: str, required: bool, field_metadata: dict) -> None:
"""Initialize a FieldToRender instance

Args:
name (str): name of the field
required (bool): whether it's a required field or not
Expand All @@ -45,10 +46,8 @@ def __init__(self, name: str, required: bool, field_metadata: dict) -> None:

def __getattr__(self, name: str) -> Any:
"""Map field_metadata keys to attributes of Field.

Args:
name (str): attribute name

Returns:
[Any]: attribute value
"""
Expand Down Expand Up @@ -78,7 +77,6 @@ def _get_one_of_values(self) -> List[List["FieldToRender"]]:

def _get_array_items(self) -> List["FieldToRender"]:
"""If the field is an array of objects, retrieve fields of these objects.

Returns:
[list]: List of fields
"""
Expand Down Expand Up @@ -147,67 +145,67 @@ def TEMPLATE(
def __init__(self, resource_name: str) -> None:
self.resource_name = resource_name

def _get_output_path(self, project_path: str, definition_type: str) -> str:
def _get_output_path(self, project_path: str, definition_type: str) -> Path:
"""Get rendered file output path

Args:
project_path (str): Current project path.
definition_type (str): Current definition_type.

Returns:
str: Full path to the output path.
"""
directory = os.path.join(project_path, f"{definition_type}s", self.resource_name)
if not os.path.exists(directory):
os.makedirs(directory)
return os.path.join(directory, "configuration.yaml")
return Path(os.path.join(directory, "configuration.yaml"))

@abc.abstractmethod
def _render(self): # pragma: no cover
"""Runs the template rendering.

Raises:
NotImplementedError: Must be implemented on subclasses.
"""
raise NotImplementedError

def write_yaml(self, project_path: str) -> str:
@staticmethod
def _confirm_overwrite(output_path):
overwrite = True
if output_path.is_file():
overwrite = click.confirm(
f"The configuration octavia-cli is about to create already exists, do you want to replace it? ({output_path})"
)
return overwrite

def write_yaml(self, project_path: Path) -> str:
"""Write rendered specification to a YAML file in local project path.

Args:
project_path (str): Path to directory hosting the octavia project.

Returns:
str: Path to the rendered specification.
"""
output_path = self._get_output_path(project_path, self.definition.type)
rendered = self._render()

with open(output_path, "w") as f:
f.write(rendered)
if self._confirm_overwrite(output_path):
with open(output_path, "w") as f:
rendered_yaml = self._render()
f.write(rendered_yaml)
return output_path

def import_configuration(self, project_path: str, configuration: dict) -> str:
def import_configuration(self, project_path: Path, configuration: dict) -> Path:
"""Import configuration from the YAML file in local project path.
If local configuration.yaml file exists, it is replaced.

Args:
project_path (str): Path to directory hosting the octavia project.
configuration (dict): Configuraton of the resource.

project_path (Path): Path to directory hosting the octavia project.
configuration (dict): Configuration of the resource.
Returns:
str: Path to the rendered specification.
Path: Path to the rendered specification.
"""
output_path = self.write_yaml(project_path)

with open(output_path) as f:
data = yaml.safe_load(f)

rendered = self._render()
data = yaml.safe_load(rendered)
data["configuration"] = configuration

with open(output_path, "wb") as f:
yaml.safe_dump(data, f, default_flow_style=False, sort_keys=False, allow_unicode=True, encoding="utf-8")

output_path = self._get_output_path(project_path, self.definition.type)
if self._confirm_overwrite(output_path):
with open(output_path, "wb") as f:
yaml.safe_dump(data, f, default_flow_style=False, sort_keys=False, allow_unicode=True, encoding="utf-8")
return output_path


Expand All @@ -216,7 +214,6 @@ class ConnectorSpecificationRenderer(BaseRenderer):

def __init__(self, resource_name: str, definition: BaseDefinition) -> None:
"""Connector specification renderer constructor.

Args:
resource_name (str): Name of the source or destination.
definition (BaseDefinition): The definition related to a source or a destination.
Expand All @@ -226,7 +223,6 @@ def __init__(self, resource_name: str, definition: BaseDefinition) -> None:

def _parse_connection_specification(self, schema: dict) -> List[List["FieldToRender"]]:
"""Create a renderable structure from the specification schema

Returns:
List[List["FieldToRender"]]: List of list of fields to render.
"""
Expand Down Expand Up @@ -254,7 +250,6 @@ class ConnectionRenderer(BaseRenderer):

def __init__(self, connection_name: str, source: resources.Source, destination: resources.Destination) -> None:
"""Connection renderer constructor.

Args:
connection_name (str): Name of the connection to render.
source (resources.Source): Connection's source.
Expand All @@ -267,10 +262,8 @@ def __init__(self, connection_name: str, source: resources.Source, destination:
@staticmethod
def catalog_to_yaml(catalog: AirbyteCatalog) -> str:
"""Convert the source catalog to a YAML string.

Args:
catalog (AirbyteCatalog): Source's catalog.

Returns:
str: Catalog rendered as yaml.
"""
Expand Down