Merge branch 'worker-async' into enrollment-key

This commit is contained in:
2025-03-25 14:07:24 +10:30
50 changed files with 4573 additions and 1159 deletions
+151 -9
View File
@@ -2,19 +2,31 @@ import json
import streamlit as st
from streamlit_server.utils.helpers import format_timestamp
def render():
def render_list():
"""
Renders a list of all container workloads.
"""
st.header("Container Workload Management")
# Initialize session state variables for delete all confirmation
if 'container_delete_all_confirmation_shown' not in st.session_state:
st.session_state.container_delete_all_confirmation_shown = False
if 'container_delete_all_confirmed' not in st.session_state:
st.session_state.container_delete_all_confirmed = False
# Initialize session state variables for delete confirmation
if 'container_delete_confirmation_shown' not in st.session_state:
st.session_state.container_delete_confirmation_shown = False
if 'container_delete_confirmed' not in st.session_state:
st.session_state.container_delete_confirmed = False
# Fetch all VDCs for the dropdown
vdcs = st.session_state.client.get_vdcs()
vdcs = st.session_state.client.get_virtual_data_centers()
vdc_options = {vdc['name']: vdc['id'] for vdc in vdcs} if vdcs else {}
# Add a dropdown to select VDC
selected_vdc_name = st.selectbox("Filter by Virtual Data Center", list(vdc_options.keys()))
# Fetch all Workloads_hosts for the dropdown
workload_hosts = st.session_state.client.get_workload_hosts()
workload_host_options = {workload_host['hostname']: workload_host['id'] for workload_host in workload_hosts} if workload_hosts else {}
@@ -42,11 +54,11 @@ def render():
})
if result:
st.success("Container workload created successfully!")
# List Container Workloads
st.subheader("Existing Container Workloads")
containers = st.session_state.client.get_containers()
if containers:
# Filter containers based on the selected VDC
if selected_vdc_name:
@@ -55,6 +67,40 @@ def render():
else:
filtered_containers = containers
# Delete All functionality
if not st.session_state.container_delete_all_confirmation_shown:
if st.button("Delete All Containers", key="delete_all_containers", type="primary", help="This will delete all visible containers"):
st.session_state.container_delete_all_confirmation_shown = True
st.rerun()
# Show confirmation if delete was clicked
if st.session_state.container_delete_all_confirmation_shown and not st.session_state.container_delete_all_confirmed:
st.warning("Are you sure you want to delete all containers? This action cannot be undone.")
confirm_col1, confirm_col2 = st.columns([1, 1])
with confirm_col1:
if st.button("Yes, Delete All", key="confirm_delete_all_containers"):
st.session_state.container_delete_all_confirmed = True
st.rerun()
with confirm_col2:
if st.button("Cancel", key="cancel_delete_all_containers"):
st.session_state.container_delete_all_confirmation_shown = False
st.rerun()
# Perform deletion if confirmed
if st.session_state.container_delete_all_confirmed:
deletion_count = 0
for container in filtered_containers:
# Call the delete API for each container
result = st.session_state.client.delete_container(container['id'])
if result:
deletion_count += 1
st.success(f"Successfully deleted {deletion_count} containers.")
# Reset the confirmation flags
st.session_state.container_delete_all_confirmation_shown = False
st.session_state.container_delete_all_confirmed = False
# Display the containers
for container in filtered_containers:
with st.container():
col1, col2, col3 = st.columns([3, 1, 1])
@@ -78,14 +124,110 @@ def render():
st.text(f"Image: {container_name}")
with col2:
st.text(f"ID: {container['id']}")
with col3:
with col3:
if st.button("View Details", key=f"view_{container['id']}"):
print("Button is pressed")
st.session_state.selected_resource = container
st.session_state.view_type = 'detail'
st.session_state.selected_resource_type = 'container'
st.rerun()
# st.switch_page("streamlit_server/views/containers.py&container_id=d", query_params={"team": "streamlit"})
else:
st.info("No container workloads found.")
def render_detail():
"""
Renders the details of a specific container workload.
"""
container = st.session_state.client.get_container(st.session_state.selected_resource['id'])
if not container:
st.error("Container workload not found.")
st.session_state.selected_resource = None
st.session_state.view_type = 'list'
st.session_state.selected_resource_type = None
return
st.title(f"Container Workload: {container['container_id']}")
if st.button("Back to list view"):
st.session_state.view_type = 'list'
st.rerun()
st.header("Container Workload Details")
col1, col2 = st.columns(2)
with col1:
st.markdown(f"**ID:** `{container['id']}`")
st.markdown(f"**Created:** {format_timestamp(container.get('created_at', 'Unknown'))}")
st.markdown(f"**VDC ID:** {container['vdc_id']}")
st.markdown(f"**Workload Host ID:** {container.get('container_host_id', 'N/A')}")
with col2:
if container.get('updated_at'):
st.markdown(f"**Last Updated:** {format_timestamp(container['updated_at'])}")
st.markdown(f"**Status:** {container['status']}")
st.markdown(f"**Launch Parameters:** {container.get('launch_params', 'N/A')}")
# Edit Container Workload Form
with st.expander("Edit Container Workload"):
with st.form("edit_container"):
new_status = st.selectbox("Status", ["running", "stopped", "pending","failed-deleted","pending-deleted","pending-allocation","failed-allocation","pending-allocated"], index=["running", "stopped", "pending","failed-deleted","pending-deleted","pending-allocation","failed-allocation","pending-allocated"].index(container['status']))
new_launch_params = st.text_input("Launch Parameters", value=container.get('launch_params', ''))
submit = st.form_submit_button("Update Container Workload")
if submit:
result = st.session_state.client.edit_container(container['id'], {
"status": new_status,
"launch_params": new_launch_params
})
if result:
st.success("Container workload updated successfully!")
st.session_state.selected_resource = container
st.session_state.view_type = 'detail'
st.session_state.selected_resource_type = 'container'
st.rerun()
# Delete functionality
if not st.session_state.container_delete_confirmation_shown:
if st.button("Delete container", key="delete_container", type="primary", help="This will delete visible container"):
st.session_state.container_delete_confirmation_shown = True
st.rerun()
# Show confirmation if delete was clicked
if st.session_state.container_delete_confirmation_shown and not st.session_state.container_delete_confirmed:
st.warning("Are you sure you want to delete container? This action cannot be undone.")
confirm_col1, confirm_col2 = st.columns([1, 1])
with confirm_col1:
if st.button("Yes, Delete", key="confirm_delete_container"):
st.session_state.container_delete_confirmed = True
st.rerun()
with confirm_col2:
if st.button("Cancel", key="cancel_delete_container"):
st.session_state.container_delete_confirmation_shown = False
st.rerun()
# Perform deletion if confirmed
if st.session_state.container_delete_confirmed:
result = st.session_state.client.delete_container(container['id'])
st.session_state.container_delete_confirmation_shown = False
st.session_state.container_delete_confirmed = False
if result:
st.success("Container workload deleted successfully!")
st.session_state.selected_resource = None
st.session_state.view_type = 'list'
st.session_state.selected_resource_type = 'container'
st.rerun()
st.success(f"Successfully deleted container.")
# Reset the confirmation flags
st.session_state.container_delete_confirmation_shown = False
st.session_state.container_delete_confirmed = False
if st.session_state.view_type == 'detail' and st.session_state.selected_resource_type=='container':
render_detail()
else:
render_list()
+34
View File
@@ -0,0 +1,34 @@
import streamlit as st
import pandas as pd
from streamlit_server.utils.helpers import format_timestamp
# def render():
st.header("Dashboard")
workload_hosts = st.session_state.client.get_workload_hosts()
st.subheader("Workload Hosts")
if workload_hosts:
workload_hosts_df = pd.DataFrame(workload_hosts)
st.dataframe(workload_hosts_df)
else:
st.info("No workload hosts found.")
images = st.session_state.client.get_images()
st.subheader("Images")
if images:
images_df = pd.DataFrame(images)
st.dataframe(images_df)
else:
st.info("No workload hosts found.")
regions = st.session_state.client.get_regions()
st.subheader("regions")
if regions:
regions_df = pd.DataFrame(regions)
st.dataframe(regions_df)
else:
st.info("No workload hosts found.")
-208
View File
@@ -1,208 +0,0 @@
import streamlit as st
import pandas as pd
from streamlit_server.utils.helpers import format_timestamp
def render():
resource = st.session_state.selected_resource
resource_type = st.session_state.selected_resource_type
if not resource:
st.warning("No resource selected.")
return
print(f"Resource type: {resource_type}")
if resource_type == 'universe':
render_detail_view_universe(resource)
elif resource_type == 'project':
render_detail_view_project(resource)
elif resource_type == 'vdc':
render_detail_view_vdc(resource)
elif resource_type == 'region':
render_detail_view_region(resource)
elif resource_type == 'network':
render_detail_view_network(resource)
elif resource_type == 'container':
render_detail_view_container(resource)
def render_detail_view_container(container):
"""
Renders the details of a specific container workload.
"""
container = st.session_state.client.get_container(container['id'])
if not container:
st.error("Container workload not found.")
return
st.title(f"Container Workload: {container['container_id']}")
st.header("Container Workload Details")
col1, col2 = st.columns(2)
with col1:
st.markdown(f"**ID:** `{container['id']}`")
st.markdown(f"**Created:** {format_timestamp(container.get('created_at', 'Unknown'))}")
st.markdown(f"**VDC ID:** {container['vdc_id']}")
st.markdown(f"**Workload Host ID:** {container.get('container_host_id', 'N/A')}")
with col2:
if container.get('updated_at'):
st.markdown(f"**Last Updated:** {format_timestamp(container['updated_at'])}")
st.markdown(f"**Status:** {container['status']}")
st.markdown(f"**Launch Parameters:** {container.get('launch_params', 'N/A')}")
# Edit Container Workload Form
with st.expander("Edit Container Workload"):
with st.form("edit_container"):
new_status = st.selectbox("Status", ["running", "stopped", "pending","failed-deleted","pending-deleted","pending-allocation","failed-allocation","pending-allocated"], index=["running", "stopped", "pending","failed-deleted","pending-deleted","pending-allocation","failed-allocation","pending-allocated"].index(container['status']))
new_launch_params = st.text_input("Launch Parameters", value=container.get('launch_params', ''))
submit = st.form_submit_button("Update Container Workload")
if submit:
result = st.session_state.client.edit_container(container['id'], {
"status": new_status,
"launch_params": new_launch_params
})
if result:
st.success("Container workload updated successfully!")
st.session_state.selected_resource = container
st.session_state.view_type = 'detail'
st.session_state.selected_resource_type = 'container'
st.rerun()
# Delete Container Workload Button
if st.button("Delete Container Workload"):
result = st.session_state.client.delete_container(container['id'])
if result:
st.success("Container workload deleted successfully!")
st.session_state.selected_resource = None
st.session_state.view_type = 'list'
st.session_state.selected_resource_type = 'container'
st.rerun()
def render_detail_view_universe(universe):
st.title(f"Universe: {universe['name']}")
st.header("Universe Details")
col1, col2 = st.columns(2)
with col1:
st.markdown(f"**ID:** `{universe['id']}`")
st.markdown(f"**Created:** {format_timestamp(universe['created_at'])}")
with col2:
if universe.get('updated_at'):
st.markdown(f"**Last Updated:** {format_timestamp(universe['updated_at'])}")
if universe.get('description'):
st.markdown(f"**Description:** {universe['description']}")
def render_detail_view_project(project):
st.title(f"Project: {project['name']}")
st.header("Project Details")
col1, col2 = st.columns(2)
with col1:
st.markdown(f"**ID:** `{project['id']}`")
st.markdown(f"**Created:** {format_timestamp(project['created_at'])}")
with col2:
st.markdown(f"**Universe ID:** `{project['universe_id']}`")
if project.get('updated_at'):
st.markdown(f"**Last Updated:** {format_timestamp(project['updated_at'])}")
def render_detail_view_vdc(vdc):
st.title(f"Virtual Data Center: {vdc['name']}")
st.header("VDC Details")
col1, col2 = st.columns(2)
with col1:
st.markdown(f"**ID:** `{vdc['id']}`")
st.markdown(f"**Created:** {format_timestamp(vdc['created_at'])}")
with col2:
st.markdown(f"**Project ID:** `{vdc['project_id']}`")
if vdc.get('updated_at'):
st.markdown(f"**Last Updated:** {format_timestamp(vdc['updated_at'])}")
def render_detail_view_network(network):
st.title(f"Network: {network['name']}")
st.header("Network Details")
col1, col2 = st.columns(2)
with col1:
st.markdown(f"**ID:** `{network['id']}`")
st.markdown(f"**Created:** {network.get('created_at', 'Unknown')}")
st.markdown(f"**IPv4 CIDR:** {network.get('ipv4_cidr', 'N/A')}")
st.markdown(f"**IPv4 Gateway:** {network.get('ipv4_gateway', 'N/A')}")
st.markdown(f"**Encapsulation Type:** {network.get('encapsulation', 'N/A')}")
st.markdown(f"**VNI:** {network.get('vni', 'N/A')}")
with col2:
if network.get('updated_at'):
st.markdown(f"**Last Updated:** {network['updated_at']}")
if network.get('description'):
st.markdown(f"**Description:** {network['description']}")
st.markdown(f"**IPv6 CIDR:** {network.get('ipv6_cidr', 'N/A')}")
st.markdown(f"**IPv6 Gateway:** {network.get('ipv6_gateway', 'N/A')}")
st.header("Network Ports")
network_ports = st.session_state.client.get_network_ports_by_network(network['id'])
if network_ports:
# Fetch workloads to map workload_id to workload name
# TODO Enable to fetching of workloads once htey exist
# workloads = st.session_state.client.get_workloads()
# workload_map = {workload['id']: workload['name'] for workload in workloads}
# Add workload names to each network port entry
for port in network_ports:
port['workload_name'] = "Unk" #workload_map.get(port['workload_id'], 'Unknown Workload')
# Create a DataFrame with the enriched data
df = pd.DataFrame(network_ports)
df = df[[
'id', 'workload_id', 'workload_name', 'ip_address', 'mac_address',
'port_type', 'state'
]]
st.dataframe(df, use_container_width=True)
else:
st.info("No network ports found for this network.")
def render_detail_view_region(region):
st.title(f"Region: {region['name']}")
st.header("Region Details")
col1, col2 = st.columns(2)
with col1:
st.markdown("**Region ID**")
st.code(f"{region['id']}")
st.markdown("**Region Enrollment Key**(Confidental)")
st.code(f"{region['enrollment_key']}")
with col2:
st.markdown(f"**Last Updated:** {region['updated_at']}")
st.markdown(f"**Created:** {region.get('created_at', 'Unknown')}")
if region.get('description'):
st.markdown(f"**Description:** {region['description']}")
st.header("Region Access Entries")
region_access = st.session_state.client.get_region_access(region['id'])
if region_access:
# Fetch all projects and regions
projects = st.session_state.client.get_projects()
regions = st.session_state.client.get_regions()
# Create dictionaries to map IDs to names
project_map = {project['id']: project['name'] for project in projects}
region_map = {region['id']: region['name'] for region in regions}
# Add project and region names to each entry
for entry in region_access:
entry['project_name'] = project_map.get(entry['project_id'], 'Unknown Project')
entry['region_name'] = region_map.get(entry['region_id'], 'Unknown Region')
# Create a DataFrame with the enriched data
df = pd.DataFrame(region_access)
df = df[['project_id', 'project_name', 'region_id', 'region_name']] # Include names in the table
st.dataframe(df, use_container_width=True)
else:
st.info("No access entries found for this region.")
+13 -13
View File
@@ -2,16 +2,16 @@ import streamlit as st
import pandas as pd
from streamlit_server.utils.helpers import format_timestamp
def render():
st.header("Worker & Host Management")
# Fetch Worker Agents & Workload Hosts
workload_hosts = st.session_state.client.get_workload_hosts()
# Display Workload Hosts
st.subheader("Workload Hosts")
if workload_hosts:
workload_hosts_df = pd.DataFrame(workload_hosts)
st.dataframe(workload_hosts_df)
else:
st.info("No workload hosts found.")
# def render():
st.header("Worker & Host Management")
# Fetch Worker Agents & Workload Hosts
workload_hosts = st.session_state.client.get_workload_hosts()
# Display Workload Hosts
st.subheader("Workload Hosts")
if workload_hosts:
workload_hosts_df = pd.DataFrame(workload_hosts)
st.dataframe(workload_hosts_df)
else:
st.info("No workload hosts found.")
+42 -88
View File
@@ -1,32 +1,34 @@
import streamlit as st
import pandas as pd
from streamlit_server.utils.helpers import format_timestamp
def render_image_list():
"""
Renders a list of all images.
"""
def render_list():
st.header("Image Management")
# Create Image Form
with st.expander("Create New Image"):
with st.form("create_image"):
location = st.text_input("Location (URL or Path)")
size = st.number_input("Size (in MB)", min_value=0.0)
location_type = st.selectbox("Location Type", ["url", "local"])
os_family = st.text_input("OS Family")
os_version = st.text_input("OS Version")
name = st.text_input("Image Name")
location = st.text_input("Image Location (e.g., /images/image.img)")
location_type = st.selectbox("Location Type", ["Local", "Remote"])
size = st.number_input("Size (GB)", min_value=0.1, step=0.1)
os_family = st.text_input("OS Family (e.g., Linux)")
os_version = st.text_input("OS Version (e.g., 20.04)")
checksum = st.text_input("Checksum (optional)")
submit = st.form_submit_button("Create Image")
if submit and location and size:
result = st.session_state.client.create_image({
"location": location,
"size": size,
"location_type": location_type,
"os_family": os_family,
"os_version": os_version
})
if submit and name and location:
result = st.session_state.client.create_image(
name=name,
location=location,
location_type=location_type,
size=size,
os_family=os_family,
os_version=os_version,
checksum=checksum
)
if result:
st.success(f"Image created successfully!")
st.success(f"Image '{name}' created successfully!")
# List Images
st.subheader("Existing Images")
@@ -37,93 +39,45 @@ def render_image_list():
with st.container():
col1, col2, col3 = st.columns([3, 1, 1])
with col1:
st.markdown(f"### {image['location']}")
st.text(f"Size: {image['size']} MB")
st.text(f"OS: {image.get('os_family', 'N/A')} {image.get('os_version', 'N/A')}")
st.markdown(f"### {image['name']}")
st.text(f"Location: {image['location']}")
st.text(f"Size: {image['size']} GB")
with col2:
st.text(f"ID: {image['id'][:8]}...")
with col3:
if st.button("View Details", key=f"view_{image['id']}"):
st.session_state.selected_resource = image
st.session_state.view_type = 'detail'
st.session_state.selected_resource_type='image'
st.session_state.selected_resource_type = 'image'
st.rerun() # Force Streamlit to rerun the script
else:
st.info("No images found.")
def render_image_detail(image_id):
"""
Renders the details of a specific image.
"""
image = st.session_state.client.get_image(image_id)
if not image:
st.error("Image not found.")
return
def render_detail():
image = st.session_state.client.get_image(st.session_state.selected_resource['id'])
st.title(f"Image: {image['location']}")
st.title(f"Image: {image['name']}")
if st.button("Back to list view"):
st.session_state.view_type = 'list'
st.rerun()
st.header("Image Details")
col1, col2 = st.columns(2)
with col1:
st.markdown(f"**ID:** `{image['id']}`")
st.markdown(f"**Created:** {format_timestamp(image.get('created_at', 'Unknown'))}")
st.markdown(f"**Size:** {image['size']} MB")
st.markdown(f"**Location Type:** {image.get('location_type', 'N/A')}")
st.markdown(f"**Created:** {format_timestamp(image['created_at'])}")
st.markdown(f"**Location:** `{image['location']}`")
st.markdown(f"**Location Type:** `{image['location_type']}`")
with col2:
st.markdown(f"**Size:** `{image['size']} GB`")
st.markdown(f"**OS Family:** `{image['os_family']}`")
st.markdown(f"**OS Version:** `{image['os_version']}`")
if image.get('checksum'):
st.markdown(f"**Checksum:** `{image['checksum']}`")
if image.get('updated_at'):
st.markdown(f"**Last Updated:** {format_timestamp(image['updated_at'])}")
st.markdown(f"**OS Family:** {image.get('os_family', 'N/A')}")
st.markdown(f"**OS Version:** {image.get('os_version', 'N/A')}")
# Edit Image Form
with st.expander("Edit Image"):
with st.form("edit_image"):
new_location = st.text_input("Location (URL or Path)", value=image['location'])
new_size = st.number_input("Size (in MB)", min_value=0.0, value=image['size'])
new_location_type = st.selectbox("Location Type", ["url", "local"], index=0 if image.get('location_type') == "url" else 1)
new_os_family = st.text_input("OS Family", value=image.get('os_family', ''))
new_os_version = st.text_input("OS Version", value=image.get('os_version', ''))
submit = st.form_submit_button("Update Image")
if submit:
result = st.session_state.client.edit_image(image['id'], {
"location": new_location,
"size": new_size,
"location_type": new_location_type,
"os_family": new_os_family,
"os_version": new_os_version
})
if result:
st.success("Image updated successfully!")
st.session_state.selected_resource = image
st.session_state.view_type = 'detail'
st.session_state.selected_resource_type='image'
# Delete Image Button
if st.button("Delete Image"):
result = st.session_state.client.delete_image(image['id'])
if result:
st.success("Image deleted successfully!")
st.session_state.view_type = 'list'
st.session_state.selected_resource_type='image'
def render():
"""
Main render function for the Images page.
"""
# Read query parameters for routing
if not st.session_state.get('api_key'):
st.warning("Please enter your API key in the sidebar to continue.")
return
if st.session_state.view_type == 'list':
print("Viewing list")
render_image_list()
elif st.session_state.view_type == 'detail' and st.session_state.selected_resource:
print("Viewing detail")
render_image_detail(st.session_state.selected_resource["id"])
else:
st.error("Invalid view type or resource ID.")
if st.session_state.view_type == 'detail' and st.session_state.selected_resource_type == 'image':
render_detail()
else:
render_list()
+62 -2
View File
@@ -2,14 +2,14 @@ import streamlit as st
import pandas as pd
from streamlit_server.utils.helpers import format_timestamp
def render():
def render_list():
st.header("Network Management")
# Create Network Form
with st.expander("Create New Network"):
with st.form("create_network"):
name = st.text_input("Network Name")
vdcs = st.session_state.client.get_vdcs()
vdcs = st.session_state.client.get_virtual_data_centers()
vdc_choices = {v['name']: v['id'] for v in vdcs} if vdcs else {}
selected_vdc = st.selectbox("Select VDC", list(vdc_choices.keys()))
submit = st.form_submit_button("Create Network")
@@ -38,3 +38,63 @@ def render():
st.session_state.view_type = 'detail'
st.session_state.selected_resource_type='network'
st.rerun() # Force Streamlit to rerun the script
def render_detail():
network = st.session_state.client.get_network(st.session_state.selected_resource['id'])
if not network:
st.error("Network not found.")
st.session_state.selected_resource = None
st.session_state.view_type = 'list'
st.session_state.selected_resource_type = None
return
st.title(f"Network: {network['name']}")
if st.button("Back to list view"):
st.session_state.view_type = 'list'
st.rerun()
st.header("Network Details")
col1, col2 = st.columns(2)
with col1:
st.markdown(f"**ID:** `{network['id']}`")
st.markdown(f"**VDC ID:** `{network['vdc_id']}`")
st.markdown(f"**Created:** {network.get('created_at', 'Unknown')}")
st.markdown(f"**IPv4 CIDR:** {network.get('ipv4_cidr', 'N/A')}")
st.markdown(f"**IPv4 Gateway:** {network.get('ipv4_gateway', 'N/A')}")
with col2:
if network.get('updated_at'):
st.markdown(f"**Last Updated:** {network['updated_at']}")
if network.get('description'):
st.markdown(f"**Description:** {network['description']}")
st.markdown(f"**IPv6 CIDR:** {network.get('ipv6_cidr', 'N/A')}")
st.markdown(f"**IPv6 Gateway:** {network.get('ipv6_gateway', 'N/A')}")
st.header("Network Ports")
network_ports = st.session_state.client.get_network_ports_by_network(network['id'])
if network_ports:
# Fetch workloads to map workload_id to workload name
# TODO Enable to fetching of workloads once htey exist
# workloads = st.session_state.client.get_workloads()
# workload_map = {workload['id']: workload['name'] for workload in workloads}
# Add workload names to each network port entry
for port in network_ports:
port['workload_name'] = "Unk" #workload_map.get(port['workload_id'], 'Unknown Workload')
# Create a DataFrame with the enriched data
df = pd.DataFrame(network_ports)
df = df[[
'id', 'workload_id', 'workload_name', 'ip_address', 'mac_address',
'port_type'
]]
st.dataframe(df, use_container_width=True)
else:
st.info("No network ports found for this network.")
if st.session_state.view_type == 'detail' and st.session_state.selected_resource_type=='network':
render_detail()
else:
render_list()
+25 -1
View File
@@ -2,7 +2,7 @@ import streamlit as st
import pandas as pd
from streamlit_server.utils.helpers import format_timestamp
def render():
def render_list():
st.header("Project Management")
# Create Project Form
@@ -39,3 +39,27 @@ def render():
st.session_state.selected_resource_type='project'
st.rerun() # Force Streamlit to rerun the script
def render_detail():
project = st.session_state.client.get_project(st.session_state.selected_resource['id'])
st.title(f"Project: {project['name']}")
if st.button("Back to list view"):
st.session_state.view_type = 'list'
st.rerun()
st.header("Project Details")
col1, col2 = st.columns(2)
with col1:
st.markdown(f"**ID:** `{project['id']}`")
st.markdown(f"**Created:** {format_timestamp(project['created_at'])}")
with col2:
st.markdown(f"**Universe ID:** `{project['universe_id']}`")
if project.get('updated_at'):
st.markdown(f"**Last Updated:** {format_timestamp(project['updated_at'])}")
if st.session_state.view_type == 'detail' and st.session_state.selected_resource_type=='project':
render_detail()
else:
render_list()
+51 -1
View File
@@ -2,7 +2,7 @@ import streamlit as st
import pandas as pd
from streamlit_server.utils.helpers import format_timestamp
def render():
def render_list():
st.header("Region Management")
# Create Region Form
@@ -39,3 +39,53 @@ def render():
st.session_state.selected_resource_type='region'
st.rerun() # Force Streamlit to rerun the script
def render_detail():
region = st.session_state.client.get_region(st.session_state.selected_resource['id'])
st.title(f"Region: {region['name']}")
if st.button("Back to list view"):
st.session_state.view_type = 'list'
st.rerun()
st.header("Region Details")
col1, col2 = st.columns(2)
with col1:
st.code(f"{region['id']}")
st.markdown(f"**Created:** {region.get('created_at', 'Unknown')}")
with col2:
if region.get('updated_at'):
st.markdown(f"**Last Updated:** {region['updated_at']}")
if region.get('description'):
st.markdown(f"**Description:** {region['description']}")
st.header("Region Access Entries")
region_access = st.session_state.client.get_region_access(region['id'])
if region_access:
# Fetch all projects and regions
projects = st.session_state.client.get_projects()
regions = st.session_state.client.get_regions()
# Create dictionaries to map IDs to names
project_map = {project['id']: project['name'] for project in projects}
region_map = {region['id']: region['name'] for region in regions}
# Add project and region names to each entry
for entry in region_access:
entry['project_name'] = project_map.get(entry['project_id'], 'Unknown Project')
entry['region_name'] = region_map.get(entry['region_id'], 'Unknown Region')
# Create a DataFrame with the enriched data
df = pd.DataFrame(region_access)
df = df[['project_id', 'project_name', 'region_id', 'region_name']] # Include names in the table
st.dataframe(df, use_container_width=True)
else:
st.info("No access entries found for this region.")
if st.session_state.view_type == 'detail' and st.session_state.selected_resource_type=='region':
render_detail()
else:
render_list()
+61 -15
View File
@@ -7,31 +7,77 @@ def render():
if 'api_key' not in st.session_state or st.session_state.api_key == "":
st.session_state.api_key = "xxx"
print("Providing xxx as api key")
# Display the API key input with the default value
api_key = st.sidebar.text_input("API Key", type="password", value=st.session_state.get('api_key'))
if api_key:
st.session_state.api_key = api_key
# Define views with appropriate icons
views = {
"Universes": "🌌",
"Projects": "📂",
"Virtual Data Centers": "🏢",
"Networks": "🔌",
"Regions": "🌎",
"Hosts": "💻",
"Images": "🖼️",
"Containers": "📦",
"Websocket": "🔄",
"Virtual Machines": "⚙️"
}
# Style the sidebar navigation
st.sidebar.markdown("""
<style>
/* Reduce spacing between items */
div.row-widget.stSelectbox > div {
margin-bottom: 0;
}
/* Style for the navbar */
.streamlit-expanderHeader {
font-size: 1em;
padding: 0.5rem;
}
/* Make the select box more compact */
.stSelectbox div:first-child {
padding-bottom: 0;
}
</style>
""", unsafe_allow_html=True)
st.sidebar.header("Navigation")
views = ["Universes", "Projects", "Virtual Data Centers", "Networks", "Regions", "Hosts", "Images", "Containers", "Websocket"]
# Initialize current view in session state if not present
if 'current_view' not in st.session_state:
st.session_state.current_view = list(views.keys())[0]
# Format the options with icons
format_func = lambda x: f"{views[x]} {x}"
# Use selectbox for navigation
if st.session_state.view_type == 'list':
# if st.sidebar.radio("Select View", views):
# print(f"Radio buton pressed")
# st.session_state.current_view = "D"
for _viewType in views:
if st.sidebar.button(_viewType):
print(f"Processing sidebar button pres {_viewType}")
st.session_state.current_view=_viewType
st.session_state.selected_resource = None
st.session_state.view_type = 'list'
st.session_state.selected_resource_type = None
# st.rerun() # Force Streamlit to rerun the script
selected_view = st.sidebar.selectbox(
"Select Resource Type",
options=list(views.keys()),
format_func=format_func,
index=list(views.keys()).index(st.session_state.current_view),
label_visibility="collapsed"
)
# Handle navigation
if selected_view != st.session_state.current_view:
st.session_state.current_view = selected_view
st.session_state.selected_resource = None
st.session_state.view_type = 'list'
st.session_state.selected_resource_type = None
st.rerun()
if st.session_state.view_type == 'detail':
if st.sidebar.button("← Back to List View"):
st.session_state.view_type = 'list'
st.session_state.selected_resource = None
st.session_state.selected_resource_type = None
st.rerun() # Force Streamlit to rerun the script
st.rerun()
+31 -1
View File
@@ -2,7 +2,7 @@ import streamlit as st
import pandas as pd
from streamlit_server.utils.helpers import format_timestamp
def render():
def render_list():
st.header("Universe Management")
with st.expander("Create New Universe"):
@@ -37,3 +37,33 @@ def render():
st.rerun() # Force Streamlit to rerun the script
def render_detail():
universe = st.session_state.client.get_universe(st.session_state.selected_resource['id'])
if not universe:
st.error("Universe not found.")
st.session_state.selected_resource = None
st.session_state.view_type = 'list'
st.session_state.selected_resource_type = None
return
st.title(f"Universe: {universe['name']}")
if st.button("Back to list view"):
st.session_state.view_type = 'list'
st.rerun()
st.header("Universe Details")
col1, col2 = st.columns(2)
with col1:
st.markdown(f"**ID:** `{universe['id']}`")
st.markdown(f"**Created:** {format_timestamp(universe['created_at'])}")
with col2:
if universe.get('updated_at'):
st.markdown(f"**Last Updated:** {format_timestamp(universe['updated_at'])}")
if universe.get('description'):
st.markdown(f"**Description:** {universe['description']}")
if st.session_state.view_type == 'detail' and st.session_state.selected_resource_type=='universe':
render_detail()
else:
render_list()
@@ -2,13 +2,13 @@ import streamlit as st
import pandas as pd
from streamlit_server.utils.helpers import format_timestamp
def render():
st.header("Virtual Data Center (VDC) Management")
def render_list():
st.header("Virtual Data Center Management")
# Create VDC Form
with st.expander("Create New VDC"):
with st.expander("Create New Virtual Data Center"):
with st.form("create_vdc"):
name = st.text_input("VDC Name")
name = st.text_input("Virtual Data Center Name")
projects = st.session_state.client.get_projects()
project_choices = {p['name']: p['id'] for p in projects} if projects else {}
selected_project = st.selectbox("Select Project", list(project_choices.keys()))
@@ -17,11 +17,11 @@ def render():
if submit and name and selected_project:
result = st.session_state.client.create_vdc(name, project_choices[selected_project])
if result:
st.success(f"VDC '{name}' created successfully!")
st.success(f"Virtual Data Center '{name}' created successfully!")
# List VDCs
st.subheader("Existing VDCs")
vdcs = st.session_state.client.get_vdcs()
st.subheader("Existing Virtual Data Center")
vdcs = st.session_state.client.get_virtual_data_centers()
# projects = st.session_state.client.get_projects()
# regions = st.session_state.client.get_regions()
@@ -41,7 +41,31 @@ def render():
if st.button("View Details", key=f"view_{vdc['id']}"):
st.session_state.selected_resource = vdc
st.session_state.view_type = 'detail'
st.session_state.selected_resource_type='vdc'
st.session_state.selected_resource_type='virtual_data_center'
st.rerun() # Force Streamlit to rerun the script
def render_detail():
vdc = st.session_state.client.get_virtual_data_center(st.session_state.selected_resource['id'])
st.title(f"Virtual Data Center: {vdc['name']}")
if st.button("Back to list view"):
st.session_state.view_type = 'list'
st.rerun()
st.header("Virtual Data Center Details")
col1, col2 = st.columns(2)
with col1:
st.markdown(f"**ID:** `{vdc['id']}`")
st.markdown(f"**Created:** {format_timestamp(vdc['created_at'])}")
with col2:
st.markdown(f"**Project ID:** `{vdc['project_id']}`")
if vdc.get('updated_at'):
st.markdown(f"**Last Updated:** {format_timestamp(vdc['updated_at'])}")
if st.session_state.view_type == 'detail' and st.session_state.selected_resource_type=='virtual_data_center':
render_detail()
else:
render_list()
+288
View File
@@ -0,0 +1,288 @@
import json
import streamlit as st
from streamlit_server.utils.helpers import format_timestamp
def render_list():
"""
Renders a list of all VM workloads.
"""
st.header("VM Workload Management")
# Initialize session state variables for delete confirmation
if 'delete_confirmation_shown' not in st.session_state:
st.session_state.delete_confirmation_shown = False
if 'delete_confirmed' not in st.session_state:
st.session_state.delete_confirmed = False
# Fetch all VDCs for the dropdown
vdcs = st.session_state.client.get_virtual_data_centers()
vdc_options = {vdc['name']: vdc['id'] for vdc in vdcs} if vdcs else {}
# Add a dropdown to select VDC
selected_vdc_name = st.selectbox("Filter by Virtual Data Center", list(vdc_options.keys()))
# Fetch all Workload Hosts for the dropdown
workload_hosts = st.session_state.client.get_workload_hosts()
workload_host_options = {workload_host['hostname']: workload_host['id'] for workload_host in workload_hosts} if workload_hosts else {}
# Create VM Workload Form
with st.expander("Create New VM Workload"):
with st.form("create_virtual_machine"):
# Dropdown for VDC selection
selected_vdc_name_create = st.selectbox("VDC", list(vdc_options.keys()))
vm_name = st.text_input("VM Name", value="my-vm")
memory = st.number_input("Memory (MB)", min_value=512, value=2048)
vcpu = st.number_input("vCPU", min_value=1, value=2)
# Networks Dropdown
networks = st.session_state.client.get_networks()
network_options = {net['id']: net['name'] for net in networks}
selected_network_ids = st.multiselect("Networks", options=list(network_options.keys()), format_func=lambda x: network_options[x])
# Volumes Section
st.subheader("Volumes")
if 'volumes' not in st.session_state:
st.session_state.volumes = []
for i, volume in enumerate(st.session_state.volumes):
col1, col2, col3, col4 = st.columns([3, 2, 2, 2])
with col1:
volume_name = st.text_input(f"Volume Name {i+1}", value=volume['name'], key=f"volume_name_{i}")
with col2:
volume_size = st.number_input(f"Size (GB) {i+1}", min_value=1, value=volume['size_gb'], key=f"volume_size_{i}")
with col3:
volume_type = st.selectbox(f"Type {i+1}", options=["local", "ceph"], index=0 if volume.get('type', 'local') == 'local' else 1, key=f"volume_type_{i}")
with col4:
# Get image options
image_list = st.session_state.client.get_images()
# Create a mapping of image names to IDs
image_name_to_id = {img['name']: img['id'] for img in image_list}
image_name_to_id["blank"] = "" # Add a blank option
# Default selected image name (fallback to 'blank' if not found)
default_image_name = volume.get('image_name', 'blank')
# Dropdown to display image names
selected_image_name = st.selectbox(
f"Image {i+1}",
options=list(image_name_to_id.keys()),
index=list(image_name_to_id.keys()).index(default_image_name) if default_image_name in image_name_to_id else 0,
key=f"volume_image_{i}"
)
# Get the corresponding image ID for the selected image name
selected_image_id = image_name_to_id[selected_image_name]
# Store updated volume info
if selected_image_name == "blank":
st.session_state.volumes[i] = {"name": volume_name, "size_gb": volume_size, "type": volume_type}
else:
st.session_state.volumes[i] = {"name": volume_name, "size_gb": volume_size, "type": volume_type, "image_id": selected_image_id}
submit = st.form_submit_button("Create VM Workload")
# **Move the buttons OUTSIDE of the form**
col1, col2 = st.columns([1, 1])
with col1:
if st.button("Add Volume"):
st.session_state.volumes.append({"name": "", "size_gb": 10, "type": "", "image":""})
st.rerun()
with col2:
for i in range(len(st.session_state.volumes)):
if st.button(f"Remove Volume {i+1}", key=f"remove_volume_{i}"):
st.session_state.volumes.pop(i)
st.rerun()
if submit and selected_vdc_name_create and vm_name:
# Use the selected VDC's ID
vdc_id = vdc_options[selected_vdc_name_create]
result = st.session_state.client.create_virtual_machine({
"virtual_data_center": vdc_id,
"virtual-machines": [{
"name": vm_name,
"memory": memory,
"vcpu": vcpu,
"volumes": st.session_state.volumes,
"networks": [{"id": net_id} for net_id in selected_network_ids]
}]
})
if result:
st.success("VM workload created successfully!")
st.session_state.volumes = [] # Reset volumes after creation
st.rerun()
# List Container Workloads
st.subheader("Existing Container Workloads")
VirtualMachines = st.session_state.client.get_virtual_machines()
print(VirtualMachines)
if VirtualMachines:
# Filter VirtualMachines based on the selected VDC
if selected_vdc_name:
selected_vdc_id = vdc_options[selected_vdc_name]
filtered_VirtualMachines = [VirtualMachine for VirtualMachine in VirtualMachines if VirtualMachine['vdc_id'] == selected_vdc_id]
else:
filtered_VirtualMachines = VirtualMachines
# Delete All functionality
if not st.session_state.delete_confirmation_shown:
if st.button("Delete All VMs", key="delete_all_vms", type="primary", help="This will delete all visible virtual machines"):
st.session_state.delete_confirmation_shown = True
st.rerun()
# Show confirmation if delete was clicked
if st.session_state.delete_confirmation_shown and not st.session_state.delete_confirmed:
st.warning("Are you sure you want to delete all virtual machines? This action cannot be undone.")
confirm_col1, confirm_col2 = st.columns([1, 1])
with confirm_col1:
if st.button("Yes, Delete All", key="confirm_delete_all"):
st.session_state.delete_confirmed = True
st.rerun()
with confirm_col2:
if st.button("Cancel", key="cancel_delete_all"):
st.session_state.delete_confirmation_shown = False
st.rerun()
# Perform deletion if confirmed
if st.session_state.delete_confirmed:
deletion_count = 0
for vm in filtered_VirtualMachines:
# Call the delete API for each VM
result = st.session_state.client.delete_virtual_machine(vm['id'])
if result:
deletion_count += 1
st.success(f"Successfully deleted {deletion_count} virtual machines.")
# Reset the confirmation flags
st.session_state.delete_confirmation_shown = False
st.session_state.delete_confirmed = False
filtered_VirtualMachines=[]
# Display the VMs
for VirtualMachine in filtered_VirtualMachines:
with st.container():
col1, col2, col3 = st.columns([3, 1, 1])
with col1:
# Safely handle empty or None launch_params
launch_params = VirtualMachine.get('launch_params')
if launch_params:
try:
VirtualMachine_name = json.loads(launch_params).get('docker_image')
except json.JSONDecodeError:
print("LP not valid json")
VirtualMachine_name = None
else:
print("lp empty")
VirtualMachine_name = None
st.markdown(f"### {VirtualMachine['name']}")
# Create a grey box for the status
status = VirtualMachine['status']
if status == "error":
status_color = "red"
elif status == "running":
status_color = "green"
elif status == "pending-allocated":
status_color = "orange"
else:
status_color = "blue"
st.markdown(
f"""
<div style="background-color: #f0f0f0; padding: 10px; border-radius: 5px;">
<strong>Status:</strong> <span style="color: {status_color}; font-weight: bold;">{status}</span>
</div>
""",
unsafe_allow_html=True
)
st.text(f"VDC ID: {VirtualMachine['vdc_id']}")
st.text(f"Image: {VirtualMachine_name}")
with col2:
st.text(f"ID: {VirtualMachine['id']}")
with col3:
if st.button("View Details", key=f"view_{VirtualMachine['id']}"):
print("Button is pressed")
st.session_state.selected_resource = VirtualMachine
st.session_state.view_type = 'detail'
st.session_state.selected_resource_type = 'VirtualMachine'
st.rerun()
else:
st.info("No VirtualMachine workloads found.")
def render_detail():
"""
Renders the details of a specific VM workload.
"""
VirtualMachine = st.session_state.client.get_virtual_machine(st.session_state.selected_resource['id'])
if not VirtualMachine:
st.error("VM workload not found.")
return
st.title(f"VM Workload: {VirtualMachine['name']}")
if st.button("Back to list view"):
st.session_state.view_type = 'list'
st.rerun()
st.header("VM Workload Details")
col1, col2 = st.columns(2)
with col1:
st.markdown(f"**ID:** `{VirtualMachine['id']}`")
st.markdown(f"**Created:** {format_timestamp(VirtualMachine.get('created_at', 'Unknown'))}")
st.markdown(f"**VDC ID:** {VirtualMachine['vdc_id']}")
st.markdown(f"**Workload Host ID:** {VirtualMachine.get('workload_host_id', 'N/A')}")
with col2:
if VirtualMachine.get('updated_at'):
st.markdown(f"**Last Updated:** {format_timestamp(VirtualMachine['updated_at'])}")
st.markdown(f"**Status:** {VirtualMachine['status']}")
st.markdown(f"**Launch Parameters:** {VirtualMachine.get('launch_params', 'N/A')}")
# Edit VM Workload Form
with st.expander("Edit VM Workload"):
with st.form("edit_vm"):
new_status = st.selectbox("Status", ["running", "stopped", "pending", "failed-deleted", "pending-deleted", "pending-allocation", "failed-allocation", "pending-allocated"], index=["running", "stopped", "pending", "failed-deleted", "pending-deleted", "pending-allocation", "failed-allocation", "pending-allocated"].index(VirtualMachine['status']))
new_launch_params = st.text_input("Launch Parameters", value=VirtualMachine.get('launch_params', ''))
submit = st.form_submit_button("Update VM Workload")
if submit:
result = st.session_state.client.edit_virtual_machine(VirtualMachine['id'], {
"status": new_status,
"launch_params": new_launch_params
})
if result:
st.success("VM workload updated successfully!")
st.session_state.selected_resource = vm
st.session_state.view_type = 'detail'
st.session_state.selected_resource_type = 'VirtualMachine'
st.rerun()
# Delete VM Workload Button
if st.button("Delete VM Workload"):
result = st.session_state.client.delete_virtual_machine(VirtualMachine['id'])
if result:
st.success("VM workload deleted successfully!")
st.session_state.selected_resource = None
st.session_state.view_type = 'list'
st.session_state.selected_resource_type = 'VirtualMachine'
st.rerun()
if st.session_state.view_type == 'detail' and st.session_state.selected_resource_type=='VirtualMachine':
render_detail()
else:
render_list()
+2
View File
@@ -35,3 +35,5 @@ def render():
st.error("Message cannot be empty!")
else:
st.warning("No connected clients found.")
render()
+201
View File
@@ -0,0 +1,201 @@
import streamlit as st
from streamlit_server.utils.helpers import format_timestamp
import uuid
def render_list():
st.header("Workload Host Management")
# Create Workload Host Form
with st.expander("Create New Workload Host"):
with st.form("create_workload_host"):
name = st.text_input("Workload Host Name")
region_id = st.text_input("Region ID")
secret_key = st.text_input("Secret Key", value=str(uuid.uuid4()))
system_manufacturer = st.text_input("System Manufacturer")
system_model = st.text_input("System Model")
physical_identifier = st.text_input("Physical Identifier")
dcim_identifier = st.text_input("DCIM Identifier")
installed_date = st.date_input("Installed Date")
installed_status = st.text_input("Installed Status")
hostname = st.text_input("Hostname")
available_for_scheduling = st.checkbox("Available for Scheduling", value=True)
placement_priority = st.number_input("Placement Priority", value=100)
submit = st.form_submit_button("Create Workload Host")
if submit and name and region_id:
result = st.session_state.client.create_workload_host(
name=name,
region_id=region_id,
secret_key=secret_key,
system_manufacturer=system_manufacturer,
system_model=system_model,
physical_identifier=physical_identifier,
dcim_identifier=dcim_identifier,
installed_date=installed_date,
installed_status=installed_status,
hostname=hostname,
available_for_scheduling=available_for_scheduling,
placement_priority=placement_priority
)
if result:
st.success(f"Workload Host '{name}' created successfully!")
# List Workload Hosts
st.subheader("Existing Workload Hosts")
workload_hosts = st.session_state.client.get_workload_hosts()
if workload_hosts:
for host in workload_hosts:
with st.container():
col1, col2, col3 = st.columns([3, 1, 1])
with col1:
st.markdown(f"### {host['name']}")
st.text(f"Hostname: {host['hostname']}")
st.text(f"Region ID: {host['region_id']}")
with col2:
st.text(f"ID: {host['id'][:8]}...")
with col3:
if st.button("View Details", key=f"view_{host['id']}"):
st.session_state.selected_resource = host
st.session_state.view_type = 'detail'
st.session_state.selected_resource_type = 'workload_host'
st.rerun() # Force Streamlit to rerun the script
def render_detail():
host_id = st.session_state.selected_resource['id']
workload_host = st.session_state.client.get_workload_host(host_id)
st.title(f"Workload Host: {workload_host['name']}")
if st.button("Back to list view"):
st.session_state.view_type = 'list'
st.rerun()
st.header("Workload Host Details")
col1, col2 = st.columns(2)
with col1:
st.markdown(f"**ID:** `{workload_host['id']}`")
st.markdown(f"**Hostname:** `{workload_host['hostname']}`")
# Make Region ID clickable
if st.button(f"**Region ID:** `{workload_host['region_id']}`"):
st.session_state.selected_resource = {"id": workload_host['region_id']}
st.session_state.view_type = 'detail'
st.session_state.selected_resource_type = 'region'
st.switch_page("streamlit_server/views/regions.py")
st.markdown(f"**System Manufacturer:** `{workload_host['system_manufacturer']}`")
st.markdown(f"**System Model:** `{workload_host['system_model']}`")
with col2:
st.markdown(f"**Physical Identifier:** `{workload_host['physical_identifier']}`")
st.markdown(f"**DCIM Identifier:** `{workload_host['dcim_identifier']}`")
st.markdown(f"**Installed Status:** `{workload_host['installed_status']}`")
st.markdown(f"**Available for Scheduling:** `{workload_host['available_for_scheduling']}`")
st.markdown(f"**Placement Priority:** `{workload_host['placement_priority']}`")
# Display OVS Bridges
st.subheader("Attached OVS Bridges")
ovs_bridges = st.session_state.client.get_ovs_bridges_for_host(host_id)
if ovs_bridges:
for bridge in ovs_bridges:
st.markdown(f"- **{bridge['ovs_bridge_name']}**")
else:
st.info("No OVS bridges attached to this host.")
# Display Workloads
st.subheader("Assigned Workloads")
workloads = st.session_state.client.get_workloads_for_host(host_id)
if workloads:
containers = [w for w in workloads if w['workload_type'] == 'container']
vms = [w for w in workloads if w['workload_type'] == 'virtual_machine']
if containers:
st.markdown("### Containers")
# Table header
header_cols = st.columns([3, 2, 2, 2, 2])
header_cols[0].markdown("**Name**")
header_cols[1].markdown("**ID**")
header_cols[2].markdown("**Status**")
header_cols[3].markdown("**Created At**")
header_cols[4].markdown("**Actions**")
# Container rows
for container in containers:
cols = st.columns([3, 2, 2, 2, 2])
cols[0].markdown(container['name'])
cols[1].markdown(f"`{container['id'][:8]}...`")
cols[2].markdown(f"`{container['status']}`")
cols[3].markdown(format_timestamp(container['created_at']))
with cols[4]:
with st.popover("⚙️"):
if st.button("View Details", key=f"view_container_{container['id']}"):
st.session_state.selected_resource = container
st.session_state.view_type = 'detail'
st.session_state.selected_resource_type = 'container'
st.switch_page("streamlit_server/views/containers.py")
if st.button("Delete", key=f"delete_container_{container['id']}"):
st.session_state.client.delete_container(container['id'])
st.rerun()
if st.button("Migrate", key=f"migrate_container_{container['id']}"):
st.session_state.client.migrate_workload(container['id'], "NEW_HOST_ID")
st.rerun()
if vms:
st.markdown("### Virtual Machines")
# Table header
header_cols = st.columns([3, 2, 2, 2, 2])
header_cols[0].markdown("**Name**")
header_cols[1].markdown("**ID**")
header_cols[2].markdown("**Status**")
header_cols[3].markdown("**Created At**")
header_cols[4].markdown("**Actions**")
# VM rows
for vm in vms:
cols = st.columns([3, 2, 2, 2, 2])
cols[0].markdown(vm['name'])
cols[1].markdown(f"`{vm['id'][:8]}...`")
cols[2].markdown(f"`{vm['status']}`")
cols[3].markdown(format_timestamp(vm['created_at']))
with cols[4]:
with st.popover("⚙️"):
if st.button("View Details", key=f"view_vm_{vm['id']}"):
st.session_state.selected_resource = vm
st.session_state.view_type = 'detail'
st.session_state.selected_resource_type = 'vm'
st.switch_page("streamlit_server/views/virtual_machines.py")
if st.button("Delete", key=f"delete_vm_{vm['id']}"):
st.session_state.client.delete_virtual_machine(vm['id'])
st.rerun()
if st.button("Migrate", key=f"migrate_vm_{vm['id']}"):
st.session_state.client.migrate_workload(vm['id'], "NEW_HOST_ID")
st.rerun()
else:
st.info("No virtual machines assigned to this host.")
else:
st.info("No workloads assigned to this host.")
# Display Fixed Resources
st.subheader("Fixed Resources")
fixed_resources = st.session_state.client.get_fixed_resources_for_host(host_id)
if fixed_resources:
for resource in fixed_resources:
st.markdown(f"- **{resource['type']}** (Model: `{resource['model']}`, Manufacturer: `{resource['manufacturer']}`)")
else:
st.info("No fixed resources attached to this host.")
# Display Pooled Resources
st.subheader("Pooled Resources")
pooled_resources = st.session_state.client.get_pooled_resources_for_host(host_id)
if pooled_resources:
for resource in pooled_resources:
st.markdown(f"- **{resource['resource_type']}** (Total: `{resource['total_quantity']}`, In Use: `{resource['quantity_in_use']}`, Available: `{resource['quantity_available']}`)")
else:
st.info("No pooled resources attached to this host.")
if st.session_state.view_type == 'detail' and st.session_state.selected_resource_type == 'workload_host':
render_detail()
else:
render_list()