@@ -36,6 +36,106 @@ from cloudutils.cloudException import CloudRuntimeException, CloudInternalExcept
3636from cloudutils .globalEnv import globalEnv
3737from cloudutils .serviceConfigServer import cloudManagementConfig
3838from optparse import OptionParser
39+ import urllib .request
40+ import configparser
41+ import hashlib
42+
43+ SYSTEMVM_TEMPLATES_PATH = "/usr/share/cloudstack-management/templates/systemvm"
44+ SYSTEMVM_TEMPLATES_METADATA_FILE = SYSTEMVM_TEMPLATES_PATH + "/metadata.ini"
45+
46+ def verify_sha512_checksum (file_path , expected_checksum ):
47+ sha512 = hashlib .sha512 ()
48+ try :
49+ with open (file_path , "rb" ) as f :
50+ for chunk in iter (lambda : f .read (8192 ), b"" ):
51+ sha512 .update (chunk )
52+ return sha512 .hexdigest ().lower () == expected_checksum .lower ()
53+ except Exception as e :
54+ print (f"Failed to verify checksum for { file_path } : { e } " )
55+ return False
56+
57+ def download_file (url , dest_path , chunk_size = 8 * 1024 * 1024 ):
58+ """
59+ Downloads a file from the given URL to the specified destination path in chunks.
60+ """
61+ try :
62+ with urllib .request .urlopen (url ) as response :
63+ total_size = response .length if response .length else None
64+ downloaded = 0
65+ try :
66+ with open (dest_path , 'wb' ) as out_file :
67+ while True :
68+ chunk = response .read (chunk_size )
69+ if not chunk :
70+ break
71+ out_file .write (chunk )
72+ downloaded += len (chunk )
73+ if total_size :
74+ print (f"Downloaded { downloaded / (1024 * 1024 ):.2f} MB of { total_size / (1024 * 1024 ):.2f} MB" , end = '\r ' )
75+ except PermissionError as pe :
76+ print (f"Permission denied: { dest_path } " )
77+ raise
78+ print (f"\n Downloaded file from { url } to { dest_path } " )
79+ except Exception as e :
80+ print (f"Failed to download file: { e } " )
81+ raise
82+
83+ def download_template_if_needed (template , url , filename , checksum ):
84+ dest_path = os .path .join (SYSTEMVM_TEMPLATES_PATH , filename )
85+ if os .path .exists (dest_path ):
86+ if checksum and verify_sha512_checksum (dest_path , checksum ):
87+ print (f"{ template } System VM template already exists at { dest_path } with valid checksum, skipping download." )
88+ return
89+ else :
90+ print (f"{ template } System VM template at { dest_path } has invalid or missing checksum, re-downloading..." )
91+ else :
92+ print (f"Downloading { template } System VM template from { url } to { dest_path } ..." )
93+ try :
94+ download_file (url , dest_path )
95+ #After download, verify checksum if provided
96+ if checksum :
97+ if verify_sha512_checksum (dest_path , checksum ):
98+ print (f"{ template } System VM template downloaded and verified successfully." )
99+ else :
100+ print (f"ERROR: Checksum verification failed for { template } System VM template after download." )
101+ except Exception as e :
102+ print (f"ERROR: Failed to download { template } System VM template: { e } " )
103+
104+ def collect_template_metadata (selected_templates , options ):
105+ template_metadata_list = []
106+ if not os .path .exists (SYSTEMVM_TEMPLATES_METADATA_FILE ):
107+ print (f"ERROR: System VM templates metadata file not found at { SYSTEMVM_TEMPLATES_METADATA_FILE } , cannot download templates." )
108+ sys .exit (1 )
109+ config = configparser .ConfigParser ()
110+ config .read (SYSTEMVM_TEMPLATES_METADATA_FILE )
111+ template_repo_url = None
112+ if options .systemvm_templates_repository :
113+ if "default" in config and "downloadrepository" in config ["default" ]:
114+ template_repo_url = config ["default" ]["downloadrepository" ].strip ()
115+ if not template_repo_url :
116+ print ("ERROR: downloadrepository value is empty in metadata file, cannot use --systemvm-template-repository option." )
117+ sys .exit (1 )
118+ for template in selected_templates :
119+ if template in config :
120+ url = config [template ].get ("downloadurl" )
121+ filename = config [template ].get ("filename" )
122+ checksum = config [template ].get ("checksum" )
123+ if url and filename :
124+ if template_repo_url :
125+ url = url .replace (template_repo_url , options .systemvm_templates_repository )
126+ template_metadata_list .append ({
127+ "template" : template ,
128+ "url" : url ,
129+ "filename" : filename ,
130+ "checksum" : checksum
131+ })
132+ else :
133+ print (f"ERROR: URL or filename not found for { template } System VM template in metadata." )
134+ sys .exit (1 )
135+ else :
136+ print (f"ERROR: No metadata found for { template } System VM template." )
137+ sys .exit (1 )
138+ return template_metadata_list
39139
40140if __name__ == '__main__' :
41141 initLoging ("@MSLOGDIR@/setupManagement.log" )
@@ -45,6 +145,16 @@ if __name__ == '__main__':
45145 parser .add_option ("--https" , action = "store_true" , dest = "https" , help = "Enable HTTPs connection of management server" )
46146 parser .add_option ("--tomcat7" , action = "store_true" , dest = "tomcat7" , help = "Depreciated option, don't use it" )
47147 parser .add_option ("--no-start" , action = "store_true" , dest = "nostart" , help = "Do not start management server after successful configuration" )
148+ parser .add_option (
149+ "--systemvm-templates" ,
150+ dest = "systemvm_templates" ,
151+ help = "Specify System VM templates to download: all, kvm-aarch64, kvm-x86_64, xenserver, vmware or comma-separated list of hypervisor combinations (e.g., kvm-x86_64,xenserver). Default is kvm-x86_64." ,
152+ )
153+ parser .add_option (
154+ "--systemvm-templates-repository" ,
155+ dest = "systemvm_templates_repository" ,
156+ help = "Specify the URL to download System VM templates from."
157+ )
48158 (options , args ) = parser .parse_args ()
49159 if options .https :
50160 glbEnv .svrMode = "HttpsServer"
@@ -53,6 +163,34 @@ if __name__ == '__main__':
53163 if options .nostart :
54164 glbEnv .noStart = True
55165
166+ available_templates = ["kvm-aarch64" , "kvm-x86_64" , "xenserver" , "vmware" ]
167+ templates_arg = options .systemvm_templates
168+
169+ selected_templates = ["kvm-x86_64" ]
170+ if templates_arg :
171+ templates_list = [t .strip ().lower () for t in templates_arg .split ("," )]
172+ if "all" in templates_list :
173+ if len (templates_list ) > 1 :
174+ print ("WARNING: 'all' specified for System VM templates, ignoring other specified templates." )
175+ selected_templates = available_templates
176+ else :
177+ invalid_templates = []
178+ for t in templates_list :
179+ if t in available_templates :
180+ if t not in selected_templates :
181+ selected_templates .append (t )
182+ else :
183+ if t not in invalid_templates :
184+ invalid_templates .append (t )
185+ if invalid_templates :
186+ print (f"ERROR: Invalid System VM template names provided: { ', ' .join (invalid_templates )} " )
187+ sys .exit (1 )
188+ print (f"Selected systemvm templates to download: { ', ' .join (selected_templates ) if selected_templates else 'None' } " )
189+
190+ template_metadata_list = []
191+ if selected_templates :
192+ template_metadata_list = collect_template_metadata (selected_templates , options )
193+
56194 glbEnv .mode = "Server"
57195
58196 print ("Starting to configure CloudStack Management Server:" )
@@ -74,3 +212,6 @@ if __name__ == '__main__':
74212 syscfg .restore ()
75213 except :
76214 pass
215+
216+ for meta in template_metadata_list :
217+ download_template_if_needed (meta ["template" ], meta ["url" ], meta ["filename" ], meta ["checksum" ])
0 commit comments