Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions app/controllers/vm_infra_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ def attached_volumes
render :json => {:error => e.message}, :status => 500
end

def storage_class_list
vm = find_record_with_rbac(VmOrTemplate, params[:id])
ems = vm.ext_management_system
storage_class = vm.storage_classes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NOTE storage_classes isn't something that we currently have. We would need to collect them in inventory refresh as part of the provider and persist them in the database for this to work. We do currently have a StorageProfile model which we could use to store these without having to create a new table/model.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @agrare. Just to clarify, storage_classes here is a function I added that fetches the list directly from the OpenShift/KubeVirt API at runtime, it is not a table/model. Would it make sense to use the existing StorageProfile model to persist storage classes list in OpenShift/KubeVirt as you suggested?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's not going to work for a couple of reasons, first this is generic VM code so we can't have provider specific methods in here, also since this is running from the UI role we can't run anything that would hit the live provider since that can only be guaranteed to be accessed via ems_operations role in the proper zone.

StorageProfiles sound like they could be a good match, what data do you need for them other than uid/name?

render :json => {
:resources => storage_class
}
end

private

def features
Expand Down
31 changes: 19 additions & 12 deletions app/javascript/components/vm-infra/add-volume.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const AddVolumeForm = ({ recordId, redirect }) => {
const [state, setState] = useState({
isLoading: true,
volumes: [],
storageClasses: [],
});

const [isSubmitDisabled, setSubmitDisabled] = useState(true);
Expand All @@ -19,21 +20,24 @@ const AddVolumeForm = ({ recordId, redirect }) => {
try {
setState(prev => ({ ...prev, isLoading: true, error: null }));

// Use the correct route for your Rails controller
const response = await fetch(`/vm_infra/${recordId}/persistentvolumeclaims`);
const data = await response.json();
// Fetch PVCs
const pvcResponse = await fetch(`/vm_infra/persistentvolumeclaims/${recordId}`);
const pvcData = await pvcResponse.json();
if (!pvcResponse.ok) throw new Error((pvcData.error && pvcData.error.message) || "Failed to fetch PVCs");

if (!response.ok) {
throw new Error((data.error && data.error.message) || 'Failed to fetch persistent volume claims');
}
// Fetch Storage Classes
const scResponse = await fetch(`/vm_infra/storage_class_list/${recordId}`);
const scData = await scResponse.json();
if (!scResponse.ok) throw new Error((scData.error && scData.error.message) || "Failed to fetch Storage Classes");

setState(prev => ({
...prev,
isLoading: false,
volumes: data.resources || [],
volumes: pvcData.resources || [],
storageClasses: scData.resources || [],
vmInfo: {
name: data.vm_name,
namespace: data.vm_namespace
name: pvcData.vm_name,
namespace: pvcData.vm_namespace
}
}));
} catch (error) {
Expand All @@ -42,15 +46,16 @@ const AddVolumeForm = ({ recordId, redirect }) => {
...prev,
isLoading: false,
error: error.message,
volumes: []
volumes: [],
storageClasses: [],
}));
}
};

fetchPersistentVolumeClaims();
}, [recordId]);

const schema = useMemo(() => createSchema(state.volumes), [state.volumes]);
const schema = useMemo(() => createSchema(state.volumes, state.storageClasses), [state.volumes, state.storageClasses]);

const onFormChange = (values) => {
if (values.volumeSourceType === "existing") {
Expand Down Expand Up @@ -87,6 +92,8 @@ const AddVolumeForm = ({ recordId, redirect }) => {
resource: {
volume_name: values.newVolumeName.trim(),
volume_size: values.newVolumeSize.trim(),
storage_class: values.storage_class,
access_mode: values.access_mode,
vm_id: recordId,
device: values.device_mountpoint ? values.device_mountpoint : ''
},
Expand All @@ -97,7 +104,7 @@ const AddVolumeForm = ({ recordId, redirect }) => {

request.then(() => {
const message = sprintf(
__('Volume processed successfully.')
__('Attechment of Volume has been successfully queued.')
);
miqRedirectBack(message, 'success', redirect);
}).catch((error) => {
Expand Down
35 changes: 34 additions & 1 deletion app/javascript/components/vm-infra/add-volume.schema.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { componentTypes } from "@@ddf";

const createSchema = (volumes = []) => ({
const createSchema = (volumes = [], storageClasses = []) => ({
fields: [
{
component: componentTypes.RADIO,
Expand Down Expand Up @@ -71,6 +71,39 @@ const createSchema = (volumes = []) => ({
},
],
},
{
component: componentTypes.SELECT,
id: "storage_class",
name: "storage_class",
label: __("Storage Class"),
isRequired: true,
condition: { when: "volumeSourceType", is: "new" },
includeEmpty: true,
options:
storageClasses.length > 0
? [
{ label: __("Select Storage Class"), value: "", isDisabled: true },
...storageClasses.map((sc) => ({
label: sc.name || sc,
value: sc.name || sc,
})),
]
: [{ label: __("No Storage Classes Available"), value: "", isDisabled: true }],
},
{
component: componentTypes.SELECT,
id: "access_mode",
name: "access_mode",
label: __("Access Mode"),
isRequired: true,
condition: { when: "volumeSourceType", is: "new" },
includeEmpty: true,
options: [
{ label: "Single Use (RWO)", value: "ReadWriteOnce" },
{ label: "Shared Access (RWX)", value: "ReadWriteMany" },
{ label: "Read Write Once Pod (RWOP)", value: "ReadWriteOncePod" },
],
},
],
});

Expand Down
4 changes: 2 additions & 2 deletions app/javascript/components/vm-infra/remove-volume.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const DetachVolumeForm = ({ recordId, redirect }) => {
try {
setState(prev => ({ ...prev, isLoading: true, error: null }));

const response = await fetch(`/vm_infra/${recordId}/attached_volumes`);
const response = await fetch(`/vm_infra/attached_volumes/${recordId}`);
const data = await response.json();

if (!response.ok) {
Expand Down Expand Up @@ -66,7 +66,7 @@ const DetachVolumeForm = ({ recordId, redirect }) => {
const request = API.post(`/api/container_volumes/${recordId}`, payload)
request.then(() => {
const message = sprintf(
__('Detachment of Container Volume has been successfully queued.')
__('Detachment of Volume has been successfully queued.')
);
miqRedirectBack(message, 'success', redirect);
}).catch((error) => {
Expand Down
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3050,6 +3050,7 @@
tagging_edit
persistentvolumeclaims
attached_volumes
storage_class_list
] +
compare_get,
:post => %w[
Expand Down
Loading