|
1 | 1 | import json
|
2 | 2 | import os
|
| 3 | +import platform |
3 | 4 | import random
|
4 | 5 | import subprocess
|
5 | 6 | import sys
|
| 7 | +from dataclasses import dataclass |
| 8 | +from enum import Enum, auto |
6 | 9 | from importlib.resources import files
|
7 | 10 | from pathlib import Path
|
| 11 | +from typing import Callable |
8 | 12 |
|
9 | 13 | import click
|
10 | 14 | import inquirer
|
@@ -46,25 +50,225 @@ def cli():
|
46 | 50 | @cli.command()
|
47 | 51 | def quickstart():
|
48 | 52 | """Setup warnet"""
|
| 53 | + |
| 54 | + class ToolStatus(Enum): |
| 55 | + Satisfied = auto() |
| 56 | + Unsatisfied = auto() |
| 57 | + |
| 58 | + @dataclass |
| 59 | + class ToolInfo: |
| 60 | + tool_name: str |
| 61 | + is_installed_func: Callable[[], tuple[bool, str]] |
| 62 | + install_instruction: str |
| 63 | + install_url: str |
| 64 | + |
| 65 | + __slots__ = ["tool_name", "is_installed_func", "install_instruction", "install_url"] |
| 66 | + |
| 67 | + def is_minikube_installed() -> tuple[bool, str]: |
| 68 | + try: |
| 69 | + version_result = subprocess.run( |
| 70 | + ["minikube", "version", "--short"], |
| 71 | + capture_output=True, |
| 72 | + text=True, |
| 73 | + ) |
| 74 | + location_result = subprocess.run( |
| 75 | + ["which", "minikube"], |
| 76 | + capture_output=True, |
| 77 | + text=True, |
| 78 | + ) |
| 79 | + if version_result.returncode == 0 and location_result.returncode == 0: |
| 80 | + return True, location_result.stdout.strip() |
| 81 | + else: |
| 82 | + return False, "" |
| 83 | + except FileNotFoundError as err: |
| 84 | + return False, str(err) |
| 85 | + |
| 86 | + def is_minikube_version_valid_on_darwin() -> tuple[bool, str]: |
| 87 | + try: |
| 88 | + version_result = subprocess.run( |
| 89 | + ["minikube", "version", "--short"], |
| 90 | + capture_output=True, |
| 91 | + text=True, |
| 92 | + ) |
| 93 | + location_result = subprocess.run( |
| 94 | + ["which", "minikube"], |
| 95 | + capture_output=True, |
| 96 | + text=True, |
| 97 | + ) |
| 98 | + if version_result.returncode == 0 and location_result.returncode == 0: |
| 99 | + version = version_result.stdout.strip().split()[-1] # Get the version number |
| 100 | + return version not in [ |
| 101 | + "v1.32.0", |
| 102 | + "1.33.0", |
| 103 | + ], f"{location_result.stdout.strip()} ({version})" |
| 104 | + else: |
| 105 | + return False, "" |
| 106 | + except FileNotFoundError as err: |
| 107 | + return False, str(err) |
| 108 | + |
| 109 | + def is_platform_darwin() -> bool: |
| 110 | + return platform.system() == "Darwin" |
| 111 | + |
| 112 | + def is_docker_installed() -> tuple[bool, str]: |
| 113 | + try: |
| 114 | + version_result = subprocess.run(["docker", "--version"], capture_output=True, text=True) |
| 115 | + location_result = subprocess.run( |
| 116 | + ["which", "docker"], |
| 117 | + capture_output=True, |
| 118 | + text=True, |
| 119 | + ) |
| 120 | + if version_result.returncode == 0 and location_result.returncode == 0: |
| 121 | + return True, location_result.stdout.strip() |
| 122 | + else: |
| 123 | + return False, "" |
| 124 | + except FileNotFoundError as err: |
| 125 | + return False, str(err) |
| 126 | + |
| 127 | + def is_docker_desktop_running() -> tuple[bool, str]: |
| 128 | + try: |
| 129 | + version_result = subprocess.run(["docker", "info"], capture_output=True, text=True) |
| 130 | + location_result = subprocess.run( |
| 131 | + ["which", "docker"], |
| 132 | + capture_output=True, |
| 133 | + text=True, |
| 134 | + ) |
| 135 | + if version_result.returncode == 0 and location_result.returncode == 0: |
| 136 | + return "Docker Desktop" in version_result.stdout, location_result.stdout.strip() |
| 137 | + else: |
| 138 | + return False, "" |
| 139 | + except FileNotFoundError as err: |
| 140 | + return False, str(err) |
| 141 | + |
| 142 | + def is_kubectl_installed() -> tuple[bool, str]: |
| 143 | + try: |
| 144 | + version_result = subprocess.run( |
| 145 | + ["kubectl", "version", "--client"], |
| 146 | + capture_output=True, |
| 147 | + text=True, |
| 148 | + ) |
| 149 | + location_result = subprocess.run( |
| 150 | + ["which", "kubectl"], |
| 151 | + capture_output=True, |
| 152 | + text=True, |
| 153 | + ) |
| 154 | + if version_result.returncode == 0 and location_result.returncode == 0: |
| 155 | + return True, location_result.stdout.strip() |
| 156 | + else: |
| 157 | + return False, "" |
| 158 | + except FileNotFoundError as err: |
| 159 | + return False, str(err) |
| 160 | + |
| 161 | + def is_helm_installed() -> tuple[bool, str]: |
| 162 | + try: |
| 163 | + version_result = subprocess.run(["helm", "version"], capture_output=True, text=True) |
| 164 | + location_result = subprocess.run( |
| 165 | + ["which", "helm"], |
| 166 | + capture_output=True, |
| 167 | + text=True, |
| 168 | + ) |
| 169 | + if version_result.returncode == 0 and location_result.returncode == 0: |
| 170 | + return version_result.returncode == 0, location_result.stdout.strip() |
| 171 | + else: |
| 172 | + return False, "" |
| 173 | + except FileNotFoundError as err: |
| 174 | + return False, str(err) |
| 175 | + |
| 176 | + def check_installation(tool_info: ToolInfo) -> ToolStatus: |
| 177 | + has_good_version, location = tool_info.is_installed_func() |
| 178 | + if not has_good_version: |
| 179 | + instruction_label = click.style(" Instruction: ", fg="yellow", bold=True) |
| 180 | + instruction_text = click.style(f"{tool_info.install_instruction}", fg="yellow") |
| 181 | + url_label = click.style(" URL: ", fg="yellow", bold=True) |
| 182 | + url_text = click.style(f"{tool_info.install_url}", fg="yellow") |
| 183 | + |
| 184 | + click.secho(f" 💥 {tool_info.tool_name} is not installed. {location}", fg="yellow") |
| 185 | + click.echo(instruction_label + instruction_text) |
| 186 | + click.echo(url_label + url_text) |
| 187 | + return ToolStatus.Unsatisfied |
| 188 | + else: |
| 189 | + click.secho(f" ⭐️ {tool_info.tool_name} is satisfied: {location}", bold=False) |
| 190 | + return ToolStatus.Satisfied |
| 191 | + |
| 192 | + docker_info = ToolInfo( |
| 193 | + tool_name="Docker", |
| 194 | + is_installed_func=is_docker_installed, |
| 195 | + install_instruction="Install Docker from Docker's official site.", |
| 196 | + install_url="https://docs.docker.com/engine/install/", |
| 197 | + ) |
| 198 | + docker_desktop_info = ToolInfo( |
| 199 | + tool_name="Docker Desktop", |
| 200 | + is_installed_func=is_docker_desktop_running, |
| 201 | + install_instruction="Make sure Docker Desktop is installed and running.", |
| 202 | + install_url="https://docs.docker.com/desktop/", |
| 203 | + ) |
| 204 | + kubectl_info = ToolInfo( |
| 205 | + tool_name="Kubectl", |
| 206 | + is_installed_func=is_kubectl_installed, |
| 207 | + install_instruction="Install kubectl.", |
| 208 | + install_url="https://kubernetes.io/docs/tasks/tools/install-kubectl/", |
| 209 | + ) |
| 210 | + helm_info = ToolInfo( |
| 211 | + tool_name="Helm", |
| 212 | + is_installed_func=is_helm_installed, |
| 213 | + install_instruction="Install Helm from Helm's official site.", |
| 214 | + install_url="https://helm.sh/docs/intro/install/", |
| 215 | + ) |
| 216 | + minikube_info = ToolInfo( |
| 217 | + tool_name="Minikube", |
| 218 | + is_installed_func=is_minikube_installed, |
| 219 | + install_instruction="Install Minikube from the official Minikube site.", |
| 220 | + install_url="https://minikube.sigs.k8s.io/docs/start/", |
| 221 | + ) |
| 222 | + minikube_version_info = ToolInfo( |
| 223 | + tool_name="Minikube's version", |
| 224 | + is_installed_func=is_minikube_version_valid_on_darwin, |
| 225 | + install_instruction="Install the latest Minikube from the official Minikube site.", |
| 226 | + install_url="https://minikube.sigs.k8s.io/docs/start/", |
| 227 | + ) |
| 228 | + |
| 229 | + print("") |
| 230 | + print(" ╭───────────────────────────────────╮") |
| 231 | + print(" │ Welcome to the Warnet Quickstart │") |
| 232 | + print(" ╰───────────────────────────────────╯") |
| 233 | + print("") |
| 234 | + print(" Let's find out if your system has what it takes to run Warnet...") |
| 235 | + print("") |
| 236 | + |
49 | 237 | try:
|
50 |
| - # Requirements checks |
51 |
| - with subprocess.Popen( |
52 |
| - ["/bin/bash", str(QUICK_START_PATH)], |
53 |
| - stdout=subprocess.PIPE, |
54 |
| - stderr=subprocess.STDOUT, |
55 |
| - universal_newlines=True, |
56 |
| - env=dict(os.environ, TERM="xterm-256color"), |
57 |
| - ) as process: |
58 |
| - if process.stdout: |
59 |
| - for line in iter(process.stdout.readline, ""): |
60 |
| - click.echo(line, nl=False) |
61 |
| - return_code = process.wait() |
62 |
| - if return_code != 0: |
63 |
| - click.secho( |
64 |
| - f"Quick start script failed with return code {return_code}", fg="red", bold=True |
65 |
| - ) |
66 |
| - click.secho("Install missing requirements before proceeding", fg="yellow") |
67 |
| - return False |
| 238 | + questions = [ |
| 239 | + inquirer.List( |
| 240 | + "platform", |
| 241 | + message=click.style("Which platform would you like to use?", fg="blue", bold=True), |
| 242 | + choices=["Minikube", "Docker Desktop"], |
| 243 | + ) |
| 244 | + ] |
| 245 | + answers = inquirer.prompt(questions) |
| 246 | + |
| 247 | + check_results: list[ToolStatus] = [] |
| 248 | + if answers: |
| 249 | + if answers["platform"] == "Docker Desktop": |
| 250 | + check_results.append(check_installation(docker_info)) |
| 251 | + check_results.append(check_installation(docker_desktop_info)) |
| 252 | + check_results.append(check_installation(kubectl_info)) |
| 253 | + check_results.append(check_installation(helm_info)) |
| 254 | + elif answers["platform"] == "Minikube": |
| 255 | + check_results.append(check_installation(docker_info)) |
| 256 | + check_results.append(check_installation(minikube_info)) |
| 257 | + if is_platform_darwin(): |
| 258 | + check_results.append(check_installation(minikube_version_info)) |
| 259 | + check_results.append(check_installation(kubectl_info)) |
| 260 | + check_results.append(check_installation(helm_info)) |
| 261 | + else: |
| 262 | + click.secho("Please re-run Quickstart.", fg="yellow") |
| 263 | + sys.exit(1) |
| 264 | + |
| 265 | + if ToolStatus.Unsatisfied in check_results: |
| 266 | + click.secho( |
| 267 | + "Please fix the installation issues above and try quickstart again.", fg="yellow" |
| 268 | + ) |
| 269 | + sys.exit(1) |
| 270 | + else: |
| 271 | + click.secho(" ⭐️ Warnet prerequisites look good.\n") |
68 | 272 |
|
69 | 273 | # New project setup
|
70 | 274 | questions = [
|
|
0 commit comments