sunholo 0.87.0__py3-none-any.whl → 0.88.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sunholo/__init__.py +2 -0
- sunholo/cli/cli.py +11 -8
- sunholo/cli/cli_init.py +57 -1
- sunholo/terraform/__init__.py +1 -0
- sunholo/terraform/tfvars_editor.py +339 -0
- {sunholo-0.87.0.dist-info → sunholo-0.88.2.dist-info}/METADATA +5 -2
- {sunholo-0.87.0.dist-info → sunholo-0.88.2.dist-info}/RECORD +11 -9
- {sunholo-0.87.0.dist-info → sunholo-0.88.2.dist-info}/WHEEL +1 -1
- {sunholo-0.87.0.dist-info → sunholo-0.88.2.dist-info}/LICENSE.txt +0 -0
- {sunholo-0.87.0.dist-info → sunholo-0.88.2.dist-info}/entry_points.txt +0 -0
- {sunholo-0.87.0.dist-info → sunholo-0.88.2.dist-info}/top_level.txt +0 -0
sunholo/__init__.py
CHANGED
|
@@ -19,6 +19,7 @@ from . import patches
|
|
|
19
19
|
from . import pubsub
|
|
20
20
|
from . import qna
|
|
21
21
|
from . import streaming
|
|
22
|
+
from . import terraform
|
|
22
23
|
from . import tools
|
|
23
24
|
from . import utils
|
|
24
25
|
from . import vertex
|
|
@@ -46,6 +47,7 @@ __all__ = ['agents',
|
|
|
46
47
|
'pubsub',
|
|
47
48
|
'qna',
|
|
48
49
|
'streaming',
|
|
50
|
+
'terraform',
|
|
49
51
|
'tools',
|
|
50
52
|
'utils',
|
|
51
53
|
'vertex',
|
sunholo/cli/cli.py
CHANGED
|
@@ -12,6 +12,7 @@ from .swagger import setup_swagger_subparser
|
|
|
12
12
|
from .vertex import setup_vertex_subparser
|
|
13
13
|
from ..llamaindex import setup_llamaindex_subparser
|
|
14
14
|
from ..excel import setup_excel_subparser
|
|
15
|
+
from ..terraform import setup_tfvarseditor_subparser
|
|
15
16
|
|
|
16
17
|
from ..utils import ConfigManager
|
|
17
18
|
from ..utils.version import sunholo_version
|
|
@@ -65,13 +66,13 @@ def main(args=None):
|
|
|
65
66
|
parser.add_argument('--debug', action='store_true', help='Enable debug output')
|
|
66
67
|
parser.add_argument('--project', default=default_project, help='GCP project to list Cloud Run services from.')
|
|
67
68
|
parser.add_argument('--region', default=default_region, help='Region to list Cloud Run services from.')
|
|
68
|
-
parser.add_argument('--version', action='store_true', help='Show the version and exit')
|
|
69
|
+
parser.add_argument('-v', '--version', action='store_true', help='Show the version and exit')
|
|
69
70
|
|
|
70
71
|
subparsers = parser.add_subparsers(title='commands',
|
|
71
72
|
description='Valid commands',
|
|
72
73
|
help='Commands',
|
|
73
74
|
dest='command',
|
|
74
|
-
required=
|
|
75
|
+
required=False)
|
|
75
76
|
|
|
76
77
|
# deploy command
|
|
77
78
|
setup_deploy_subparser(subparsers)
|
|
@@ -95,11 +96,18 @@ def main(args=None):
|
|
|
95
96
|
setup_llamaindex_subparser(subparsers)
|
|
96
97
|
# excel
|
|
97
98
|
setup_excel_subparser(subparsers)
|
|
99
|
+
# terraform
|
|
100
|
+
setup_tfvarseditor_subparser(subparsers)
|
|
98
101
|
|
|
99
102
|
#TODO: add database setup commands: alloydb and supabase
|
|
100
103
|
|
|
101
104
|
args = parser.parse_args(args)
|
|
102
105
|
|
|
106
|
+
# Handle global flags
|
|
107
|
+
if args.version:
|
|
108
|
+
console.print(sunholo_version())
|
|
109
|
+
return
|
|
110
|
+
|
|
103
111
|
if args.debug:
|
|
104
112
|
log.setLevel(logging.DEBUG)
|
|
105
113
|
logging.getLogger().setLevel(logging.DEBUG)
|
|
@@ -107,14 +115,9 @@ def main(args=None):
|
|
|
107
115
|
log.setLevel(logging.WARNING)
|
|
108
116
|
logging.getLogger().setLevel(logging.WARNING)
|
|
109
117
|
|
|
110
|
-
|
|
111
|
-
sunholo_version()
|
|
112
|
-
return
|
|
113
|
-
|
|
118
|
+
# Handle subcommand
|
|
114
119
|
if hasattr(args, 'func'):
|
|
115
120
|
args.func(args)
|
|
116
121
|
else:
|
|
117
122
|
parser.print_help()
|
|
118
123
|
|
|
119
|
-
if __name__ == "__main__":
|
|
120
|
-
main()
|
sunholo/cli/cli_init.py
CHANGED
|
@@ -27,7 +27,8 @@ sunholo init my_genai_project
|
|
|
27
27
|
This will create a new directory named `my_genai_project` with the template files, allowing users to start building their GenAI application.
|
|
28
28
|
"""
|
|
29
29
|
project_name = args.project_name
|
|
30
|
-
|
|
30
|
+
current_dir = os.getcwd() # This captures the current directory where the command is run
|
|
31
|
+
project_dir = os.path.join(current_dir, project_name)
|
|
31
32
|
|
|
32
33
|
print(f"Initializing project: {project_name} in directory: {project_dir}")
|
|
33
34
|
|
|
@@ -48,6 +49,59 @@ This will create a new directory named `my_genai_project` with the template file
|
|
|
48
49
|
elif os.path.isdir(src_path):
|
|
49
50
|
shutil.copytree(src_path, dest_path)
|
|
50
51
|
|
|
52
|
+
# Determine the location of the generated.tfvars file
|
|
53
|
+
terraform_dir = args.terraform_dir or os.getenv('MULTIVAC_TERRAFORM_DIR')
|
|
54
|
+
if terraform_dir is None:
|
|
55
|
+
raise ValueError("Must specify a terraform_dir or use the MULTIVAC_TERRAFORM_DIR environment variable")
|
|
56
|
+
|
|
57
|
+
tfvars_file = os.path.join(terraform_dir, 'generated.tfvars')
|
|
58
|
+
|
|
59
|
+
# Get the service account, either from the CLI argument or default
|
|
60
|
+
service_account = args.service_account or "sa-llmops" # Default service account
|
|
61
|
+
|
|
62
|
+
# Determine the relative path for the cloud build included directories
|
|
63
|
+
def get_relative_application_path(full_path: str, base_dir: str) -> str:
|
|
64
|
+
application_base_index = full_path.find("application/")
|
|
65
|
+
if application_base_index != -1:
|
|
66
|
+
return full_path[application_base_index:]
|
|
67
|
+
return os.path.relpath(full_path, base_dir)
|
|
68
|
+
|
|
69
|
+
# Paths to be included in the cloud build (based on the current working directory)
|
|
70
|
+
# We want paths to start from 'application/system_services/{project_name}'
|
|
71
|
+
relative_base = os.path.relpath(current_dir, os.path.join(current_dir, "..", ".."))
|
|
72
|
+
included_path = os.path.join(relative_base, project_name, "**")
|
|
73
|
+
cloud_build_path = os.path.join(relative_base, project_name, "cloudbuild.yaml")
|
|
74
|
+
|
|
75
|
+
# Define the cloud_run configuration for 'discord-server' with the correct project_dir path
|
|
76
|
+
cloud_run_config = {
|
|
77
|
+
project_name: {
|
|
78
|
+
"cpu": "1",
|
|
79
|
+
"memory": "2Gi",
|
|
80
|
+
"max_instance_count": 3,
|
|
81
|
+
"timeout_seconds": 1500,
|
|
82
|
+
"port": 8080,
|
|
83
|
+
"service_account": service_account,
|
|
84
|
+
"invokers": ["allUsers"],
|
|
85
|
+
"cloud_build": {
|
|
86
|
+
"included": [included_path],
|
|
87
|
+
"path": cloud_build_path,
|
|
88
|
+
"substitutions": {},
|
|
89
|
+
"repo_name": "",
|
|
90
|
+
"repo_owner": ""
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
# Initialize the TerraformVarsEditor and update the .tfvars file
|
|
97
|
+
try:
|
|
98
|
+
from ..terraform import TerraformVarsEditor
|
|
99
|
+
editor = TerraformVarsEditor(tfvars_file, terraform_dir)
|
|
100
|
+
editor.update_from_dict(cloud_run_config, 'cloud_run')
|
|
101
|
+
print(f"{tfvars_file} file initialized and updated successfully.")
|
|
102
|
+
except ImportError as e:
|
|
103
|
+
print(f"Error initializing TerraformVarsEditor: {e}")
|
|
104
|
+
|
|
51
105
|
print(f"Project {project_name} initialized successfully.")
|
|
52
106
|
print(f"Navigate to {project_dir} and customize the configuration files in the 'config' directory.")
|
|
53
107
|
|
|
@@ -57,4 +111,6 @@ def setup_init_subparser(subparsers):
|
|
|
57
111
|
"""
|
|
58
112
|
init_parser = subparsers.add_parser('init', help='Initializes a new Multivac project.')
|
|
59
113
|
init_parser.add_argument('project_name', help='The name of the new project.')
|
|
114
|
+
init_parser.add_argument('--terraform-dir', help='The directory where Terraform files will be generated.')
|
|
115
|
+
init_parser.add_argument('--service-account', help='The service account to use for Cloud Run. Defaults to "sa-llmops"')
|
|
60
116
|
init_parser.set_defaults(func=init_project)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .tfvars_editor import setup_tfvarseditor_subparser, TerraformVarsEditor
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
try:
|
|
2
|
+
import hcl2
|
|
3
|
+
except ImportError:
|
|
4
|
+
hcl2 = None
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
import subprocess
|
|
8
|
+
import os
|
|
9
|
+
import io
|
|
10
|
+
from typing import Dict, Any
|
|
11
|
+
from ..custom_logging import log
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
from ..cli.sun_rich import console
|
|
15
|
+
except ImportError:
|
|
16
|
+
console = None
|
|
17
|
+
|
|
18
|
+
class TerraformVarsEditor:
|
|
19
|
+
"""
|
|
20
|
+
A class to manage and safely edit Terraform .tfvars files.
|
|
21
|
+
|
|
22
|
+
This class allows you to update specific keys in a .tfvars file with new data
|
|
23
|
+
and ensures that the changes only take effect if Terraform validation passes.
|
|
24
|
+
|
|
25
|
+
Attributes:
|
|
26
|
+
----------
|
|
27
|
+
tfvars_file : str
|
|
28
|
+
The path to the .tfvars file to be edited.
|
|
29
|
+
terraform_dir : str
|
|
30
|
+
The directory where Terraform commands will be executed (default is current directory).
|
|
31
|
+
tfvars_data : dict
|
|
32
|
+
The content of the .tfvars file loaded into a dictionary.
|
|
33
|
+
|
|
34
|
+
Methods:
|
|
35
|
+
-------
|
|
36
|
+
_load_tfvars() -> Dict[str, Any]
|
|
37
|
+
Loads the .tfvars file into a dictionary.
|
|
38
|
+
_save_tfvars() -> None
|
|
39
|
+
Saves the current state of the dictionary back to the .tfvars file.
|
|
40
|
+
_backup_tfvars() -> str
|
|
41
|
+
Creates a backup of the current .tfvars file.
|
|
42
|
+
_restore_tfvars(backup_file: str) -> None
|
|
43
|
+
Restores the .tfvars file from the backup.
|
|
44
|
+
update_or_add_instance(main_key: str, instance_name: str, instance_data: Dict[str, Any]) -> None
|
|
45
|
+
Adds or updates an instance under a specified top-level key in the .tfvars file.
|
|
46
|
+
validate_terraform() -> bool
|
|
47
|
+
Runs `terraform validate` in the specified directory.
|
|
48
|
+
update_from_json(json_file: str, main_key: str) -> None
|
|
49
|
+
Updates the .tfvars file based on the content of a JSON file and validates the changes.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
def __init__(self, tfvars_file: str, terraform_dir: str = '.') -> None:
|
|
53
|
+
"""
|
|
54
|
+
Initializes the TerraformVarsEditor with the given .tfvars file and Terraform directory.
|
|
55
|
+
|
|
56
|
+
Parameters:
|
|
57
|
+
----------
|
|
58
|
+
tfvars_file : str
|
|
59
|
+
The path to the .tfvars file to be edited.
|
|
60
|
+
terraform_dir : str
|
|
61
|
+
The directory where Terraform commands will be executed (default is current directory). Will use MULTIVAC_TERRAFORM_DIR env var if present.
|
|
62
|
+
|
|
63
|
+
Example:
|
|
64
|
+
-------
|
|
65
|
+
editor = TerraformVarsEditor('example.tfvars', '/path/to/terraform/config')
|
|
66
|
+
"""
|
|
67
|
+
if hcl2 is None:
|
|
68
|
+
raise ImportError('hcl2 is required for parsing terraform files, install via `pip install sunholo[iac]`')
|
|
69
|
+
|
|
70
|
+
# Check for the MULTIVAC_TERRAFORM_DIR environment variable
|
|
71
|
+
if terraform_dir == '.' and 'MULTIVAC_TERRAFORM_DIR' in os.environ:
|
|
72
|
+
terraform_dir = os.environ['MULTIVAC_TERRAFORM_DIR']
|
|
73
|
+
|
|
74
|
+
log.info(f'MULTIVAC_TERRAFORM_DIR environment variable is set to {terraform_dir}')
|
|
75
|
+
|
|
76
|
+
self.tfvars_file = tfvars_file
|
|
77
|
+
self.terraform_dir = terraform_dir
|
|
78
|
+
self.tfvars_data = self._load_tfvars()
|
|
79
|
+
|
|
80
|
+
def _load_tfvars(self) -> Dict[str, Any]:
|
|
81
|
+
"""
|
|
82
|
+
Loads the .tfvars file into a dictionary.
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
-------
|
|
86
|
+
dict
|
|
87
|
+
The content of the .tfvars file.
|
|
88
|
+
|
|
89
|
+
Example:
|
|
90
|
+
-------
|
|
91
|
+
data = self._load_tfvars()
|
|
92
|
+
"""
|
|
93
|
+
with open(self.tfvars_file, 'r') as file:
|
|
94
|
+
return hcl2.load(file)
|
|
95
|
+
|
|
96
|
+
def _save_tfvars(self) -> None:
|
|
97
|
+
"""
|
|
98
|
+
Saves the current state of the dictionary back to the .tfvars file.
|
|
99
|
+
|
|
100
|
+
Example:
|
|
101
|
+
-------
|
|
102
|
+
self._save_tfvars()
|
|
103
|
+
"""
|
|
104
|
+
with open(self.tfvars_file, 'w') as file:
|
|
105
|
+
for key, value in self.tfvars_data.items():
|
|
106
|
+
file.write(f'{key} = {json.dumps(value, indent=2)}\n')
|
|
107
|
+
|
|
108
|
+
def _backup_tfvars(self) -> str:
|
|
109
|
+
"""
|
|
110
|
+
Creates a backup of the current .tfvars file.
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
-------
|
|
114
|
+
str
|
|
115
|
+
The path to the backup file.
|
|
116
|
+
|
|
117
|
+
Example:
|
|
118
|
+
-------
|
|
119
|
+
backup_file = self._backup_tfvars()
|
|
120
|
+
"""
|
|
121
|
+
backup_file = f"{self.tfvars_file}.bak"
|
|
122
|
+
os.rename(self.tfvars_file, backup_file)
|
|
123
|
+
return backup_file
|
|
124
|
+
|
|
125
|
+
def _restore_tfvars(self, backup_file: str) -> None:
|
|
126
|
+
"""
|
|
127
|
+
Restores the .tfvars file from the backup.
|
|
128
|
+
|
|
129
|
+
Parameters:
|
|
130
|
+
----------
|
|
131
|
+
backup_file : str
|
|
132
|
+
The path to the backup file to restore from.
|
|
133
|
+
|
|
134
|
+
Example:
|
|
135
|
+
-------
|
|
136
|
+
self._restore_tfvars('example.tfvars.bak')
|
|
137
|
+
"""
|
|
138
|
+
os.rename(backup_file, self.tfvars_file)
|
|
139
|
+
|
|
140
|
+
def update_or_add_instance(self, main_key: str, instance_name: str, instance_data: Dict[str, Any]) -> None:
|
|
141
|
+
"""
|
|
142
|
+
Adds or updates an instance under a specified top-level key in the .tfvars file.
|
|
143
|
+
|
|
144
|
+
Parameters:
|
|
145
|
+
----------
|
|
146
|
+
main_key : str
|
|
147
|
+
The top-level key in the .tfvars file (e.g., "cloud_run").
|
|
148
|
+
instance_name : str
|
|
149
|
+
The name of the instance to add or update.
|
|
150
|
+
instance_data : dict
|
|
151
|
+
The dictionary containing the instance data.
|
|
152
|
+
|
|
153
|
+
Example:
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
editor.update_or_add_instance('cloud_run', 'new_service', (your dict))
|
|
157
|
+
```
|
|
158
|
+
"""
|
|
159
|
+
if main_key not in self.tfvars_data:
|
|
160
|
+
self.tfvars_data[main_key] = {}
|
|
161
|
+
|
|
162
|
+
self.tfvars_data[main_key][instance_name] = instance_data
|
|
163
|
+
|
|
164
|
+
def validate_terraform(self) -> bool:
|
|
165
|
+
"""
|
|
166
|
+
Runs `terraform init` followed by `terraform validate` in the specified directory.
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
-------
|
|
170
|
+
bool
|
|
171
|
+
True if validation passes, False otherwise.
|
|
172
|
+
|
|
173
|
+
Example:
|
|
174
|
+
-------
|
|
175
|
+
```python
|
|
176
|
+
if self.validate_terraform():
|
|
177
|
+
print("Validation passed.")
|
|
178
|
+
```
|
|
179
|
+
"""
|
|
180
|
+
# Step 1: Run `terraform init` to ensure the directory is initialized
|
|
181
|
+
init_process = subprocess.run(['terraform', 'init'], cwd=self.terraform_dir, capture_output=True, text=True)
|
|
182
|
+
|
|
183
|
+
if init_process.returncode != 0:
|
|
184
|
+
log.error("Terraform initialization failed.")
|
|
185
|
+
print(init_process.stdout)
|
|
186
|
+
print(init_process.stderr)
|
|
187
|
+
return False
|
|
188
|
+
|
|
189
|
+
log.info("Terraform initialized successfully.")
|
|
190
|
+
|
|
191
|
+
# Step 2: Run `terraform validate`
|
|
192
|
+
validate_process = subprocess.run(['terraform', 'validate'], cwd=self.terraform_dir, capture_output=True, text=True)
|
|
193
|
+
|
|
194
|
+
if validate_process.returncode == 0:
|
|
195
|
+
log.info("Terraform validation passed.")
|
|
196
|
+
return True
|
|
197
|
+
else:
|
|
198
|
+
log.error("Terraform validation failed.")
|
|
199
|
+
print(validate_process.stdout)
|
|
200
|
+
print(validate_process.stderr)
|
|
201
|
+
return False
|
|
202
|
+
|
|
203
|
+
def update_from_json(self, json_file: str, main_key: str) -> None:
|
|
204
|
+
"""
|
|
205
|
+
Updates the .tfvars file based on the content of a JSON file and validates the changes.
|
|
206
|
+
|
|
207
|
+
Parameters:
|
|
208
|
+
----------
|
|
209
|
+
json_file : str
|
|
210
|
+
The path to the JSON file with the new instance data.
|
|
211
|
+
main_key : str
|
|
212
|
+
The top-level key in the .tfvars file (e.g., "cloud_run").
|
|
213
|
+
|
|
214
|
+
Example:
|
|
215
|
+
-------
|
|
216
|
+
editor.update_from_json('update.json', 'cloud_run')
|
|
217
|
+
"""
|
|
218
|
+
with open(json_file, 'r') as file:
|
|
219
|
+
data = json.load(file)
|
|
220
|
+
|
|
221
|
+
# Update the tfvars data in memory
|
|
222
|
+
for instance_name, instance_data in data.get(main_key, {}).items():
|
|
223
|
+
self.update_or_add_instance(main_key, instance_name, instance_data)
|
|
224
|
+
|
|
225
|
+
# Backup the original .tfvars file
|
|
226
|
+
backup_file = self._backup_tfvars()
|
|
227
|
+
|
|
228
|
+
# Temporarily save the updated data to the original file location
|
|
229
|
+
self._save_tfvars()
|
|
230
|
+
|
|
231
|
+
# Attempt to validate the changes with Terraform
|
|
232
|
+
if not self.validate_terraform():
|
|
233
|
+
# If validation fails, restore the original file from the backup
|
|
234
|
+
self._restore_tfvars(backup_file)
|
|
235
|
+
log.error(f"Changes aborted, original {self.tfvars_file} restored.")
|
|
236
|
+
else:
|
|
237
|
+
log.info(f"Terraform validation passed, changes saved to {self.tfvars_file}.")
|
|
238
|
+
os.remove(backup_file) # Remove the backup if validation passes
|
|
239
|
+
|
|
240
|
+
def update_from_dict(self, data: Dict[str, Any], main_key: str) -> None:
|
|
241
|
+
"""
|
|
242
|
+
Updates the .tfvars file based on the content of a Python dictionary and validates the changes.
|
|
243
|
+
|
|
244
|
+
Parameters:
|
|
245
|
+
----------
|
|
246
|
+
data : dict
|
|
247
|
+
The dictionary with the new instance data.
|
|
248
|
+
main_key : str
|
|
249
|
+
The top-level key under which the instance is added (e.g., "cloud_run").
|
|
250
|
+
|
|
251
|
+
Example:
|
|
252
|
+
-------
|
|
253
|
+
editor.update_from_dict(data, 'cloud_run')
|
|
254
|
+
"""
|
|
255
|
+
# Create an in-memory file-like object from the dictionary by converting it to JSON
|
|
256
|
+
json_data = json.dumps({main_key: data})
|
|
257
|
+
json_file = io.StringIO(json_data)
|
|
258
|
+
|
|
259
|
+
# Load the JSON data from the StringIO object
|
|
260
|
+
parsed_data = json.load(json_file)
|
|
261
|
+
|
|
262
|
+
# Update the tfvars data in memory
|
|
263
|
+
for instance_name, instance_data in parsed_data.get(main_key, {}).items():
|
|
264
|
+
self.update_or_add_instance(main_key, instance_name, instance_data)
|
|
265
|
+
|
|
266
|
+
# Now that the data is updated in memory, proceed to validate and write it back to the file
|
|
267
|
+
# Backup the original .tfvars file
|
|
268
|
+
backup_file = self._backup_tfvars()
|
|
269
|
+
|
|
270
|
+
# Temporarily save the updated data to the original file location
|
|
271
|
+
self._save_tfvars()
|
|
272
|
+
|
|
273
|
+
# Attempt to validate the changes with Terraform
|
|
274
|
+
if not self.validate_terraform():
|
|
275
|
+
# If validation fails, restore the original file from the backup
|
|
276
|
+
self._restore_tfvars(backup_file)
|
|
277
|
+
console.print(f"Changes aborted, original {self.tfvars_file} restored.")
|
|
278
|
+
else:
|
|
279
|
+
console.print(f"Terraform validation passed, changes saved to {self.tfvars_file}.")
|
|
280
|
+
os.remove(backup_file) # Remove the backup if validation passes
|
|
281
|
+
|
|
282
|
+
def tfvars_command(args):
|
|
283
|
+
"""
|
|
284
|
+
Executes the tfvars command based on parsed arguments.
|
|
285
|
+
|
|
286
|
+
Args:
|
|
287
|
+
args: The parsed command-line arguments.
|
|
288
|
+
"""
|
|
289
|
+
|
|
290
|
+
if console is None:
|
|
291
|
+
raise ImportError("Need cli tools to use `sunholo tfvars` - install via `pip install sunholo[cli]`")
|
|
292
|
+
|
|
293
|
+
# Load JSON data from the specified file
|
|
294
|
+
try:
|
|
295
|
+
with open(args.json_file, 'r') as f:
|
|
296
|
+
instance_data = json.load(f)
|
|
297
|
+
except FileNotFoundError:
|
|
298
|
+
console.print(f"Error: The JSON file '{args.json_file}' was not found.")
|
|
299
|
+
return
|
|
300
|
+
except json.JSONDecodeError as e:
|
|
301
|
+
console.print(f"Error parsing JSON data: {e}")
|
|
302
|
+
return
|
|
303
|
+
|
|
304
|
+
# Create an instance of TerraformVarsEditor
|
|
305
|
+
editor = TerraformVarsEditor(args.tfvars_file, args.terraform_dir)
|
|
306
|
+
|
|
307
|
+
# Add or update the instance
|
|
308
|
+
editor.update_or_add_instance(args.main_key, args.instance_name, instance_data)
|
|
309
|
+
|
|
310
|
+
# Validate the Terraform configuration
|
|
311
|
+
if editor.validate_terraform():
|
|
312
|
+
console.print(f"Successfully updated '{args.instance_name}' under '{args.main_key}' in '{args.tfvars_file}'.")
|
|
313
|
+
else:
|
|
314
|
+
console.print(f"[bold red]Failed to update '{args.instance_name}'. The changes have been rolled back.[/bold red]")
|
|
315
|
+
|
|
316
|
+
def setup_tfvarseditor_subparser(subparsers):
|
|
317
|
+
"""
|
|
318
|
+
Sets up an argparse subparser for the 'tfvars' command.
|
|
319
|
+
|
|
320
|
+
Args:
|
|
321
|
+
subparsers: The subparsers object from argparse.ArgumentParser().
|
|
322
|
+
"""
|
|
323
|
+
# TFVars subparser setup
|
|
324
|
+
tfvars_parser = subparsers.add_parser('tfvars', help='Manage Terraform .tfvars files')
|
|
325
|
+
tfvars_subparsers = tfvars_parser.add_subparsers(dest='action', help='TFVars subcommands')
|
|
326
|
+
|
|
327
|
+
# TFVars add command
|
|
328
|
+
add_parser = tfvars_subparsers.add_parser('add', help='Add or update an instance in a .tfvars file')
|
|
329
|
+
add_parser.add_argument('tfvars_file', help='Path to the .tfvars file')
|
|
330
|
+
add_parser.add_argument('main_key', help='The main key under which the instance is added (e.g., "cloud_run")')
|
|
331
|
+
add_parser.add_argument('instance_name', help='The name of the instance to add or update')
|
|
332
|
+
add_parser.add_argument('--json-file', help='Path to a JSON file with the instance data', required=True)
|
|
333
|
+
add_parser.add_argument('--terraform-dir', default='.', help='The directory where Terraform is initialized')
|
|
334
|
+
|
|
335
|
+
tfvars_parser.set_defaults(func=tfvars_command)
|
|
336
|
+
|
|
337
|
+
# If no subcommand is provided, print the help message
|
|
338
|
+
tfvars_parser.set_defaults(func=lambda args: tfvars_parser.print_help() if args.action is None else tfvars_command)
|
|
339
|
+
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sunholo
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.88.2
|
|
4
4
|
Summary: Large Language Model DevOps - a package to help deploy LLMs to the Cloud.
|
|
5
5
|
Home-page: https://github.com/sunholo-data/sunholo-py
|
|
6
|
-
Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.
|
|
6
|
+
Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.88.2.tar.gz
|
|
7
7
|
Author: Holosun ApS
|
|
8
8
|
Author-email: multivac@sunholo.com
|
|
9
9
|
License: Apache License, Version 2.0
|
|
@@ -64,6 +64,7 @@ Requires-Dist: playwright ; extra == 'all'
|
|
|
64
64
|
Requires-Dist: psutil ; extra == 'all'
|
|
65
65
|
Requires-Dist: psycopg2-binary ; extra == 'all'
|
|
66
66
|
Requires-Dist: pypdf ; extra == 'all'
|
|
67
|
+
Requires-Dist: python-hcl2 ; extra == 'all'
|
|
67
68
|
Requires-Dist: python-socketio ; extra == 'all'
|
|
68
69
|
Requires-Dist: pytesseract ; extra == 'all'
|
|
69
70
|
Requires-Dist: rich ; extra == 'all'
|
|
@@ -121,6 +122,8 @@ Requires-Dist: httpx ; extra == 'http'
|
|
|
121
122
|
Requires-Dist: langfuse ; extra == 'http'
|
|
122
123
|
Requires-Dist: python-socketio ; extra == 'http'
|
|
123
124
|
Requires-Dist: requests ; extra == 'http'
|
|
125
|
+
Provides-Extra: iac
|
|
126
|
+
Requires-Dist: python-hcl2 ; extra == 'iac'
|
|
124
127
|
Provides-Extra: openai
|
|
125
128
|
Requires-Dist: langchain-openai ; extra == 'openai'
|
|
126
129
|
Requires-Dist: tiktoken ; extra == 'openai'
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
sunholo/__init__.py,sha256=
|
|
1
|
+
sunholo/__init__.py,sha256=lLuVyilzmDbTaiAptR8SZzpbUNsgwHFsp4Ejbr5EApI,1136
|
|
2
2
|
sunholo/custom_logging.py,sha256=YfIN1oP3dOEkkYkyRBU8BGS3uJFGwUDsFCl8mIVbwvE,12225
|
|
3
3
|
sunholo/agents/__init__.py,sha256=X2I3pPkGeKWjc3d0QgSpkTyqD8J8JtrEWqwrumf1MMc,391
|
|
4
4
|
sunholo/agents/chat_history.py,sha256=Gph_CdlP2otYnNdR1q1Umyyyvcad2F6K3LxU5yBQ9l0,5387
|
|
@@ -43,8 +43,8 @@ sunholo/chunker/pubsub.py,sha256=48bhuAcszN7LGe3-ksPSLHHhq0uKxiXOrizck5qpcP0,101
|
|
|
43
43
|
sunholo/chunker/splitter.py,sha256=QLAEsJOpEYFZr9-UGZUuAlNVyjfCWb8jvzCHg0rVShE,6751
|
|
44
44
|
sunholo/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
45
45
|
sunholo/cli/chat_vac.py,sha256=jTmCt62U4uqJjeGp_XfIbxnafAAOhQAJMi8TxSkeKlM,23164
|
|
46
|
-
sunholo/cli/cli.py,sha256=
|
|
47
|
-
sunholo/cli/cli_init.py,sha256=
|
|
46
|
+
sunholo/cli/cli.py,sha256=q-ATmnWnc_PPo2q31xhqpp-m3GtOSBoqh0gvMeSo4XU,4374
|
|
47
|
+
sunholo/cli/cli_init.py,sha256=jifczqRd4ATrfUPl-LYCpuhURZiEwqAy1MaAgpSdxQ4,5025
|
|
48
48
|
sunholo/cli/configs.py,sha256=QUM9DvKOdZmEQRM5uI3Nh887T0YDiSMr7O240zTLqws,4546
|
|
49
49
|
sunholo/cli/deploy.py,sha256=zxdwUsRTRMC8U5vyRv0JiKBLFn84Ug_Tc88-_h9hJSs,1609
|
|
50
50
|
sunholo/cli/embedder.py,sha256=v-FKiSPHaQzB6ctClclYueIf3bf3CqYtC1oRgPfT4dY,5566
|
|
@@ -119,6 +119,8 @@ sunholo/streaming/stream_lookup.py,sha256=hYg1DbdSE_QNJ8ZB-ynXJlWgvFjrGvwoUsGJu_
|
|
|
119
119
|
sunholo/streaming/streaming.py,sha256=5dRXo1wHYE0E91gll-939RShYTYxQMeVwAVCqFR13h0,16343
|
|
120
120
|
sunholo/summarise/__init__.py,sha256=MZk3dblUMODcPb1crq4v-Z508NrFIpkSWNf9FIO8BcU,38
|
|
121
121
|
sunholo/summarise/summarise.py,sha256=95A-6PXFGanjona8DvZPnnIHLbzZ2ip5hO0wOAJQhfw,3791
|
|
122
|
+
sunholo/terraform/__init__.py,sha256=yixxEltc3n9UpZaVi05GlgS-YRq_DVGjUc37I9ajeP4,76
|
|
123
|
+
sunholo/terraform/tfvars_editor.py,sha256=iBKyDajnZsDnLWuqGZv9SJKWMfK0J809-I6X0_EnUHU,12395
|
|
122
124
|
sunholo/tools/__init__.py,sha256=5NuYpwwTX81qGUWvgwfItoSLXteNnp7KjgD7IPZUFjI,53
|
|
123
125
|
sunholo/tools/web_browser.py,sha256=8Gdf02F4zCOeSnijnfaL6jzk4oaSI0cj48o-esoWzwE,29086
|
|
124
126
|
sunholo/utils/__init__.py,sha256=Hv02T5L2zYWvCso5hzzwm8FQogwBq0OgtUbN_7Quzqc,89
|
|
@@ -141,9 +143,9 @@ sunholo/vertex/init.py,sha256=1OQwcPBKZYBTDPdyU7IM4X4OmiXLdsNV30C-fee2scQ,2875
|
|
|
141
143
|
sunholo/vertex/memory_tools.py,sha256=q_phxgGX2TG2j2MXNULF2xGzQnQPENwjPN9nZ_A9Gh0,7526
|
|
142
144
|
sunholo/vertex/safety.py,sha256=S9PgQT1O_BQAkcqauWncRJaydiP8Q_Jzmu9gxYfy1VA,2482
|
|
143
145
|
sunholo/vertex/type_dict_to_json.py,sha256=uTzL4o9tJRao4u-gJOFcACgWGkBOtqACmb6ihvCErL8,4694
|
|
144
|
-
sunholo-0.
|
|
145
|
-
sunholo-0.
|
|
146
|
-
sunholo-0.
|
|
147
|
-
sunholo-0.
|
|
148
|
-
sunholo-0.
|
|
149
|
-
sunholo-0.
|
|
146
|
+
sunholo-0.88.2.dist-info/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
|
|
147
|
+
sunholo-0.88.2.dist-info/METADATA,sha256=HUlu0wOukUKSs4pQW1k2F3xwu8x6nQD8WRO4dukQGKk,7706
|
|
148
|
+
sunholo-0.88.2.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
|
|
149
|
+
sunholo-0.88.2.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
|
|
150
|
+
sunholo-0.88.2.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
|
|
151
|
+
sunholo-0.88.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|