@@ -18,7 +18,7 @@ def get_deployed_infrastructure_version(region: str) -> Optional[str]:
18
18
try :
19
19
cfn = boto3 .client ('cloudformation' , region_name = region )
20
20
stack_info = cfn .describe_stacks (StackName = ENV_STACK_NAME )['Stacks' ][0 ]
21
-
21
+
22
22
# Get ArtifactVersion parameter from stack
23
23
for param in stack_info .get ('Parameters' , []):
24
24
if param ['ParameterKey' ] == 'ArtifactVersion' :
@@ -36,20 +36,20 @@ def check_infrastructure_completeness(region: str) -> Tuple[bool, str]:
36
36
try :
37
37
cfn = boto3 .client ('cloudformation' , region_name = region )
38
38
s3 = boto3 .client ('s3' , region_name = region )
39
-
39
+
40
40
# Check CloudFormation stack
41
41
try :
42
42
stack_info = cfn .describe_stacks (StackName = ENV_STACK_NAME )['Stacks' ][0 ]
43
43
stack_status = stack_info ['StackStatus' ]
44
-
44
+
45
45
if stack_status not in ['CREATE_COMPLETE' , 'UPDATE_COMPLETE' ]:
46
46
return False , f"CloudFormation stack status: { stack_status } "
47
-
47
+
48
48
except cfn .exceptions .ClientError as e :
49
49
if "does not exist" in str (e ):
50
50
return False , "CloudFormation stack does not exist"
51
51
raise
52
-
52
+
53
53
# Check S3 bucket (get bucket name from stack resources)
54
54
try :
55
55
from emd .sdk .bootstrap import get_bucket_name
@@ -60,9 +60,9 @@ def check_infrastructure_completeness(region: str) -> Tuple[bool, str]:
60
60
s3 .head_bucket (Bucket = bucket_name )
61
61
except Exception as e :
62
62
return False , f"S3 bucket issue: { str (e )} "
63
-
63
+
64
64
return True , "Infrastructure is complete"
65
-
65
+
66
66
except Exception as e :
67
67
logger .debug (f"Infrastructure completeness check failed: { e } " )
68
68
return False , f"Infrastructure check failed: { str (e )} "
@@ -71,7 +71,7 @@ def check_infrastructure_completeness(region: str) -> Tuple[bool, str]:
71
71
class SmartBootstrapManager :
72
72
def __init__ (self ):
73
73
self .console = Console ()
74
-
74
+
75
75
def check_version_compatibility (self , current_version : str , deployed_version : str , region : str ) -> str :
76
76
"""
77
77
Check version compatibility and infrastructure completeness
@@ -82,14 +82,14 @@ def check_version_compatibility(self, current_version: str, deployed_version: st
82
82
if not is_complete :
83
83
logger .debug (f"Infrastructure incomplete: { status_msg } " )
84
84
return 'auto_bootstrap' # Infrastructure missing/incomplete, need bootstrap
85
-
85
+
86
86
if not deployed_version :
87
87
return 'auto_bootstrap' # No version info, need bootstrap
88
-
88
+
89
89
try :
90
90
current_parsed = packaging .version .parse (current_version )
91
91
deployed_parsed = packaging .version .parse (deployed_version )
92
-
92
+
93
93
if current_parsed > deployed_parsed :
94
94
return 'auto_bootstrap' # Local newer, auto bootstrap
95
95
elif deployed_parsed > current_parsed :
@@ -99,7 +99,7 @@ def check_version_compatibility(self, current_version: str, deployed_version: st
99
99
except Exception as e :
100
100
logger .debug (f"Failed to parse versions: { e } " )
101
101
return 'auto_bootstrap' # Default to bootstrap if parsing fails
102
-
102
+
103
103
def show_bootstrap_notification (self , current_version : str , deployed_version : str ):
104
104
"""Show notification about automatic bootstrap"""
105
105
self .console .print () # Empty line for spacing
@@ -108,18 +108,18 @@ def show_bootstrap_notification(self, current_version: str, deployed_version: st
108
108
else :
109
109
self .console .print (f"🚀 [bold green]Setting up infrastructure...[/bold green] [bold green]{ current_version } [/bold green]" )
110
110
self .console .print () # Empty line for spacing
111
-
111
+
112
112
def show_version_mismatch_warning (self , current_version : str , deployed_version : str ):
113
113
"""Show warning when cloud version is newer than local version"""
114
114
self .console .print () # Empty line for spacing
115
115
self .console .print (f"⚠️ [bold yellow]Version mismatch:[/bold yellow] Local [dim]{ current_version } [/dim] < Cloud [bold yellow]{ deployed_version } [/bold yellow]" )
116
116
self .console .print (f" [bold]Recommendation:[/bold] pip install --upgrade easy-model-deployer" )
117
117
self .console .print () # Empty line for spacing
118
-
118
+
119
119
def is_auto_bootstrap_disabled (self ) -> bool :
120
120
"""Check if auto bootstrap is disabled via environment variable"""
121
121
return os .getenv ("EMD_DISABLE_AUTO_BOOTSTRAP" , "" ).lower () in ["true" , "1" , "yes" ]
122
-
122
+
123
123
def auto_bootstrap_if_needed (self , region : str ) -> bool :
124
124
"""
125
125
Automatically run bootstrap if needed based on comprehensive infrastructure check
@@ -129,67 +129,67 @@ def auto_bootstrap_if_needed(self, region: str) -> bool:
129
129
if self .is_auto_bootstrap_disabled ():
130
130
logger .debug ("Auto bootstrap disabled via EMD_DISABLE_AUTO_BOOTSTRAP" )
131
131
return False
132
-
132
+
133
133
current_version = VERSION
134
134
deployed_version = get_deployed_infrastructure_version (region )
135
-
135
+
136
136
action = self .check_version_compatibility (current_version , deployed_version , region )
137
-
137
+
138
138
if action == 'compatible' :
139
139
return False # No action needed
140
-
140
+
141
141
elif action == 'version_mismatch_warning' :
142
142
# Cloud version > Local version - show warning and ask user
143
143
self .show_version_mismatch_warning (current_version , deployed_version )
144
-
144
+
145
145
if not typer .confirm ("Continue deployment despite version mismatch?" , default = False ):
146
146
self .console .print ("[yellow]Deployment cancelled. Please update EMD to the latest version.[/yellow]" )
147
147
raise typer .Exit (0 )
148
-
148
+
149
149
return False # User chose to continue, no bootstrap
150
-
150
+
151
151
elif action == 'auto_bootstrap' :
152
152
# Infrastructure missing/incomplete OR version mismatch - ask for confirmation
153
153
self .show_bootstrap_notification (current_version , deployed_version )
154
-
154
+
155
155
# Ask for user confirmation
156
156
if deployed_version :
157
157
# Update scenario
158
158
confirm_msg = f"Update infrastructure from { deployed_version } to { current_version } ?"
159
159
else :
160
160
# Initialize scenario
161
161
confirm_msg = f"Initialize EMD infrastructure for version { current_version } ?"
162
-
162
+
163
163
if not typer .confirm (confirm_msg , default = True ):
164
164
self .console .print ("[yellow]Bootstrap cancelled. Infrastructure will not be updated.[/yellow]" )
165
165
self .console .print ("[red]Deployment cannot proceed without compatible infrastructure.[/red]" )
166
166
raise typer .Exit (1 )
167
-
167
+
168
168
# User confirmed - proceed with bootstrap
169
169
try :
170
170
from emd .sdk .bootstrap import create_env_stack , get_bucket_name
171
-
171
+
172
172
bucket_name = get_bucket_name (
173
173
bucket_prefix = ENV_BUCKET_NAME_PREFIX ,
174
174
region = region
175
175
)
176
-
176
+
177
177
create_env_stack (
178
178
region = region ,
179
179
stack_name = ENV_STACK_NAME ,
180
180
bucket_name = bucket_name ,
181
181
force_update = True
182
182
)
183
-
183
+
184
184
self .console .print ("[bold green]✅ Infrastructure setup completed successfully![/bold green]" )
185
185
return True
186
-
186
+
187
187
except Exception as e :
188
188
self .console .print (f"[bold red]❌ Infrastructure setup failed: { str (e )} [/bold red]" )
189
189
raise typer .Exit (1 )
190
-
190
+
191
191
return False
192
192
193
193
194
194
# Global instance
195
- smart_bootstrap_manager = SmartBootstrapManager ()
195
+ smart_bootstrap_manager = SmartBootstrapManager ()
0 commit comments