Merge branch 'worker-async' into enrollment-key
This commit is contained in:
@@ -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()
|
||||
@@ -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.")
|
||||
@@ -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.")
|
||||
@@ -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.")
|
||||
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -35,3 +35,5 @@ def render():
|
||||
st.error("Message cannot be empty!")
|
||||
else:
|
||||
st.warning("No connected clients found.")
|
||||
|
||||
render()
|
||||
@@ -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()
|
||||
Reference in New Issue
Block a user