hcs-cli 0.1.317__py3-none-any.whl → 0.1.319__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.
Files changed (112) hide show
  1. hcs_cli/__init__.py +1 -1
  2. hcs_cli/cmds/advisor/html_utils.py +30 -26
  3. hcs_cli/cmds/advisor/recommendation_engine.py +7 -10
  4. hcs_cli/cmds/api.py +5 -3
  5. hcs_cli/cmds/daas/tenant/plan.py +1 -1
  6. hcs_cli/cmds/debug/start.py +2 -3
  7. hcs_cli/cmds/dev/fs/helper/credential_helper.py +2 -0
  8. hcs_cli/cmds/dev/fs/helper/k8s_util.py +0 -1
  9. hcs_cli/cmds/dev/fs/helper/license_info.py +36 -12
  10. hcs_cli/cmds/dev/fs/init.py +38 -5
  11. hcs_cli/cmds/dev/fs/profiler.py +0 -1
  12. hcs_cli/cmds/dev/fs/provided_files/akka.plan.yml +94 -250
  13. hcs_cli/cmds/dev/fs/provided_files/azsim.plan.yml +27 -34
  14. hcs_cli/cmds/dev/fs/provided_files/azure.plan.yml +294 -322
  15. hcs_cli/cmds/dev/fs/provided_files/mqtt-secret.yaml +188 -93
  16. hcs_cli/cmds/dev/fs/provided_files/mqtt-server-external.yaml +4 -5
  17. hcs_cli/cmds/dev/fs/provided_files/patch-mqtt-hostname.yml +3 -3
  18. hcs_cli/cmds/dev/fs/provided_files/patch-vernemq-ssl-depth.json +1 -1
  19. hcs_cli/cmds/dev/fs/tailor.py +7 -12
  20. hcs_cli/cmds/dev/mqtt.py +1 -2
  21. hcs_cli/cmds/dev/onboard.py +35 -1
  22. hcs_cli/cmds/dev/util/mqtt_helper.py +0 -1
  23. hcs_cli/cmds/hoc/search.py +39 -9
  24. hcs_cli/cmds/hst/clean.py +2 -1
  25. hcs_cli/cmds/inventory/assign.py +72 -28
  26. hcs_cli/cmds/inventory/deassign.py +35 -18
  27. hcs_cli/cmds/inventory/logoff.py +86 -8
  28. hcs_cli/cmds/inventory/session.py +2 -2
  29. hcs_cli/cmds/scm/operator.py +2 -2
  30. hcs_cli/cmds/scm/plan.py +131 -3
  31. hcs_cli/cmds/task.py +2 -4
  32. hcs_cli/cmds/template/expand.py +65 -0
  33. hcs_cli/cmds/template/list_usage.py +2 -2
  34. hcs_cli/cmds/template/usage.py +20 -7
  35. hcs_cli/cmds/vm/list.py +0 -1
  36. hcs_cli/config/hcs-deployments.yaml +52 -52
  37. hcs_cli/main.py +0 -2
  38. hcs_cli/payload/akka.blueprint.yml +95 -243
  39. hcs_cli/payload/app/manual.json +19 -19
  40. hcs_cli/payload/edge/akka.json +6 -6
  41. hcs_cli/payload/edge/vsphere.json +6 -6
  42. hcs_cli/payload/hoc/lcm-capcalc.json.template +43 -0
  43. hcs_cli/payload/hoc/no-spare.json.template +1 -1
  44. hcs_cli/payload/inventory/assign.json +14 -16
  45. hcs_cli/payload/inventory/deassign.json +11 -11
  46. hcs_cli/payload/lcm/akka.json +31 -33
  47. hcs_cli/payload/lcm/azure-dummy-nt.json +64 -66
  48. hcs_cli/payload/lcm/azure-dummy.json +64 -66
  49. hcs_cli/payload/lcm/azure-real.json +13 -11
  50. hcs_cli/payload/lcm/edge-proxy.json +34 -36
  51. hcs_cli/payload/lcm/zero-dedicated.json +34 -36
  52. hcs_cli/payload/lcm/zero-delay-1m-per-vm.json +53 -69
  53. hcs_cli/payload/lcm/zero-fail-delete-template.json +43 -0
  54. hcs_cli/payload/lcm/zero-fail-destroy-onthread.json +38 -40
  55. hcs_cli/payload/lcm/zero-fail-destroy.json +38 -40
  56. hcs_cli/payload/lcm/zero-fail-prepare-onthread.json +38 -40
  57. hcs_cli/payload/lcm/zero-fail-prepare.json +38 -40
  58. hcs_cli/payload/lcm/zero-fail-vm-onthread.json +58 -74
  59. hcs_cli/payload/lcm/zero-fail-vm.json +58 -74
  60. hcs_cli/payload/lcm/zero-floating.json +34 -36
  61. hcs_cli/payload/lcm/zero-manual.json +33 -35
  62. hcs_cli/payload/lcm/zero-multisession.json +34 -36
  63. hcs_cli/payload/lcm/zero-nanw.json +31 -33
  64. hcs_cli/payload/lcm/zero-new-5k-delay.json +69 -78
  65. hcs_cli/payload/lcm/zero-new-5k.json +36 -38
  66. hcs_cli/payload/lcm/zero-new-snapshot.json +37 -39
  67. hcs_cli/payload/lcm/zero-new.json +37 -39
  68. hcs_cli/payload/lcm/zero-reuse-vm-id.json +33 -35
  69. hcs_cli/payload/lcm/zero-with-max-id-offset.json +32 -34
  70. hcs_cli/payload/lcm/zero.json +59 -73
  71. hcs_cli/payload/provider/ad-stes-vsphere.json +26 -26
  72. hcs_cli/payload/provider/akka.json +12 -12
  73. hcs_cli/payload/provider/azure.json +14 -14
  74. hcs_cli/payload/provider/edgeproxy.json +12 -12
  75. hcs_cli/payload/provider/vsphere.json +14 -14
  76. hcs_cli/payload/scm/starter.json +22 -23
  77. hcs_cli/payload/synt/core/p01-dummy-success.json +11 -15
  78. hcs_cli/payload/synt/core/p02-dummy-fail.json +12 -15
  79. hcs_cli/payload/synt/core/p03-dummy-exception.json +12 -15
  80. hcs_cli/payload/synt/core/p04-dummy-success-repeat.json +12 -15
  81. hcs_cli/payload/synt/core/p05-dummy-fail-repeat.json +13 -16
  82. hcs_cli/payload/synt/core/p06-dummy-exception-repeat.json +13 -16
  83. hcs_cli/payload/synt/core/p07-dummy-delay.json +12 -15
  84. hcs_cli/payload/synt/core/p08-dummy-property.json +12 -15
  85. hcs_cli/payload/synt/ext/p20-connect-success.json +12 -15
  86. hcs_cli/payload/synt/ext/p21-connect-fail.json +12 -15
  87. hcs_cli/payload/synt/ext/p30-ssl-success.json +12 -15
  88. hcs_cli/payload/synt/ext/p31-ssl-fail.json +13 -16
  89. hcs_cli/payload/synt/ext/p40-http-success.json +12 -15
  90. hcs_cli/payload/synt/ext/p41-http-fail.json +12 -15
  91. hcs_cli/payload/synt/ext/p42-http-status-code.json +14 -20
  92. hcs_cli/payload/synt/ext1/p10-ping-success.json +13 -16
  93. hcs_cli/payload/synt/ext1/p11-ping-fail.json +12 -15
  94. hcs_cli/payload/synt/ext1/p12-ping-success-repeat.json +14 -17
  95. hcs_cli/provider/hcs/cert.py +0 -1
  96. hcs_cli/provider/hcs/edge.py +1 -1
  97. hcs_cli/provider/hcs/uag.py +6 -1
  98. hcs_cli/service/hoc/diagnostic.py +0 -3
  99. hcs_cli/service/inventory/__init__.py +1 -1
  100. hcs_cli/service/inventory/session.py +23 -7
  101. hcs_cli/service/lcm/vm.py +0 -1
  102. hcs_cli/service/task.py +0 -1
  103. hcs_cli/support/debug_util.py +0 -1
  104. hcs_cli/support/plan_util.py +0 -1
  105. hcs_cli/support/predefined_payload.py +4 -1
  106. hcs_cli/support/template_util.py +0 -1
  107. hcs_cli/support/test_utils.py +2 -2
  108. hcs_cli/support/test_utils2.py +536 -0
  109. {hcs_cli-0.1.317.dist-info → hcs_cli-0.1.319.dist-info}/METADATA +24 -17
  110. {hcs_cli-0.1.317.dist-info → hcs_cli-0.1.319.dist-info}/RECORD +112 -108
  111. {hcs_cli-0.1.317.dist-info → hcs_cli-0.1.319.dist-info}/WHEEL +0 -0
  112. {hcs_cli-0.1.317.dist-info → hcs_cli-0.1.319.dist-info}/entry_points.txt +0 -0
hcs_cli/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
- __version__ = "0.1.317"
1
+ __version__ = "0.1.319"
2
2
 
3
3
  from . import service
@@ -131,10 +131,10 @@ def prepare_vm_utilization_chart_data(template_info: dict) -> dict:
131
131
  utilized_capacity.append(0)
132
132
 
133
133
  start_date = datetime.fromtimestamp(start_timestamp / 1000)
134
- x_axis = [start_date + timedelta(minutes=(timeslot_ms / (1000 * 60)) * i) for i in range(data_length)]
134
+ x_axis_dt = [start_date + timedelta(minutes=(timeslot_ms / (1000 * 60)) * i) for i in range(data_length)]
135
135
 
136
136
  # Convert datetime objects to formatted strings for ECharts
137
- x_axis = [dt.strftime("%Y-%m-%d %H:%M") for dt in x_axis]
137
+ x_axis = [dt.strftime("%Y-%m-%d %H:%M") for dt in x_axis_dt]
138
138
  else:
139
139
  x_axis = []
140
140
  provisioned_vms = []
@@ -287,7 +287,7 @@ def _get_pool_html_template(
287
287
  itemStyle: {{
288
288
  color: '#007acc'
289
289
  }},
290
- data: {chart_data['provisioned_vms']}
290
+ data: {chart_data["provisioned_vms"]}
291
291
  }},
292
292
  {{
293
293
  name: 'Powered-on VMs',
@@ -303,7 +303,7 @@ def _get_pool_html_template(
303
303
  itemStyle: {{
304
304
  color: '#dc3545'
305
305
  }},
306
- data: {chart_data['powered_on_vms']}
306
+ data: {chart_data["powered_on_vms"]}
307
307
  }},
308
308
  {{
309
309
  name: 'Utilized Capacity',
@@ -319,7 +319,7 @@ def _get_pool_html_template(
319
319
  itemStyle: {{
320
320
  color: '#28a745'
321
321
  }},
322
- data: {chart_data['utilized_capacity']}
322
+ data: {chart_data["utilized_capacity"]}
323
323
  }}
324
324
  """
325
325
  else: # line chart
@@ -332,7 +332,7 @@ def _get_pool_html_template(
332
332
  focus: 'series'
333
333
  }},
334
334
  color: '#007acc',
335
- data: {chart_data['provisioned_vms']}
335
+ data: {chart_data["provisioned_vms"]}
336
336
  }},
337
337
  {{
338
338
  name: 'Powered-on VMs',
@@ -342,7 +342,7 @@ def _get_pool_html_template(
342
342
  focus: 'series'
343
343
  }},
344
344
  color: '#dc3545',
345
- data: {chart_data['powered_on_vms']}
345
+ data: {chart_data["powered_on_vms"]}
346
346
  }},
347
347
  {{
348
348
  name: 'Utilized Capacity',
@@ -352,7 +352,7 @@ def _get_pool_html_template(
352
352
  focus: 'series'
353
353
  }},
354
354
  color: '#28a745',
355
- data: {chart_data['utilized_capacity']}
355
+ data: {chart_data["utilized_capacity"]}
356
356
  }}
357
357
  """
358
358
 
@@ -557,19 +557,21 @@ def _get_pool_html_template(
557
557
  </html>
558
558
  """
559
559
 
560
- return yumako.template.replace(
561
- template,
562
- {
563
- "org_name": org_name,
564
- "resource_type": resource_type,
565
- "resource_id": resource_id,
566
- "generation_date": generation_date,
567
- "summary_html": summary_html,
568
- "usage_table_html": usage_table_html,
569
- "recommendations_html": recommendations_html,
570
- "x_axis_data": chart_data["x_axis"],
571
- "chart_series_data": chart_series,
572
- },
560
+ return str(
561
+ yumako.template.replace(
562
+ template,
563
+ {
564
+ "org_name": org_name,
565
+ "resource_type": resource_type,
566
+ "resource_id": resource_id,
567
+ "generation_date": generation_date,
568
+ "summary_html": summary_html,
569
+ "usage_table_html": usage_table_html,
570
+ "recommendations_html": recommendations_html,
571
+ "x_axis_data": chart_data["x_axis"],
572
+ "chart_series_data": chart_series,
573
+ },
574
+ )
573
575
  )
574
576
 
575
577
 
@@ -600,8 +602,8 @@ def _get_org_html_template(org_name: str, generation_date: str, all_recommendati
600
602
  recommended_settings = json.dumps(rec["recommended_settings"], indent=2)
601
603
  recommendations_html += f"""
602
604
  <tr>
603
- <td>{rec['action']}</td>
604
- <td>{rec['justification']}</td>
605
+ <td>{rec["action"]}</td>
606
+ <td>{rec["justification"]}</td>
605
607
  <td><pre>{current_settings}</pre></td>
606
608
  <td><pre>{recommended_settings}</pre></td>
607
609
  </tr>
@@ -709,7 +711,9 @@ def _get_org_html_template(org_name: str, generation_date: str, all_recommendati
709
711
  </html>
710
712
  """
711
713
 
712
- return yumako.template.replace(
713
- template,
714
- {"org_name": org_name, "generation_date": generation_date, "recommendations_html": recommendations_html},
714
+ return str(
715
+ yumako.template.replace(
716
+ template,
717
+ {"org_name": org_name, "generation_date": generation_date, "recommendations_html": recommendations_html},
718
+ )
715
719
  )
@@ -1,8 +1,6 @@
1
1
  """
2
2
  Copyright © 2025 Omnissa, LLC.
3
- """
4
3
 
5
- """
6
4
  Recommendation engine for generating recommendations for advisor reports.
7
5
  """
8
6
 
@@ -137,7 +135,7 @@ def calculate_observation_period_days(template_info: dict) -> float:
137
135
  observation_hours = (data_length_after_cutoff * timeslot_ms) / (1000 * 60 * 60)
138
136
  observation_days = observation_hours / 24
139
137
 
140
- return max(1.0, observation_days) # Minimum 1 day
138
+ return float(max(1.0, observation_days)) # Minimum 1 day
141
139
  except Exception:
142
140
  return 30.0 # Default to 30 days
143
141
 
@@ -259,7 +257,7 @@ def calculate_peak_utilized_capacity(template_info: dict) -> int:
259
257
  else:
260
258
  peak_capacity = peak_sessions
261
259
 
262
- return peak_capacity
260
+ return int(peak_capacity)
263
261
  except Exception:
264
262
  return 0
265
263
 
@@ -377,7 +375,7 @@ def estimate_cost_savings_max_vms_reduction(old_max_vms: int, new_max_vms: int,
377
375
  # Total savings = VM savings + disk savings
378
376
  total_savings = vm_savings + disk_savings
379
377
 
380
- return round(total_savings, 2)
378
+ return float(round(total_savings, 2))
381
379
  except Exception:
382
380
  return 0.0
383
381
 
@@ -478,7 +476,7 @@ def calculate_scheduled_powered_on_hours(template_info: dict, power_schedules: l
478
476
  # Calculate total powered-on hours during scheduled periods
479
477
  total_scheduled_hours = sum(scheduled_powered_on) * timeslot_hours
480
478
 
481
- return total_scheduled_hours
479
+ return float(total_scheduled_hours)
482
480
 
483
481
  except Exception as e:
484
482
  print(f"Warning: Error calculating scheduled powered-on hours: {str(e)}")
@@ -658,7 +656,7 @@ def estimate_cost_savings_min_available_vms(old_min: float, new_min: float, temp
658
656
 
659
657
  # Calculate savings
660
658
  savings = limit * (old_min - new_min) * config.HOURS_PER_MONTH * vm_cost_per_hour
661
- return round(savings, 2)
659
+ return float(round(savings, 2))
662
660
  except Exception:
663
661
  return 0.0
664
662
 
@@ -1067,7 +1065,7 @@ def calculate_schedule_resource_utilization(template_info: dict, power_schedules
1067
1065
  # Calculate utilization percentage
1068
1066
  if scheduled_allocated_hours > 0:
1069
1067
  utilization = (scheduled_utilized_hours / scheduled_allocated_hours) * 100
1070
- return max(0.0, utilization)
1068
+ return float(max(0.0, utilization))
1071
1069
 
1072
1070
  return 0.0
1073
1071
 
@@ -1088,7 +1086,6 @@ def _is_within_scheduled_period(point_datetime, power_schedules):
1088
1086
  bool: True if point falls within any scheduled period
1089
1087
  """
1090
1088
  try:
1091
-
1092
1089
  # Get day of week (0=Monday, 6=Sunday)
1093
1090
  day_of_week = point_datetime.weekday()
1094
1091
  # Convert to our bit mask format (0=Monday, 6=Sunday)
@@ -1486,7 +1483,7 @@ def is_all_at_once_provisioning(template_info: dict) -> bool:
1486
1483
  min_vms = spare_policy.get("min", 0)
1487
1484
 
1488
1485
  # "All at once" if limit == max == min
1489
- return limit > 0 and limit == max_vms and max_vms == min_vms
1486
+ return bool(limit > 0 and limit == max_vms and max_vms == min_vms)
1490
1487
  except Exception:
1491
1488
  return False
1492
1489
 
hcs_cli/cmds/api.py CHANGED
@@ -134,13 +134,14 @@ def api(
134
134
  f"Method {method} does not support request body. Use --data or --json or STDIN only with POST, PUT, or PATCH methods."
135
135
  )
136
136
 
137
- if path.startswith(profile.current().hcs.url):
138
- path = path[len(profile.current().hcs.url) :]
137
+ hcs_url = profile.current().hcs.url
138
+ if path.startswith(hcs_url):
139
+ path = path[len(hcs_url) :]
139
140
  if not path.startswith("/"):
140
141
  path = "/" + path
141
142
 
142
143
  if not path.startswith("/"):
143
- raise click.UsageError("Path must start with a '/'. Please provide a valid context path.")
144
+ raise click.UsageError("Path must start with a '/'. Please provide a valid context path. Provided path=" + path)
144
145
 
145
146
  service_path = path.split("/")[1]
146
147
  api_path = path[len(service_path) + 1 :]
@@ -155,6 +156,7 @@ def api(
155
156
  headers = None
156
157
 
157
158
  # print( f"{method} {api_path} text={raw_data} json={json_data}" )
159
+
158
160
  if method == "GET":
159
161
  if all_pages:
160
162
 
@@ -90,7 +90,7 @@ def _select_order_type(var: dict):
90
90
  def fn_get_text(order_type: str):
91
91
  o = orders[order_type]
92
92
  num_apps = len(o["application"]["info"])
93
- desc = f'{o["template"]["type"]}/{o["image"]["os"]},{o["image"]["gen"]}, apps: {num_apps}'
93
+ desc = f"{o['template']['type']}/{o['image']['os']},{o['image']['gen']}, apps: {num_apps}"
94
94
  ret = f"{order_type} ({desc})"
95
95
  return ret
96
96
 
@@ -52,15 +52,14 @@ def start(service: str, skip: bool, force: bool, **kwargs):
52
52
 
53
53
  def pod_forwarding(pod_id):
54
54
  print("Start forwarding pod")
55
- pod_forwarding_command = f"kubectl port-forward {pod_id} 10762:10762"
55
+ pod_forwarding_command = f"kubectl port-forward {pod_id} 5005:5005"
56
56
  global _forwarding_process
57
57
  _forwarding_process = subprocess.Popen(shlex.split(pod_forwarding_command), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
58
58
  print("Started forwarding pod. pid:", _forwarding_process.pid)
59
59
 
60
60
 
61
61
  def run_with_debug(pod_id):
62
-
63
- run_app_command = f"kubectl exec -it {pod_id} -c app -- /bin/bash -c 'java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=10762 -jar app.jar'"
62
+ run_app_command = f"kubectl exec -it {pod_id} -c app -- /bin/bash -c 'java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -jar app.jar'"
64
63
 
65
64
  # Execute the command
66
65
  process = subprocess.Popen(shlex.split(run_app_command), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@@ -12,6 +12,8 @@ def _get_application_properties_from_configmap(configmap_name: str):
12
12
  log.warn(f"ConfigMap {configmap_name} not found.")
13
13
  return {}
14
14
  app_properties_text = config["data"].get("application.properties")
15
+ if app_properties_text is None:
16
+ app_properties_text = config["data"].get("application-group.properties")
15
17
  if app_properties_text is not None:
16
18
  lines = app_properties_text.split("\n")
17
19
  app_properties = {}
@@ -35,7 +35,6 @@ def kubectl(command: str, ignore_error: bool = False, get_json: bool = False, in
35
35
 
36
36
 
37
37
  def validate_kubeconfig(fs_name: str, try_default_config: bool = True, raise_on_error: bool = True):
38
-
39
38
  if os.path.exists(_fs_kubeconfig):
40
39
  log.info("Using feature stack kubeconfig: " + _fs_kubeconfig)
41
40
  global _kubectl_command
@@ -74,18 +74,42 @@ def createLicenseFeatures():
74
74
  log.trivial("Creating license features record for csp org id {}".format(org_id))
75
75
  client_id = os.environ.get("CSP_LICENSE_SVC_CLIENT_ID")
76
76
  client_secret = os.environ.get("CSP_LICENSE_SVC_CLIENT_SECRET")
77
- if not client_id:
78
- print("Using admin service credentials from current profile...") # which has service permission
79
- client_id = current_profile.override["admin"]["client-id"]
80
- client_secret = current_profile.override["admin"]["client-secret"]
81
- client = hcs_client(
82
- current_profile.hcs.url,
83
- {
84
- "url": current_profile.csp.url,
85
- "client_id": client_id,
86
- "client_secret": client_secret,
87
- },
88
- )
77
+ while True:
78
+ if client_id:
79
+ log.trivial("Using credentials from env CSP_LICENSE_SVC_CLIENT_ID")
80
+ break
81
+ override = current_profile.override
82
+ if override:
83
+ license_service_override = current_profile.override.get("license-features")
84
+ if license_service_override:
85
+ log.trivial("Using license-features service override from current profile...")
86
+ client_id = license_service_override["client-id"]
87
+ client_secret = license_service_override["client-secret"]
88
+ break
89
+
90
+ admin_override = current_profile.override.get("admin")
91
+ if admin_override:
92
+ log.trivial("Using admin service override from current profile...")
93
+ client_id = current_profile.override["admin"]["client-id"]
94
+ client_secret = current_profile.override["admin"]["client-secret"]
95
+ break
96
+
97
+ log.warn("No admin override found in current profile. Using default credentials.")
98
+ client_id = None
99
+ break
100
+
101
+ if client_id:
102
+ client = hcs_client(
103
+ current_profile.hcs.url,
104
+ {
105
+ "url": current_profile.csp.url,
106
+ "client_id": client_id,
107
+ "client_secret": client_secret,
108
+ },
109
+ )
110
+ else:
111
+ # default profile
112
+ client = hcs_client(url=current_profile.hcs.url, custom_auth=current_profile.csp)
89
113
  response_data = client.post("/license-features/v1/licenses", json=data)
90
114
  log.good(f"Successfully created license-features: {response_data}")
91
115
 
@@ -17,6 +17,7 @@ import inspect
17
17
  import json
18
18
  import os
19
19
  import re
20
+ import tempfile
20
21
  import shutil
21
22
  import subprocess
22
23
  import time
@@ -25,6 +26,7 @@ from pathlib import Path
25
26
 
26
27
  import click
27
28
  import hcs_core.sglib.cli_options as cli
29
+ import yaml
28
30
  from dotenv import load_dotenv
29
31
  from hcs_core.ctxp import context, profile
30
32
  from hcs_core.ctxp.util import error_details
@@ -290,8 +292,34 @@ def _create_infra_azure(fs_name):
290
292
 
291
293
  @step
292
294
  def _create_infra_azsim():
293
- azusim_plan_path = _resolve_bundled_file_path("provided_files/azsim.plan.yml")
294
- ret = run_cli("hcs plan apply -f " + azusim_plan_path, raise_on_error=False)
295
+ import requests
296
+
297
+ # Fetch credentials from simhub
298
+ SIMHUB_URL = "https://simhub.steslabs.net/subscription"
299
+ try:
300
+ resp = requests.get(SIMHUB_URL)
301
+ resp.raise_for_status()
302
+ creds = resp.json()
303
+ except Exception as e:
304
+ log.warn(f"Failed to fetch simhub credentials: {e}")
305
+ return
306
+ log.info(f"Azure Simulator credentials fetched from simhub: {creds}")
307
+ # Read the plan template
308
+ plan_template_path = _resolve_bundled_file_path("provided_files/azsim.plan.yml")
309
+ with open(plan_template_path, "r") as f:
310
+ plan = yaml.safe_load(f)
311
+
312
+ # Overwrite provider values
313
+ plan["var"]["provider"]["subscriptionId"] = creds["subscriptionId"]
314
+
315
+ # Write to a temp file
316
+ tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".yml", mode="w")
317
+ yaml.dump(plan, tmp)
318
+ tmp.close()
319
+ dynamic_plan_path = tmp.name
320
+
321
+ # Apply the plan
322
+ ret = run_cli("hcs plan apply -f " + dynamic_plan_path, raise_on_error=False)
295
323
  if ret.returncode == 0:
296
324
  log.good("Azure simulator infrastructure set up.")
297
325
  else:
@@ -469,8 +497,8 @@ def _write_env_file(data, props, env_file):
469
497
  for key, value in data.items():
470
498
  if key not in ignore_keys:
471
499
  f.write(f"{to_env_key(key)}={value}\n")
472
- config_block = f"""HCS_CLIENT_ID={props['csp.service.app.client_id']}
473
- HCS_CLIENT_SECRET={props['csp.service.app.client_secret']}
500
+ config_block = f"""HCS_CLIENT_ID={props["csp.service.app.client_id"]}
501
+ HCS_CLIENT_SECRET={props["csp.service.app.client_secret"]}
474
502
  IDP_TENANT_DOMAIN=test-sanity-domain
475
503
  UAG_FQDN=myuag.fqdn
476
504
  DESKTOP_SUBNET_CIDR=10.76.0.0/16
@@ -1016,12 +1044,17 @@ def _create_idp():
1016
1044
  log.good("IDP set up.")
1017
1045
  except Exception as e:
1018
1046
  print(e)
1019
- fail("IDP credentials require 2FA which is currently not supported. Please manually set up your IDP in Astro.")
1047
+ fail(
1048
+ "IDP credentials require 2FA, which is currently not supported via API calls. Please manually set up "
1049
+ "your IDP in Astro. Once you have completed set up, re-run the 'hcs dev fs init' command skipping the"
1050
+ "Common Init step."
1051
+ )
1020
1052
 
1021
1053
 
1022
1054
  @step
1023
1055
  def _restart_services():
1024
1056
  kubectl("rollout restart deployment portal-deployment", ignore_error=True)
1057
+ kubectl("rollout restart deployment infra-vsphere-twin-deployment", ignore_error=True)
1025
1058
  kubectl("rollout restart statefulset vmhub-statefulset", ignore_error=True)
1026
1059
  kubectl("rollout restart statefulset connection-service-statefulset", ignore_error=True)
1027
1060
  kubectl("rollout restart statefulset clouddriver-statefulset", ignore_error=True)
@@ -65,7 +65,6 @@ def _run_mongo_commands(command: str):
65
65
 
66
66
 
67
67
  def _enable_mongo_profiler():
68
-
69
68
  mongo_commands = """
70
69
  use app
71
70
  db.setProfilingLevel(0)