Skip to content

Commit

Permalink
Merge pull request #7 from Qualytics/sc-15303/create-a-script-that-tr…
Browse files Browse the repository at this point in the history
…iggers-the-export

Create a script that triggers the export
  • Loading branch information
shindiogawa authored Dec 28, 2023
2 parents 323bc93 + df8f309 commit e2fb848
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 8 deletions.
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.1.3
current_version = 0.1.4
commit = True
tag = True
tag_name = {new_version}
Expand Down
112 changes: 108 additions & 4 deletions qualytics/qualytics.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,28 @@
import urllib3
import re
import jwt
from datetime import datetime, timezone
import platform
import subprocess

from datetime import datetime
from pathlib import Path
from rich import print
from rich.progress import track
from itertools import product
from typing import Optional
from typing_extensions import Annotated
from croniter import croniter


__version__ = "0.1.3"
__version__ = "0.1.4"

app = typer.Typer()

# Create a new Typer instance for checks
checks_app = typer.Typer(name="checks", help="Commands for handling checks")

# Create a new Typer instance for operation
schedule_app = typer.Typer(name="schedule", help="Commands for handling schedules")

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# Get the home directory
Expand All @@ -34,7 +39,8 @@
BASE_PATH = f"{home}/{folder_name}"

CONFIG_PATH = os.path.expanduser(f"{BASE_PATH}/config.json")

CRONTAB_ERROR_PATH = os.path.expanduser(f"{BASE_PATH}/schedule-operation-errors.txt")
CRONTAB_COMMANDS_PATH = os.path.expanduser(f"{BASE_PATH}/schedule-operation.txt")

def validate_and_format_url(url: str) -> str:
"""Validates and formats the URL to the desired structure."""
Expand Down Expand Up @@ -375,8 +381,106 @@ def checks_import(datastore: str = typer.Option(..., "--datastore",
distinct_file_content(BASE_PATH + "/errors.log")


@schedule_app.command("export-metadata")
def schedule(
crontab_expression: str = typer.Option(..., "--crontab", help="Crontab expression inside quotes, specifying when the task should run. Example: '0 * * * *' "),
datastore: str = typer.Option(..., "--datastore",help="The datastore ID"),
containers: Optional[str] = typer.Option(None, "--containers",help="Comma-separated list of containers IDs or array-like format. Example: \"1, 2, 3\" or \"[1,2,3]\""),
options: str = typer.Option(..., "--options", help="Comma-separated list of op to export or all for everything. Example: anomalies, checks, field-profiles or all"),
):

# Validate the crontab expression
try:
croniter(crontab_expression)
except ValueError:
print("[bold red] WARNING: Invalid crontab expression. Please provide a valid expression. [/bold red]")
return
if containers:
containers = [int(x.strip()) for x in containers.strip("[]").split(",")]

if "all" in options:
# If "all" is specified, include all metadata types
options = ["anomalies", "checks", "field-profiles"]
elif "," in options:
options = [str(x.strip()) for x in options.strip("[]").split(",")]
else:
options = [options]

config = load_config()
base_url = validate_and_format_url(config['url'])
token = is_token_valid(config['token'])

# Determine the operating system
operating_system = platform.system()

if token:
commands = []
# Construct the appropriate command based on the operating system

for option in options:
log_file_path = f'{BASE_PATH}/schedule_{option}.txt'
if operating_system == "Windows":
if containers:
containers_string = ''.join(f'&containers={container}' for container in containers)
powershell_script = (
f'Invoke-RestMethod -Method \'Post\' '
f'-Uri \"{base_url}export/{option}?datastore={datastore}{containers_string}\" '
f'-Headers @{{\'Authorization\' = \'Bearer {token}\'; \'Content-Type\' = \'application/json\'}} '
)

else:
powershell_script = (
f'Invoke-RestMethod -Method \'Post\' '
f'-Uri {base_url}export/{option}?datastore={datastore} '
f'-Headers @{{\'Authorization\' = \'Bearer {token}\'; \'Content-Type\' = \'application/json\'}} '
)

# powershell_script += f'$response | Out-File \'{log_file_path}\' -Append\''
script_name = f"task_scheduler_script_{option}_{datastore}.ps1"
# Save the PowerShell script to a file
script_location = BASE_PATH+"/"+script_name
with open(script_location, 'w') as ps_script_file:
ps_script_file.write(powershell_script)

# Print success message
print(f"[bold green]PowerShell script successfully created! Please check the script at: {script_location}[/bold green]")

elif operating_system == "Linux":

if containers:
command = f'{crontab_expression} /usr/bin/curl --request POST --url \'{base_url}export/{option}?datastore={datastore}\'' + ''.join(f'&containers={container}' for container in containers) + f' --header \'Authorization: Bearer {token}\' >> {log_file_path} 2>&1'
else:
command = f'{crontab_expression} /usr/bin/curl --request POST --url \'{base_url}export/{option}?datastore={datastore}\' --header \'Authorization: Bearer {token}\' >> {log_file_path} 2>&1'
commands.append(command)

if operating_system == "Linux":
cron_commands = "\n".join(commands)

with open(CRONTAB_COMMANDS_PATH, "a+") as file:
file.write(cron_commands + "\n")

# Run crontab command and add generated commands
try:
with open(CRONTAB_COMMANDS_PATH, 'r') as commands_file:
commands_content = commands_file.read()
# Use input redirection to pass the content of the file to the crontab command
subprocess.run(f'crontab -l 2>{CRONTAB_ERROR_PATH} | echo "{commands_content}" | crontab -', shell=True, check=True)
# subprocess.run(f'(crontab -l 2>{CRONTAB_ERROR_PATH}; cat {CRONTAB_COMMANDS_PATH}) | crontab -', shell=True, check=True)
print(f"[bold green]Crontab successfully created! Please check the cronjobs in {CRONTAB_COMMANDS_PATH} or run `crontab -l` to list all cronjobs[/bold green]")
except subprocess.CalledProcessError as e:
# Handle errors and write to the error file
print(f"[bold red] WARNING: There was an error in the crontab command. Please check the path: {CRONTAB_ERROR_PATH} [/bold red]")
with open(CRONTAB_ERROR_PATH, "a") as error_file:
current_datetime = datetime.now().strftime("[%m-%d-%Y %H:%M:%S]")
error_file.write(f"{current_datetime} : Error executing crontab command: {e}\n")
return


# Add the checks_app as a subcommand to the main app
app.add_typer(checks_app, name="checks")

# Add the schedule_app as a subcommand to the main app
app.add_typer(schedule_app, name="schedule")

if __name__ == "__main__":
app()
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
typer-cli
typer[all]
bump2version
pyjwt
pyjwt
croniter
5 changes: 3 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
'GitHub': 'https://github.com/Qualytics/qualytics-cli',
'Userguide': 'https://qualytics.github.io/userguide/'
}
__version__ = "0.1.3"
__version__ = "0.1.4"
setup(
name="qualytics-cli",
packages=find_packages(),
Expand All @@ -27,7 +27,8 @@
install_requires=[
"typer[all]",
"requests",
"pyjwt"
"pyjwt",
"croniter",
],
entry_points={
'console_scripts': ['qualytics=qualytics.qualytics:app']
Expand Down

0 comments on commit e2fb848

Please sign in to comment.