Skip to content

Commit

Permalink
Generalize rest.js API for multiple users
Browse files Browse the repository at this point in the history
Change `connnect()` and `call()` to accept a `uid` parameter instead of an
address/superuser pair. Compute the Unix address within rest.js, move
`getAddress()` from client for that. For now, just accept `0` for root
and `null` for "current cockpit user", until we actually use that.

Drop the `system` argument from `debug()`, and let the caller specify an
appropriate string. We were only calling `debug()` from rest.js so far anyway,
so that isn't very intrusive.

Keep `isSystem` for the client.js API for the time being. That will be the next
step, but let's not change everything at once.
  • Loading branch information
martinpitt committed Feb 3, 2025
1 parent dd536ed commit 52ac83e
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 34 deletions.
4 changes: 2 additions & 2 deletions src/ContainerLogs.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ class ContainerLogs extends React.Component {
}
this.resize(this.props.width);

const connection = rest.connect(client.getAddress(this.props.system), this.props.system);
const connection = rest.connect(this.props.system ? 0 : null);
const options = {
method: "GET",
path: client.VERSION + "libpod/containers/" + this.props.containerId + "/logs",
Expand All @@ -125,7 +125,7 @@ class ContainerLogs extends React.Component {
},
};

connection.monitor(options, this.onStreamMessage, this.props.system, true)
connection.monitor(options, this.onStreamMessage, true)
.then(this.onStreamClose)
.catch(e => {
const error = JSON.parse(new TextDecoder().decode(e.message));
Expand Down
11 changes: 7 additions & 4 deletions src/ContainerTerminal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { EmptyStatePanel } from "cockpit-components-empty-state.tsx";

import { ErrorNotification } from './Notification.jsx';
import * as client from './client.js';
import rest from './rest.js';

import "./ContainerTerminal.css";

Expand Down Expand Up @@ -191,10 +192,11 @@ class ContainerTerminal extends React.Component {
execAndConnect() {
client.execContainer(this.props.system, this.state.container)
.then(r => {
const address = rest.getAddress(this.props.system ? 0 : null);
const channel = cockpit.channel({
payload: "stream",
unix: client.getAddress(this.props.system),
superuser: this.props.system ? "require" : null,
unix: address.path,
superuser: address.superuser,
binary: true
});

Expand All @@ -210,10 +212,11 @@ class ContainerTerminal extends React.Component {
}

connectToTty() {
const address = rest.getAddress(this.props.system ? 0 : null);
const channel = cockpit.channel({
payload: "stream",
unix: client.getAddress(this.props.system),
superuser: this.props.system ? "require" : null,
unix: address.path,
superuser: address.superuser,
binary: true
});

Expand Down
2 changes: 1 addition & 1 deletion src/ImageRunModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ export class ImageRunModal extends React.Component {
this.activeConnection.close();

this.setState({ searchFinished: false, searchInProgress: true });
this.activeConnection = rest.connect(client.getAddress(this.isSystem()), this.isSystem());
this.activeConnection = rest.connect(this.isSystem() ? 0 : null);
const searches = [];

// Try to get specified image manifest
Expand Down
2 changes: 1 addition & 1 deletion src/ImageSearchModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const ImageSearchModal = ({ downloadImage, user, userServiceAvailable, sy
// can't use that so instead we pass the selected registry.
const onSearchTriggered = (searchRegistry = "", forceSearch = false) => {
// When search re-triggers close any existing active connection
activeConnection = rest.connect(client.getAddress(isSystem), isSystem);
activeConnection = rest.connect(isSystem ? 0 : null);
if (activeConnection)
activeConnection.close();
setSearchFinished(false);
Expand Down
17 changes: 3 additions & 14 deletions src/client.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,7 @@
import rest from './rest.js';

const PODMAN_SYSTEM_ADDRESS = "/run/podman/podman.sock";
export const VERSION = "/v1.12/";

export function getAddress(system) {
if (system)
return PODMAN_SYSTEM_ADDRESS;
const xrd = sessionStorage.getItem('XDG_RUNTIME_DIR');
if (xrd)
return (xrd + "/podman/podman.sock");
console.warn("$XDG_RUNTIME_DIR is not present. Cannot use user service.");
return "";
}

function podmanCall(name, method, args, system, body) {
const options = {
method,
Expand All @@ -21,7 +10,7 @@ function podmanCall(name, method, args, system, body) {
params: args,
};

return rest.call(getAddress(system), system, options);
return rest.call(system ? 0 : null, options);
}

const podmanJson = (name, method, args, system, body) => podmanCall(name, method, args, system, body)
Expand All @@ -35,8 +24,8 @@ function podmanMonitor(name, method, args, callback, system) {
params: args,
};

const connection = rest.connect(getAddress(system), system);
return connection.monitor(options, callback, system);
const connection = rest.connect(system ? 0 : null);
return connection.monitor(options, callback);
}

export const streamEvents = (system, callback) => podmanMonitor("libpod/events", "GET", {}, callback, system);
Expand Down
44 changes: 34 additions & 10 deletions src/rest.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,37 @@ let call_id = 0;

const NL = '\n'.charCodeAt(0); // always 10, but avoid magic constant

function connect(address, system) {
const PODMAN_SYSTEM_ADDRESS = "/run/podman/podman.sock";

/* uid: null for logged in session user; 0 for root; in the future we'll support other users */
/* Return { path, superuser } */
function getAddress(uid) {
if (uid === null) {
// FIXME: make this async and call cockpit.user()
const xrd = sessionStorage.getItem('XDG_RUNTIME_DIR');
if (xrd)
return { path: xrd + "/podman/podman.sock", superuser: null };
console.warn("$XDG_RUNTIME_DIR is not present. Cannot use user service.");
return { path: "", superuser: null };
}

if (uid === 0)
return { path: PODMAN_SYSTEM_ADDRESS, superuser: "require" };

throw new Error(`getAddress: uid ${uid} not supported`);
}

/* uid: null for logged in session user; 0 for root; in the future we'll support other users */
function connect(uid) {
const addr = getAddress(uid);
/* This doesn't create a channel until a request */
/* HACK: use binary channel to work around https://github.com/cockpit-project/cockpit/issues/19235 */
const http = cockpit.http(address, { superuser: system ? "require" : null, binary: true });
const http = cockpit.http(addr.path, { superuser: addr.superuser, binary: true });
const connection = {};
const decoder = new TextDecoder();
const user_str = (uid === null) ? "user" : (uid === 0) ? "root" : `uid ${uid}`;

connection.monitor = function(options, callback, system, return_raw) {
connection.monitor = function(options, callback, return_raw) {
return new Promise((resolve, reject) => {
let buffer = new Uint8Array();

Expand All @@ -48,7 +71,7 @@ function connect(address, system) {
buffer = buffer.slice(idx + 1);

const line_str = decoder.decode(line);
debug(system, "monitor", line_str);
debug(user_str, "monitor", line_str);
callback(JSON.parse(line_str));
}
}
Expand All @@ -62,18 +85,18 @@ function connect(address, system) {

connection.call = function (options) {
const id = call_id++;
debug(system, `call ${id}:`, JSON.stringify(options));
debug(user_str, `call ${id}:`, JSON.stringify(options));
return new Promise((resolve, reject) => {
options = options || {};
http.request(options)
.then(result => {
const text = decoder.decode(result);
debug(system, `call ${id} result:`, text);
debug(user_str, `call ${id} result:`, text);
resolve(text);
})
.catch((error, content) => {
const text = decoder.decode(content);
debug(system, `call ${id} error:`, JSON.stringify(error), "content", text);
debug(user_str, `call ${id} error:`, JSON.stringify(error), "content", text);
manage_error(reject, error, text);
});
});
Expand All @@ -90,14 +113,15 @@ function connect(address, system) {
* Connects to the podman service, performs a single call, and closes the
* connection.
*/
async function call (address, system, parameters) {
const connection = connect(address, system);
async function call (uid, parameters) {
const connection = connect(uid);
const result = await connection.call(parameters);
connection.close();
return result;
}

export default {
connect,
call
call,
getAddress,
};
4 changes: 2 additions & 2 deletions src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ export const podStates = [_("Created"), _("Running"), _("Stopped"), _("Paused"),

export const fallbackRegistries = ["docker.io", "quay.io"];

export function debug(system, ...args) {
export function debug(...args) {
if (window.debugging === "all" || window.debugging?.includes("podman"))
console.debug("podman", system ? "system" : "user", ...args);
console.debug("podman", ...args);
}

export function truncate_id(id) {
Expand Down

0 comments on commit 52ac83e

Please sign in to comment.