diff --git a/app/controller/api/workload_vm_routes.py b/app/controller/api/workload_vm_routes.py index d32b603..565a07f 100644 --- a/app/controller/api/workload_vm_routes.py +++ b/app/controller/api/workload_vm_routes.py @@ -329,8 +329,8 @@ def add_VirtualMachine_workload(): # Handle the case where the image ID is not a valid UUID return {"error": f"Invalid image ID format: {volume['image']}"}, 400 - - _volume_path=volume['type'], + logger.debug(f"Vol type is {volume['type']}") + _volume_path=volume['type'] new_volume = Volume( name=volume['name'], diff --git a/app/models/models.py b/app/models/models.py index 5e284d6..d9e950a 100644 --- a/app/models/models.py +++ b/app/models/models.py @@ -147,7 +147,6 @@ class Image(BaseModel): class Volume(BaseModel): __tablename__ = "volumes" - volume_type = Column(Enum("Ceph", "Local", name="volume_type"), nullable=False) path = Column(String, nullable=True) type = Column(String, nullable=True) source = Column(String, nullable=True) diff --git a/streamlit_server/views/virtual_machines.py b/streamlit_server/views/virtual_machines.py index 142fd35..0f25848 100644 --- a/streamlit_server/views/virtual_machines.py +++ b/streamlit_server/views/virtual_machines.py @@ -229,63 +229,149 @@ def render_list(): - - 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 + host_id = st.session_state.selected_resource['id'] + workload_host = st.session_state.client.get_workload_host(host_id) - st.title(f"VM Workload: {VirtualMachine['name']}") + 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("VM Workload Details") + + st.header("Workload Host 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") + 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") - if submit: - result = st.session_state.client.edit_virtual_machine(VirtualMachine['id'], { - "status": new_status, - "launch_params": new_launch_params + 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: + # Split workloads into containers and VMs + containers = [w for w in workloads if w['type'] == 'container'] + vms = [w for w in workloads if w['type'] == 'vm'] + + # Display Containers in a table + if containers: + st.markdown("### Containers") + container_data = [] + for container in containers: + container_data.append({ + "Name": container['name'], + "ID": container['id'], + "Status": container['status'], + "Created At": format_timestamp(container['created_at']), + "Actions": f""" +
+ View Details + Delete + Migrate +
+ """ }) - if result: - st.success("VM workload updated successfully!") + st.table(container_data) + + # Handle actions for containers + for container in containers: + if st.session_state.get(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.session_state.get(f"delete_container_{container['id']}"): + st.session_state.client.delete_workload(container['id']) + st.success(f"Container '{container['name']}' deleted successfully!") + st.rerun() + if st.session_state.get(f"migrate_container_{container['id']}"): + st.session_state.client.migrate_workload(container['id'], new_host_id="NEW_HOST_ID") + st.success(f"Container '{container['name']}' migration initiated!") + st.rerun() + else: + st.info("No containers assigned to this host.") + + # Display Virtual Machines in a table + if vms: + st.markdown("### Virtual Machines") + vm_data = [] + for vm in vms: + vm_data.append({ + "Name": vm['name'], + "ID": vm['id'], + "Status": vm['status'], + "Created At": format_timestamp(vm['created_at']), + "Actions": f""" +
+ View Details + Delete + Migrate +
+ """ + }) + st.table(vm_data) + + # Handle actions for VMs + for vm in vms: + if st.session_state.get(f"view_vm_{vm['id']}"): st.session_state.selected_resource = vm st.session_state.view_type = 'detail' - st.session_state.selected_resource_type = 'VirtualMachine' + st.session_state.selected_resource_type = 'vm' + st.switch_page("streamlit_server/views/virtual_machines.py") + if st.session_state.get(f"delete_vm_{vm['id']}"): + st.session_state.client.delete_workload(vm['id']) + st.success(f"VM '{vm['name']}' deleted successfully!") 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.get(f"migrate_vm_{vm['id']}"): + st.session_state.client.migrate_workload(vm['id'], new_host_id="NEW_HOST_ID") + st.success(f"VM '{vm['name']}' migration initiated!") + 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.") diff --git a/streamlit_server/views/workload_hosts.py b/streamlit_server/views/workload_hosts.py index 0794129..3fa5260 100644 --- a/streamlit_server/views/workload_hosts.py +++ b/streamlit_server/views/workload_hosts.py @@ -91,8 +91,6 @@ def render_detail(): 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) @@ -105,9 +103,71 @@ def render_detail(): # Display Workloads st.subheader("Assigned Workloads") workloads = st.session_state.client.get_workloads_for_host(host_id) + if workloads: - for workload in workloads: - st.markdown(f"- **{workload['name']}** (ID: `{workload['id']}`)") + # Split workloads into containers and VMs + containers = [w for w in workloads if w['workload_type'] == 'container'] + vms = [w for w in workloads if w['workload_type'] == 'virtual_machine'] + + # Display Containers + if containers: + st.markdown("### Containers") + for container in containers: + with st.container(): + col1, col2, col3 = st.columns([3, 1, 1]) + with col1: + st.markdown(f"**Name:** {container['name']}") + st.markdown(f"**ID:** `{container['id']}`") + st.markdown(f"**Status:** `{container['status']}`") + st.markdown(f"**Created At:** `{format_timestamp(container['created_at'])}`") + with col2: + if st.button(f"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") + with col3: + with st.popover("Actions"): + if st.button("Delete", key=f"delete_container_{container['id']}"): + st.session_state.client.delete_workload(container['id']) + st.success(f"Container '{container['name']}' deleted successfully!") + st.rerun() + if st.button("Migrate", key=f"migrate_container_{container['id']}"): + st.session_state.client.migrate_workload(container['id'], new_host_id="NEW_HOST_ID") + st.success(f"Container '{container['name']}' migration initiated!") + st.rerun() + else: + st.info("No containers assigned to this host.") + + # Display Virtual Machines + if vms: + st.markdown("### Virtual Machines") + for vm in vms: + with st.container(): + col1, col2, col3 = st.columns([3, 1, 1]) + with col1: + st.markdown(f"**Name:** {vm['name']}") + st.markdown(f"**ID:** `{vm['id']}`") + st.markdown(f"**Status:** `{vm['status']}`") + st.markdown(f"**Created At:** `{format_timestamp(vm['created_at'])}`") + with col2: + if st.button(f"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") + with col3: + with st.popover("Actions"): + if st.button("Delete", key=f"delete_vm_{vm['id']}"): + st.session_state.client.delete_workload(vm['id']) + st.success(f"VM '{vm['name']}' deleted successfully!") + st.rerun() + if st.button("Migrate", key=f"migrate_vm_{vm['id']}"): + st.session_state.client.migrate_workload(vm['id'], new_host_id="NEW_HOST_ID") + st.success(f"VM '{vm['name']}' migration initiated!") + st.rerun() + else: + st.info("No virtual machines assigned to this host.") else: st.info("No workloads assigned to this host.") diff --git a/streamlit_server2.py b/streamlit_server2.py index 8b238ec..ea95a5c 100644 --- a/streamlit_server2.py +++ b/streamlit_server2.py @@ -1,33 +1,36 @@ import streamlit as st from streamlit_server.utils.session import init_session_state +# Define pages with icons pages = { "Your account": [ - st.Page("streamlit_server/views/dashboard.py", title="Dashboard"), - - st.Page("streamlit_server/views/hosts.py", title="Hosts"), - st.Page("streamlit_server/views/images.py", title="Images"), - st.Page("streamlit_server/views/networks.py", title="Networks"), - st.Page("streamlit_server/views/projects.py", title="Projects"), - st.Page("streamlit_server/views/universes.py", title="Universes"), - st.Page("streamlit_server/views/regions.py", title="Regions"), - st.Page("streamlit_server/views/virtual_data_centers.py", title="Virtual Data Centers"), - st.Page("streamlit_server/views/websocket.py", title="Active websockets"), - + st.Page("streamlit_server/views/dashboard.py", title="πŸ“Š Dashboard"), + st.Page("streamlit_server/views/hosts.py", title="πŸ–₯️ Hosts"), + st.Page("streamlit_server/views/images.py", title="πŸ–ΌοΈ Images"), + st.Page("streamlit_server/views/networks.py", title="🌐 Networks"), + st.Page("streamlit_server/views/projects.py", title="πŸ“‚ Projects"), + st.Page("streamlit_server/views/universes.py", title="🌌 Universes"), + st.Page("streamlit_server/views/regions.py", title="πŸ—ΊοΈ Regions"), + st.Page("streamlit_server/views/virtual_data_centers.py", title="🏒 Virtual Data Centers"), + st.Page("streamlit_server/views/websocket.py", title="πŸ”Œ Active websockets"), ], "Workloads": [ - st.Page("streamlit_server/views/workload_hosts.py", title="Workload Hosts"), - st.Page("streamlit_server/views/containers.py", title="Containers"), - - st.Page("streamlit_server/views/virtual_machines.py", title="Virtual Machines"), + st.Page("streamlit_server/views/workload_hosts.py", title="πŸ–₯️ Workload Hosts"), + st.Page("streamlit_server/views/containers.py", title="πŸ“¦ Containers"), + st.Page("streamlit_server/views/virtual_machines.py", title="πŸ’» Virtual Machines"), ], } -st.set_page_config( - page_title="IaaS Management Portal", - page_icon="🌐", - layout="wide" - ) +# Set page config +st.set_page_config( + page_title="IaaS Management Portal", + page_icon="🌐", + layout="wide" +) + +# Initialize session state init_session_state() + +# Run navigation pg = st.navigation(pages) pg.run() \ No newline at end of file