Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Console Access for KubeVirt VMs #268

Open
Dhamo1107 opened this issue Dec 13, 2024 · 9 comments
Open

Add Console Access for KubeVirt VMs #268

Dhamo1107 opened this issue Dec 13, 2024 · 9 comments

Comments

@Dhamo1107
Copy link
Contributor

ManageIQ currently does not support console access for KubeVirt VMs, a feature that is available for OpenStack instances. Enabling this functionality would allow users to interact directly with their KubeVirt VMs for troubleshooting, configuration and recovery. Please provide your suggestions on how to implement this feature. Thank you for your consideration!

@Dhamo1107
Copy link
Contributor Author

Hi @agrare,

From the Readme of the KubeVirt provider, it appears that we can connect to the console of VMs (VNC is used in our OpenShift environment). However, on the VM detail page, the Access -> VM Console option is currently not available.

In this WIP PR I have added the RemoteConsole module.

As a result, the VM Console option is now visible.
image
image

How should I proceed further from here? Please provide your insights on the next steps or any improvements required.

Thank You!

@agrare
Copy link
Member

agrare commented Jan 2, 2025

It looks like there is an API to get a web socket for a VNC console, https://kubevirt.io/api-reference/v1.4.0/operations.html#_v1vnc

And the web socket template is wss://%s:%v/v1/namespaces/%s/virtualmachineinstances/%s/vnc (based on the virtctl code)

@agrare
Copy link
Member

agrare commented Jan 2, 2025

You'll need to implement the remote_console_acquire_ticket_queue and remote_console_acquire_ticket methods. The OpenStack VM VNC model is probably a good one to follow here, https://github.com/ManageIQ/manageiq-providers-openstack/blob/master/app/models/manageiq/providers/openstack/cloud_manager/vm/remote_console.rb

@Dhamo1107
Copy link
Contributor Author

Dhamo1107 commented Jan 2, 2025

Hi @agrare,

I used this API: KubeVirt v1.4.0 API Reference

I have the following method:

def remote_console_acquire_ticket(_userid, _originating_server, _console_type)
  url = ext_management_system.with_provider_connection(:namespace => location) do |connection|
    Rails.logger.info("Provider connection established: #{connection.inspect}")
    token = connection.instance_variable_get(:@conn).instance_variable_get(:@kubevirt_token)

    # Construct OpenShift console URL
    host = connection.instance_variable_get(:@conn).instance_variable_get(:@host)
    base_url = "https://#{host}:6443"
    vm_path = "/apis/subresources.kubevirt.io/v1/namespaces/#{location}/virtualmachineinstances/#{name}/vnc"
    "#{base_url}#{vm_path}"
  end

  Rails.logger.info("Generated console URL: #{url}")
  {:remote_url => url, :proto => 'remote'}
end

The request is sent to this URL correctly from ManageIQ:
https://console-openshift-console.apps.ocp4.int:6443/apis/subresources.kubevirt.io/v1/namespaces/default/virtualmachineinstances/centos-stream9-cyan-silkworm-83/vnc

However, I got the following error:

Generated console URL: https://console-openshift-console.apps.ocp4.int:6443/apis/subresources.kubevirt.io/v1/namespaces/default/virtualmachineinstances/centos-stream9-cyan-silkworm-83/vnc
Dec 31 18:19:32 cmp production[1217426]: INFO -- production: Response status: 400
Dec 31 18:19:32 cmp production[1217426]: INFO -- production: Response body: Bad Request
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {},
  "status": "Failure",
  "message": "websocket: the client is not using the websocket protocol: 'upgrade' token not found in 'Connection' header",
  "reason": "BadRequest",
  "code": 400
}
Dec 31 18:19:32 cmp production[1217426]: ERROR -- production: Error accessing console: Bad Request
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {},
  "status": "Failure",
  "message": "websocket: the client is not using the websocket protocol: 'upgrade' token not found in 'Connection' header",
  "reason": "BadRequest",
  "code": 400
}

@Dhamo1107
Copy link
Contributor Author

Dhamo1107 commented Jan 2, 2025

I tested the WebSocket request using Postman by sending it to the same URL:
wss://console-openshift-console.apps.ocp4.int:6443/apis/subresources.kubevirt.io/v1/namespaces/default/virtualmachineinstances/centos-stream9-cyan-silkworm-83/vnc

And it successfully connected with the following details:

  • Status Code: 101 Switching Protocols
  • Request Headers:
    • Sec-WebSocket-Version: 13
    • Sec-WebSocket-Key: QTGSxn3c63B53SMw==
    • Connection: Upgrade
    • Upgrade: websocket
    • Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
    • Host: console-openshift-console.apps.ocp4.int:6443
  • Response Headers:
    • Upgrade: websocket
    • Connection: Upgrade
    • Sec-WebSocket-Accept: MclrefDvR8V0T/C

Could you please confirm if this approach aligns with what’s needed for VNC console access? Let me know if there’s a better way to handle this.

@agrare
Copy link
Member

agrare commented Jan 3, 2025

Console access in MIQ is brokered through the Remote Console Worker so that a user is able to access a console even if they don't have access to the underlying provider.

https://www.manageiq.org/docs/guides/remote_consoles

I believe you would return that url from the remote_console_acquire_ticket method as the {:remote_url => url}, there might be other values that you have to pass for e.g. the websocket-key we might have to figure that out as we go.

@Dhamo1107
Copy link
Contributor Author

Hi @agrare, thanks for your support. How to proceed further

@agrare
Copy link
Member

agrare commented Jan 3, 2025

I would start by implementing the methods described above, running the remote console worker per the docs and testing it out

@Dhamo1107
Copy link
Contributor Author

Dhamo1107 commented Jan 7, 2025

Hi @agrare,

Is this the correct approach to open a WebSocket request and access the console?

def remote_console_acquire_ticket(_userid, _originating_server, _console_type)
  begin
    kubevirt = ext_management_system.parent_manager.connect(:service => "kubernetes",
                                                            :path => "/apis/subresources.kubevirt.io",
                                                            :version => "v1")
    api_url = kubevirt.rest_client.url
    ws_url = api_url.sub('http:', 'wss:').sub('https:', 'wss:')
    console_url = "#{ws_url}/namespaces/#{location}/virtualmachineinstances/#{name}/vnc"
    Rails.logger.info("Generated WebSocket console URL: #{console_url}")

    # Return with additional connection info
    {
      :remote_url => console_url,
      :proto => 'wss',
      :token => kubevirt.get_headers[:Authorization],
      :connection_options => {
        :headers => {
          'Origin' => 'https://console-openshift-console.apps.ocp4.int:6443',
          'Sec-WebSocket-Protocol' => 'base64.binary.k8s.io',
          'Sec-WebSocket-Version' => '13',
          'Sec-WebSocket-Key' => 'QTGSxn3c63B53SMw==',
          'Connection' => 'Upgrade',
          'Upgrade' => 'websocket',
          'Sec-WebSocket-Extensions' => 'permessage-deflate; client_max_window_bits',
          'Host' => 'console-openshift-console.apps.ocp4.int:6443'
        }
      }
    }
  rescue => e
    Rails.logger.error("Failed to generate console URL: #{e.message}")
    raise MiqException::RemoteConsoleNotSupportedError, "Failed to generate console URL: #{e.message}"
  end
end

From this code, I generated the following log:

Generated WebSocket console URL: wss://console-openshift-console.apps.ocp4.int:6443/apis/subresources.kubevirt.io/v1/namespaces/default/virtualmachineinstances/centos-stream9-cyan-silkworm-83/vnc

Could you provide guidance on how to proceed further? Specifically:

  1. Is this implementation correct for opening a WebSocket request and accessing the console?
  2. Should we use VNC to access the console in this case?
  3. Do you have any updates or recommendations for this approach?

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants