diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 441e305..f968e4d 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -2,17 +2,16 @@ { "name": "Codefresh Support Package", "image": "mcr.microsoft.com/devcontainers/universal:3", - "onCreateCommand": "curl -fsSL https://deno.land/install.sh | sh -s -- -y", + "postCreateCommand": "pip install -e .", "customizations": { "vscode": { - "settings": { - "deno.enable": true, - "deno.lint": true - }, + // "settings": { + // }, "extensions": [ - "denoland.vscode-deno", "davidanson.vscode-markdownlint", - "redhat.vscode-yaml" + "redhat.vscode-yaml", + "usernamehw.errorlens", + "ms-python.python" ] } } diff --git a/.gitignore b/.gitignore index 13c73c3..baaeda2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,132 +1,33 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.pyc +*.pyd +*.so + +# Virtual environment +venv/ +.venv/ +env/ + +# IDE specific files +.idea/ +*.iml +.vscode/ + +# Jupyter Notebook +.ipynb_checkpoints + +# Distribution / build files +dist/ +build/ +*.egg-info/ + # Logs -logs *.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* -.pnpm-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) -web_modules/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional stylelint cache -.stylelintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variable files -.env -.env.development.local -.env.test.local -.env.production.local -.env.local - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# Next.js build output -.next -out - -# Nuxt.js build / generate output -.nuxt -dist - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# vuepress v2.x temp and cache directory -.temp -.cache - -# Docusaurus cache and generated files -.docusaurus - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port - -# Stores VSCode versions used for testing VSCode extensions -.vscode-test - -# yarn v2 -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.yarn/install-state.gz -.pnp.* +# OS generated files .DS_Store -bin \ No newline at end of file +Thumbs.db + +# Auto Generated Version +_version.py \ No newline at end of file diff --git a/codresh-support-package.env b/codresh-support-package.env new file mode 100644 index 0000000..0309f0c --- /dev/null +++ b/codresh-support-package.env @@ -0,0 +1,3 @@ +CF_API_KEY= +CF_URL= +USERPROFILE= \ No newline at end of file diff --git a/deno.json b/old/deno.json similarity index 100% rename from deno.json rename to old/deno.json diff --git a/deno.lock b/old/deno.lock similarity index 100% rename from deno.lock rename to old/deno.lock diff --git a/main.js b/old/main.js similarity index 100% rename from main.js rename to old/main.js diff --git a/src/gitops.js b/old/src/gitops.js similarity index 100% rename from src/gitops.js rename to old/src/gitops.js diff --git a/src/index.js b/old/src/index.js similarity index 100% rename from src/index.js rename to old/src/index.js diff --git a/src/logic/codefresh.js b/old/src/logic/codefresh.js similarity index 100% rename from src/logic/codefresh.js rename to old/src/logic/codefresh.js diff --git a/src/logic/core.js b/old/src/logic/core.js similarity index 100% rename from src/logic/core.js rename to old/src/logic/core.js diff --git a/src/logic/k8s.js b/old/src/logic/k8s.js similarity index 100% rename from src/logic/k8s.js rename to old/src/logic/k8s.js diff --git a/src/onprem.js b/old/src/onprem.js similarity index 100% rename from src/onprem.js rename to old/src/onprem.js diff --git a/src/oss.js b/old/src/oss.js similarity index 100% rename from src/oss.js rename to old/src/oss.js diff --git a/src/pipelines.js b/old/src/pipelines.js similarity index 100% rename from src/pipelines.js rename to old/src/pipelines.js diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..1158a6c --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,23 @@ +[project] +name = "cf-support" +dynamic = ["version"] +description = "Codefresh Support Package" +authors = [{ name = "Codefresh Support", email = "support@codefresh.io" }] +readme = "README.md" +requires-python = ">=3.12" +dependencies = [ + "click>=8.1", + "kubernetes>=31.1", + "PyYAML>=6.0", + "requests>=2.32" +] + +[project.scripts] +cf-support = "cf_support.cli:cli" + +[build-system] +requires = ["setuptools>=80.9", "setuptools_scm[toml]>=8.3"] +build-backend = "setuptools.build_meta" + +[tool.setuptools_scm] +write_to = "src/cf_support/_version.py" \ No newline at end of file diff --git a/src/cf_support/cli.py b/src/cf_support/cli.py new file mode 100644 index 0000000..e6b4f08 --- /dev/null +++ b/src/cf_support/cli.py @@ -0,0 +1,23 @@ +import click +from .commands import pipelines, gitops, onprem, oss + +try: + from ._version import version as __version__ +except ImportError: + __version__ = "0.0.0+dev.uninstalled" + +@click.group() +@click.version_option(version=__version__, prog_name="cf-support") +def cli(): + """Codefresh Support Package + + Tool to gather information for Codefresh Support + """ + pass + +# Add individual commands directly to the main 'cli' group +cli.add_command(pipelines.pipelines_command) +cli.add_command(gitops.gitops_command) +cli.add_command(onprem.onprem_command) +cli.add_command(oss.oss_command) + diff --git a/src/cf_support/commands/gitops.py b/src/cf_support/commands/gitops.py new file mode 100644 index 0000000..bb6483f --- /dev/null +++ b/src/cf_support/commands/gitops.py @@ -0,0 +1,10 @@ +import click + +@click.command(name='gitops') # Use @click.command() directly +@click.option('-n','--namespace', help='The namespace where the GitOps Runtime is installed') +def gitops_command(namespace): + """Collect data for the Codefresh GitOps Runtime""" + + click.echo(f"Executing pipelines command with filter: {filter if filter else 'none'}") + # Add your core logic for the 'pipelines' command here. + # This might involve calling functions from 'utils.py' or directly performing actions. \ No newline at end of file diff --git a/src/cf_support/commands/onprem.py b/src/cf_support/commands/onprem.py new file mode 100644 index 0000000..c62e827 --- /dev/null +++ b/src/cf_support/commands/onprem.py @@ -0,0 +1,10 @@ +import click + +@click.command(name='onprem') # Use @click.command() directly +@click.option('-n','--namespace', help='The namespace where Codefresh OnPrem is installed') +def onprem_command(namespace): + """Collect data for the Codefresh OnPrem Installation""" + + click.echo(f"Executing pipelines command with filter: {filter if filter else 'none'}") + # Add your core logic for the 'pipelines' command here. + # This might involve calling functions from 'utils.py' or directly performing actions. \ No newline at end of file diff --git a/src/cf_support/commands/oss.py b/src/cf_support/commands/oss.py new file mode 100644 index 0000000..c12ef73 --- /dev/null +++ b/src/cf_support/commands/oss.py @@ -0,0 +1,10 @@ +import click + +@click.command(name='oss') # Use @click.command() directly +@click.option('-n','--namespace', help='The namespace where the OSS ArgoCD is installed') +def oss_command(namespace): + """Collect data for the Open Source ArgoCD""" + + click.echo(f"Executing pipelines command with filter: {filter if filter else 'none'}") + # Add your core logic for the 'pipelines' command here. + # This might involve calling functions from 'utils.py' or directly performing actions. \ No newline at end of file diff --git a/src/cf_support/commands/pipelines.py b/src/cf_support/commands/pipelines.py new file mode 100644 index 0000000..bf3d46e --- /dev/null +++ b/src/cf_support/commands/pipelines.py @@ -0,0 +1,11 @@ +import click + +@click.command(name='pipelines') # Use @click.command() directly +@click.option('-n','--namespace', help='The namespace where the Pipelines Runtime is installed') +@click.option('-r','--runtime', help='The name of the Pipelines Runtime') +def pipelines_command(namespace, runtime): + """Collect data for the Codefresh Pipelines Runtime""" + + click.echo(f"Executing pipelines command with filter: {filter if filter else 'none'}") + # Add your core logic for the 'pipelines' command here. + # This might involve calling functions from 'utils.py' or directly performing actions. \ No newline at end of file diff --git a/src/cf_support/logic/codefresh.py b/src/cf_support/logic/codefresh.py new file mode 100644 index 0000000..0973cea --- /dev/null +++ b/src/cf_support/logic/codefresh.py @@ -0,0 +1,58 @@ +from dotenv import load_dotenv +import requests +import yaml +import sys +import os + + +load_dotenv() + + +# TODO: Add this when we break out the main function +# required_env_vars: list[str] = ["CF_API_KEY", "CF_URL"] + +# for var in required_env_vars: +# if not var: +# sys.exit(f"Environment variable {var} is not defined") + + + +def get_runtime_spec(cf_creds, runtime): + response = requests.get( + f"{cf_creds['base_url']}/runtime-environments/{runtime}", + headers=cf_creds["headers"], + ) + return response.json() + + +def get_all_accounts(cf_creds): + response = requests.get( + f"{cf_creds['base_url']}/admin/accounts", + headers=cf_creds["headers"], + ) + return response.json() + + +def get_all_runtimes(cf_creds): + response = requests.get( + f"{cf_creds['base_url']}/admin/runtime-environments", + headers=cf_creds["headers"], + ) + return response.json() + + +def get_total_users(cf_creds): + response = requests.get( + f"{cf_creds['base_url']}/admin/user?limit=1&page=1", + headers=cf_creds["headers"], + ) + users = response.json() + return {"totalUsers": users["total"]} + + +def get_system_feature_flags(cf_creds): + response = requests.get( + f"{cf_creds['base_url']}/admin/features", + headers=cf_creds["headers"], + ) + return response.json() diff --git a/src/cf_support/logic/controllers/account_controller.py b/src/cf_support/logic/controllers/account_controller.py new file mode 100644 index 0000000..a5a08a2 --- /dev/null +++ b/src/cf_support/logic/controllers/account_controller.py @@ -0,0 +1,14 @@ +import requests + + +class AccountController: + def __init__(self, cf_creds: dict[str, dict[str, str]]) -> None: + self.base_url = cf_creds["base_url"] + self.auth_headers = cf_creds["headers"] + + def get_runtimes(self): + response = requests.get( + f"{self.base_url}/runtime-environments", + headers=self.auth_headers["headers"], # type: ignore + ) + return response.json() diff --git a/src/cf_support/logic/controllers/auth_controller.py b/src/cf_support/logic/controllers/auth_controller.py new file mode 100644 index 0000000..1c65ca6 --- /dev/null +++ b/src/cf_support/logic/controllers/auth_controller.py @@ -0,0 +1,48 @@ +import yaml +import os + + +class AuthController: + def __init__(self, env_token: str | None, env_url: str | None) -> None: + self.env_token = env_token + self.env_url = env_url + + def get_cf_credentials( + self, + ) -> dict[str, dict[str, str] | str] | None: + env_token = self.env_token + env_url = self.env_url + cf_credentials: dict[str, dict[str, str] | str] | None = None + + if env_token and env_url: + auth_header: dict[str, str] = {"Authorization": env_token} + + cf_credentials = { + "headers": auth_header, + "base_url": f"{env_url}/api", + } + + else: + config_path = ( + f"{os.getenv('USERPROFILE')}/.cfconfig" + if os.name == "nt" + else f"{os.getenv('HOME')}/.cfconfig" + ) + + with open(config_path, "r") as config_file: + config = yaml.safe_load(config_file) + + current_context = config["contexts"].get(config["current-context"]) + + if current_context: + context_token = current_context["token"] + context_url = current_context["url"] + + if context_token and context_url: + auth_header = {"Authorization": context_token} + cf_credentials = { + "headers": auth_header, + "base_url": f"{context_url}/api", + } + + return cf_credentials diff --git a/src/cf_support/logic/controllers/runtime_controller.py b/src/cf_support/logic/controllers/runtime_controller.py new file mode 100644 index 0000000..55bf49b --- /dev/null +++ b/src/cf_support/logic/controllers/runtime_controller.py @@ -0,0 +1,14 @@ +import requests + + +class RuntimeController: + def __init__(self, cf_creds: dict[str, dict[str, str]]) -> None: + self.base_url = cf_creds["base_url"] + self.auth_headers = cf_creds["headers"] + + def get_spec(self, runtime_name: str): + response = requests.get( + f"{self.base_url}/runtime-environments/{runtime_name}", + headers=self.auth_headers, + ) + return response.json() diff --git a/src/cf_support/logic/controllers/system_controller.py b/src/cf_support/logic/controllers/system_controller.py new file mode 100644 index 0000000..28a259c --- /dev/null +++ b/src/cf_support/logic/controllers/system_controller.py @@ -0,0 +1,37 @@ +import requests + + +class SystemController: + def __init__(self, cf_creds: dict[str, dict[str, str]]) -> None: + self.base_url = cf_creds["base_url"] + self.auth_headers = cf_creds["headers"] + + def get_all_accounts(self): + response = requests.get( + f"{self.base_url}/admin/accounts", + headers=self.auth_headers, + ) + return response.json() + + def get_all_runtimes(self): + response = requests.get( + f"{self.base_url}/admin/runtime-environments", + headers=self.auth_headers, + ) + return response.json() + + def get_feature_flags(self): + response = requests.get( + f"{self.base_url}/admin/features", + headers=self.auth_headers, + ) + return response.json() + + def get_total_users(self): + response = requests.get( + f"{self.base_url}/admin/user?limit=1&page=1", + headers=self.auth_headers, + ) + users = response.json() + + return {"totalUsers": users["total"]} diff --git a/src/cf_support/logic/controllers/user_controller.py b/src/cf_support/logic/controllers/user_controller.py new file mode 100644 index 0000000..e69de29 diff --git a/src/cf_support/logic/core.py b/src/cf_support/logic/core.py new file mode 100644 index 0000000..e69de29 diff --git a/src/cf_support/logic/k8s.py b/src/cf_support/logic/k8s.py new file mode 100644 index 0000000..e69de29 diff --git a/src/cf_support/logic/main.py b/src/cf_support/logic/main.py new file mode 100644 index 0000000..58ca014 --- /dev/null +++ b/src/cf_support/logic/main.py @@ -0,0 +1,14 @@ +from dotenv import load_dotenv +import os + +from .controllers.auth_controller import AuthController + +load_dotenv() + +def main(): + env_token = os.getenv("CF_API_KEY") + env_url = os.getenv("CF_URL") + auth_controller = AuthController(env_token, env_url) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/src/cf_support/logic/models/STUB b/src/cf_support/logic/models/STUB new file mode 100644 index 0000000..e69de29