GUACAMOLE-1174: Merge support for Kubernetes "exec" API call.
This commit is contained in:
commit
5428ac5057
@ -213,10 +213,11 @@ void* guac_kubernetes_client_thread(void* data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Generate endpoint for attachment URL */
|
/* Generate endpoint for attachment URL */
|
||||||
if (guac_kubernetes_endpoint_attach(endpoint_path, sizeof(endpoint_path),
|
if (guac_kubernetes_endpoint_uri(endpoint_path, sizeof(endpoint_path),
|
||||||
settings->kubernetes_namespace,
|
settings->kubernetes_namespace,
|
||||||
settings->kubernetes_pod,
|
settings->kubernetes_pod,
|
||||||
settings->kubernetes_container)) {
|
settings->kubernetes_container,
|
||||||
|
settings->exec_command)) {
|
||||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||||
"Unable to generate path for Kubernetes API endpoint: "
|
"Unable to generate path for Kubernetes API endpoint: "
|
||||||
"Resulting path too long");
|
"Resulting path too long");
|
||||||
|
@ -31,6 +31,7 @@ const char* GUAC_KUBERNETES_CLIENT_ARGS[] = {
|
|||||||
"namespace",
|
"namespace",
|
||||||
"pod",
|
"pod",
|
||||||
"container",
|
"container",
|
||||||
|
"exec-command",
|
||||||
"use-ssl",
|
"use-ssl",
|
||||||
"client-cert",
|
"client-cert",
|
||||||
"client-key",
|
"client-key",
|
||||||
@ -86,6 +87,11 @@ enum KUBERNETES_ARGS_IDX {
|
|||||||
*/
|
*/
|
||||||
IDX_CONTAINER,
|
IDX_CONTAINER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The command used by exec call. If omitted, attach call will be used.
|
||||||
|
*/
|
||||||
|
IDX_EXEC_COMMAND,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether SSL/TLS should be used. If omitted, SSL/TLS will not be used.
|
* Whether SSL/TLS should be used. If omitted, SSL/TLS will not be used.
|
||||||
*/
|
*/
|
||||||
@ -275,6 +281,11 @@ guac_kubernetes_settings* guac_kubernetes_parse_args(guac_user* user,
|
|||||||
guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
|
guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
|
||||||
IDX_CONTAINER, NULL);
|
IDX_CONTAINER, NULL);
|
||||||
|
|
||||||
|
/* Read exec command (optional) */
|
||||||
|
settings->exec_command =
|
||||||
|
guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
|
||||||
|
IDX_EXEC_COMMAND, NULL);
|
||||||
|
|
||||||
/* Parse whether SSL should be used */
|
/* Parse whether SSL should be used */
|
||||||
settings->use_ssl =
|
settings->use_ssl =
|
||||||
guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
|
guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
|
||||||
@ -406,6 +417,9 @@ void guac_kubernetes_settings_free(guac_kubernetes_settings* settings) {
|
|||||||
free(settings->kubernetes_pod);
|
free(settings->kubernetes_pod);
|
||||||
free(settings->kubernetes_container);
|
free(settings->kubernetes_container);
|
||||||
|
|
||||||
|
/* Free Kubernetes exec command */
|
||||||
|
free(settings->exec_command);
|
||||||
|
|
||||||
/* Free SSL/TLS details */
|
/* Free SSL/TLS details */
|
||||||
free(settings->client_cert);
|
free(settings->client_cert);
|
||||||
free(settings->client_key);
|
free(settings->client_key);
|
||||||
|
@ -97,6 +97,12 @@ typedef struct guac_kubernetes_settings {
|
|||||||
*/
|
*/
|
||||||
char* kubernetes_container;
|
char* kubernetes_container;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The command to generate api endpoint for call exec.
|
||||||
|
* If omitted call attach will be used.
|
||||||
|
*/
|
||||||
|
char* exec_command;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether SSL/TLS should be used.
|
* Whether SSL/TLS should be used.
|
||||||
*/
|
*/
|
||||||
|
@ -89,15 +89,56 @@ int guac_kubernetes_escape_url_component(char* output, int length,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int guac_kubernetes_endpoint_attach(char* buffer, int length,
|
int guac_kubernetes_append_endpoint_param(char* buffer, int length,
|
||||||
const char* kubernetes_namespace, const char* kubernetes_pod,
|
const char* param_name, const char* param_value) {
|
||||||
const char* kubernetes_container) {
|
|
||||||
|
|
||||||
|
char escaped_param_value[GUAC_KUBERNETES_MAX_ENDPOINT_LENGTH];
|
||||||
|
|
||||||
|
/* Escape value */
|
||||||
|
if (guac_kubernetes_escape_url_component(escaped_param_value,
|
||||||
|
sizeof(escaped_param_value), param_value))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
char* str = buffer;
|
||||||
|
|
||||||
|
int str_len = 0;
|
||||||
|
int qmark = 0;
|
||||||
|
|
||||||
|
while (*str != '\0') {
|
||||||
|
|
||||||
|
/* Look for a question mark */
|
||||||
|
if (*str=='?') qmark = 1;
|
||||||
|
|
||||||
|
/* Compute the buffer string length */
|
||||||
|
str_len++;
|
||||||
|
|
||||||
|
/* Verify the buffer null terminated */
|
||||||
|
if (str_len >= length) return 1;
|
||||||
|
|
||||||
|
/* Next character */
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Determine the parameter delimiter */
|
||||||
|
char delimiter = '?';
|
||||||
|
if (qmark) delimiter = '&';
|
||||||
|
|
||||||
|
/* Write the parameter to the buffer */
|
||||||
int written;
|
int written;
|
||||||
|
written = snprintf(buffer + str_len, length - str_len,
|
||||||
|
"%c%s=%s", delimiter, param_name, escaped_param_value);
|
||||||
|
|
||||||
|
/* The parameter was successfully added if it was written to the given
|
||||||
|
* buffer without truncation */
|
||||||
|
return (written < 0 || written >= length);
|
||||||
|
}
|
||||||
|
|
||||||
|
int guac_kubernetes_endpoint_uri(char* buffer, int length,
|
||||||
|
const char* kubernetes_namespace, const char* kubernetes_pod,
|
||||||
|
const char* kubernetes_container, const char* exec_command) {
|
||||||
|
|
||||||
char escaped_namespace[GUAC_KUBERNETES_MAX_ENDPOINT_LENGTH];
|
char escaped_namespace[GUAC_KUBERNETES_MAX_ENDPOINT_LENGTH];
|
||||||
char escaped_pod[GUAC_KUBERNETES_MAX_ENDPOINT_LENGTH];
|
char escaped_pod[GUAC_KUBERNETES_MAX_ENDPOINT_LENGTH];
|
||||||
char escaped_container[GUAC_KUBERNETES_MAX_ENDPOINT_LENGTH];
|
|
||||||
|
|
||||||
/* Escape Kubernetes namespace */
|
/* Escape Kubernetes namespace */
|
||||||
if (guac_kubernetes_escape_url_component(escaped_namespace,
|
if (guac_kubernetes_escape_url_component(escaped_namespace,
|
||||||
@ -109,29 +150,38 @@ int guac_kubernetes_endpoint_attach(char* buffer, int length,
|
|||||||
sizeof(escaped_pod), kubernetes_pod))
|
sizeof(escaped_pod), kubernetes_pod))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* Generate attachment endpoint URL */
|
/* Determine the call type */
|
||||||
if (kubernetes_container != NULL) {
|
char* call = "attach";
|
||||||
|
if (exec_command != NULL)
|
||||||
|
call = "exec";
|
||||||
|
|
||||||
/* Escape container name */
|
int written;
|
||||||
if (guac_kubernetes_escape_url_component(escaped_container,
|
|
||||||
sizeof(escaped_container), kubernetes_container))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
written = snprintf(buffer, length,
|
/* Generate the endpoint path and write to the buffer */
|
||||||
"/api/v1/namespaces/%s/pods/%s/attach"
|
written = snprintf(buffer, length,
|
||||||
"?container=%s&stdin=true&stdout=true&tty=true",
|
"/api/v1/namespaces/%s/pods/%s/%s", escaped_namespace, escaped_pod, call);
|
||||||
escaped_namespace, escaped_pod, escaped_container);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
written = snprintf(buffer, length,
|
|
||||||
"/api/v1/namespaces/%s/pods/%s/attach"
|
|
||||||
"?stdin=true&stdout=true&tty=true",
|
|
||||||
escaped_namespace, escaped_pod);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Endpoint URL was successfully generated if it was written to the given
|
/* Operation successful if the endpoint path was written to the given
|
||||||
* buffer without truncation */
|
* buffer without truncation */
|
||||||
return !(written < length - 1);
|
if (written < 0 || written >= length)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Append exec command parameter */
|
||||||
|
if (exec_command != NULL) {
|
||||||
|
if (guac_kubernetes_append_endpoint_param(buffer,
|
||||||
|
length, "command", exec_command))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Append kubernetes container parameter */
|
||||||
|
if (kubernetes_container != NULL) {
|
||||||
|
if (guac_kubernetes_append_endpoint_param(buffer,
|
||||||
|
length, "container", kubernetes_container))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Append stdin, stdout and tty parameters */
|
||||||
|
return (guac_kubernetes_append_endpoint_param(buffer, length, "stdin", "true"))
|
||||||
|
|| (guac_kubernetes_append_endpoint_param(buffer, length, "stdout", "true"))
|
||||||
|
|| (guac_kubernetes_append_endpoint_param(buffer, length, "tty", "true"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +49,31 @@
|
|||||||
int guac_kubernetes_escape_url_component(char* output, int length,
|
int guac_kubernetes_escape_url_component(char* output, int length,
|
||||||
const char* str);
|
const char* str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append the parameter to the endpoint path.
|
||||||
|
* Value within the path will be URL-escaped as necessary.
|
||||||
|
*
|
||||||
|
* @param buffer
|
||||||
|
* The buffer which should receive the parameter. It could contain the endpoint path.
|
||||||
|
* The parameter will be written to the end of the buffer.
|
||||||
|
*
|
||||||
|
* @param length
|
||||||
|
* The number of bytes available in the given buffer.
|
||||||
|
*
|
||||||
|
* @param param_name
|
||||||
|
* The name of the parameter.
|
||||||
|
*
|
||||||
|
* @param param_value
|
||||||
|
* The value of the parameter.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Zero if the parameter was successfully attached to the buffer,
|
||||||
|
* non-zero if insufficient space exists within the buffer or
|
||||||
|
* buffer not null terminated.
|
||||||
|
*/
|
||||||
|
int guac_kubernetes_append_endpoint_param(char* buffer, int length,
|
||||||
|
const char* param_name, const char* param_value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates the full path to the Kubernetes API endpoint which handles
|
* Generates the full path to the Kubernetes API endpoint which handles
|
||||||
* attaching to running containers within specific pods. Values within the path
|
* attaching to running containers within specific pods. Values within the path
|
||||||
@ -73,13 +98,17 @@ int guac_kubernetes_escape_url_component(char* output, int length,
|
|||||||
* The name of the container to attach to, or NULL to arbitrarily attach
|
* The name of the container to attach to, or NULL to arbitrarily attach
|
||||||
* to the first container in the pod.
|
* to the first container in the pod.
|
||||||
*
|
*
|
||||||
|
* @param exec_command
|
||||||
|
* The command used to run a new process and attach to it,
|
||||||
|
* instead of the main container process.
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
* Zero if the endpoint path was successfully written to the provided
|
* Zero if the endpoint path was successfully written to the provided
|
||||||
* buffer, non-zero if insufficient space exists within the buffer.
|
* buffer, non-zero if insufficient space exists within the buffer.
|
||||||
*/
|
*/
|
||||||
int guac_kubernetes_endpoint_attach(char* buffer, int length,
|
int guac_kubernetes_endpoint_uri(char* buffer, int length,
|
||||||
const char* kubernetes_namespace, const char* kubernetes_pod,
|
const char* kubernetes_namespace, const char* kubernetes_pod,
|
||||||
const char* kubernetes_container);
|
const char* kubernetes_container, const char* exec_command);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user