Skip to content

Commit

Permalink
Show user owned containers
Browse files Browse the repository at this point in the history
  • Loading branch information
marusak committed Oct 17, 2019
1 parent f4587ec commit 9c3d9bb
Show file tree
Hide file tree
Showing 14 changed files with 713 additions and 284 deletions.
2 changes: 1 addition & 1 deletion src/ContainerCommitModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class ContainerCommitModal extends React.Component {

if (reply && 'logs' in reply && Array.isArray(reply.logs) && reply.logs.length > 0)
console.log("Container commit:", message.parameters.reply.logs.join("\n"));
}, this.props.onHide)
}, this.props.onHide, this.props.container.isSystem)
.then(() => this.props.onHide())
.catch(ex => {
this.setState({
Expand Down
6 changes: 3 additions & 3 deletions src/ContainerTerminal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class ContainerTerminal extends React.Component {
var realWidth = this.state.term._core._renderCoordinator.dimensions.actualCellWidth;
var cols = Math.floor((width - padding) / realWidth);
this.state.term.resize(cols, 24);
cockpit.spawn(["sh", "-c", "echo '1 24 " + cols.toString() + "'>" + this.state.control_channel], { superuser: true });
cockpit.spawn(["sh", "-c", "echo '1 24 " + cols.toString() + "'>" + this.state.control_channel], { superuser: this.props.system ? "require" : null });
this.setState({ cols: cols });
}

Expand All @@ -91,12 +91,12 @@ class ContainerTerminal extends React.Component {
return;
}

utils.podmanCall("GetAttachSockets", { name: this.state.container })
utils.podmanCall("GetAttachSockets", { name: this.state.container }, this.props.system)
.then(out => {
let opts = {
payload: "packet",
unix: out.sockets.io_socket,
superuser: "require",
superuser: this.props.system ? "require" : null,
binary: false
};

Expand Down
30 changes: 19 additions & 11 deletions src/Containers.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,15 @@ class Containers extends React.Component {

if (force)
args.timeout = 0;
utils.podmanCall("StopContainer", args)
utils.podmanCall("StopContainer", args, container.isSystem)
.catch(ex => this.setState({
actionError: cockpit.format(_("Failed to stop container $0"), container.names),
actionErrorDetail: ex.parameters && ex.parameters.reason
}));
}

startContainer(container) {
utils.podmanCall("StartContainer", { name: container.names })
utils.podmanCall("StartContainer", { name: container.names }, container.isSystem)
.catch(ex => this.setState({
actionError: cockpit.format(_("Failed to start container $0"), container.names),
actionErrorDetail: ex.parameters && ex.parameters.reason
Expand All @@ -85,24 +85,31 @@ class Containers extends React.Component {

if (force)
args.timeout = 0;
utils.podmanCall("RestartContainer", args)
utils.podmanCall("RestartContainer", args, container.isSystem)
.catch(ex => this.setState({
actionError: cockpit.format(_("Failed to restart container $0"), container.names),
actionErrorDetail: ex.parameters && ex.parameters.reason
}));
}

renderRow(containersStats, container) {
const containerStats = containersStats[container.id];
const containerStats = containersStats[container.id + container.isSystem.toString()];
const isRunning = container.status == "running";
const image = container.image;

let proc = "";
let mem = "";
if (containerStats) {
proc = containerStats.cpu ? utils.format_cpu_percent(containerStats.cpu * 100) : <abbr title={_("not available")}>{_("n/a")}</abbr>;
mem = containerStats.mem_usage ? utils.format_memory_and_limit(containerStats.mem_usage, containerStats.mem_limit) : <abbr title={_("not available")}>{_("n/a")}</abbr>;
}
let columns = [
{ name: container.names, header: true },
image,
utils.quote_cmdline(container.command),
isRunning ? utils.format_cpu_percent(containerStats.cpu * 100) : "",
containerStats ? utils.format_memory_and_limit(containerStats.mem_usage, containerStats.mem_limit) : "",
proc,
mem,
container.isSystem ? _("system") : this.props.user,
container.status /* TODO: i18n */,
];
let tabs = [{
Expand All @@ -112,7 +119,7 @@ class Containers extends React.Component {
}, {
name: _("Console"),
renderer: ContainerTerminal,
data: { containerId: container.id, containerStatus: container.status, width:this.state.width }
data: { containerId: container.id, containerStatus: container.status, width:this.state.width, system:container.isSystem }
}];

var actions = [
Expand Down Expand Up @@ -152,7 +159,8 @@ class Containers extends React.Component {
return (
<ScrollableAnchor id={container.id} key={container.id}>
<Listing.ListingRow
rowId={container.id}
key={container.id + container.isSystem.toString()}
rowId={container.id + container.isSystem.toString()}
columns={columns}
tabRenderers={tabs}
listingActions={actions}
Expand All @@ -172,7 +180,7 @@ class Containers extends React.Component {
this.setState({
selectContainerDeleteModal: false
});
utils.podmanCall("RemoveContainer", { name: id })
utils.podmanCall("RemoveContainer", { name: id }, this.state.containerWillDelete.isSystem)
.catch(ex => console.error("Failed to do RemoveContainer call:", JSON.stringify(ex)));
}

Expand All @@ -185,7 +193,7 @@ class Containers extends React.Component {
// TODO: force
handleForceRemoveContainer() {
const id = this.state.containerWillDelete ? this.state.containerWillDelete.id : "";
utils.podmanCall("RemoveContainer", { name: id, force: true })
utils.podmanCall("RemoveContainer", { name: id, force: true }, this.state.containerWillDelete.isSystem)
.then(reply => {
this.setState({
setContainerRemoveErrorModal: false
Expand All @@ -201,7 +209,7 @@ class Containers extends React.Component {
}

render() {
const columnTitles = [_("Name"), _("Image"), _("Command"), _("CPU"), _("Memory"), _("State")];
const columnTitles = [_("Name"), _("Image"), _("Command"), _("CPU"), _("Memory"), _("Owner"), _("State")];

let emptyCaption = _("No containers");
if (this.props.containers === null)
Expand Down
4 changes: 2 additions & 2 deletions src/ImageRunModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -253,8 +253,8 @@ export class ImageRunModal extends React.Component {
onRunClicked() {
const createConfig = this.getCreateConfig();

utils.podmanCall("CreateContainer", { create: createConfig })
.then(reply => utils.podmanCall("StartContainer", { name: reply.container }))
utils.podmanCall("CreateContainer", { create: createConfig }, this.state.image.isSystem)
.then(reply => utils.podmanCall("StartContainer", { name: reply.container }, this.state.image.isSystem))
.then(() => this.props.close())
.catch(ex => {
this.setState({
Expand Down
7 changes: 6 additions & 1 deletion src/ImageSearchModal.css
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,9 @@
padding-left: 0.25rem;
padding-right: 0.25rem;
}
}
}

.ct-form .radio {
margin-top: 0px;
margin-bottom: 0px;
}
21 changes: 19 additions & 2 deletions src/ImageSearchModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ export class ImageSearchModal extends React.Component {
imageList: [],
searchInProgress: false,
searchFinished: false,
isSystem: props.systemServiceAvailable,
};
this.onDownloadClicked = this.onDownloadClicked.bind(this);
this.onItemSelected = this.onItemSelected.bind(this);
this.onSearchTriggered = this.onSearchTriggered.bind(this);
this.onValueChanged = this.onValueChanged.bind(this);
this.onKeyPress = this.onKeyPress.bind(this);
this.onToggleUser = this.onToggleUser.bind(this);
}

componentDidMount() {
Expand All @@ -38,11 +40,15 @@ export class ImageSearchModal extends React.Component {
this.activeConnection.close();
}

onToggleUser(ev) {
this.setState({ isSystem: ev.target.id === "system" });
}

onDownloadClicked() {
let selectedImageName = this.state.imageList[this.state.selected].name;

this.props.close();
this.props.downloadImage(selectedImageName, this.state.imageTag);
this.props.downloadImage(selectedImageName, this.state.imageTag, this.state.isSystem);
}

onItemSelected(key) {
Expand All @@ -63,7 +69,7 @@ export class ImageSearchModal extends React.Component {

this.setState({ searchInProgress: true });

varlink.connect(utils.PODMAN_SYSTEM_ADDRESS)
varlink.connect(utils.getAddress(this.state.isSystem), this.state.isSystem)
.then(connection => {
this.activeConnection = connection;

Expand Down Expand Up @@ -110,6 +116,17 @@ export class ImageSearchModal extends React.Component {
render() {
let defaultBody = (
<React.Fragment>
{ this.props.userServiceAvailable && this.props.systemServiceAvailable &&
<form className="ct-form">
<label className="control-label" htmlFor="as-user">{_("Download as:")}</label>
<fieldset id="as-user">
<input type="radio" value="system" id="system" onChange={this.onToggleUser} checked={this.state.isSystem} />
<label className="radio" htmlFor="system">{_("System")}</label>
<input type="radio" value="user" id="user" onChange={this.onToggleUser} checked={!this.state.isSystem} />
<label className="radio" htmlFor="user">{this.props.user.name}</label>
</fieldset>
</form>
}
<div className="input-group">
<span className="input-group-addon">
<span className="fa fa-search" />
Expand Down
10 changes: 8 additions & 2 deletions src/ImageUsedBy.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,18 @@ const _ = cockpit.gettext;

const renderRow = (containerStats, container, showAll) => {
const isRunning = container.status == "running";
let proc = "";
let mem = "";
if (containerStats) {
proc = containerStats.cpu ? utils.format_cpu_percent(containerStats.cpu * 100) : <abbr title={_("not available")}>{_("n/a")}</abbr>;
mem = containerStats.mem_usage ? utils.format_memory_and_limit(containerStats.mem_usage, containerStats.mem_limit) : <abbr title={_("not available")}>{_("n/a")}</abbr>;
}

const columns = [
{ name: container.names, header: true },
utils.quote_cmdline(container.command),
isRunning ? utils.format_cpu_percent(containerStats.cpu * 100) : "",
containerStats ? utils.format_memory_and_limit(containerStats.mem_usage, containerStats.mem_limit) : "",
proc,
mem,
container.status /* TODO: i18n */,

];
Expand Down
45 changes: 25 additions & 20 deletions src/Images.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,13 @@ class Images extends React.Component {
}));
}

downloadImage(imageName, imageTag) {
downloadImage(imageName, imageTag, system) {
let pullImageId = imageName;
if (imageTag)
pullImageId += ":" + imageTag;

this.setState({ imageDownloadInProgress: imageName });
utils.podmanCall("PullImage", { name: pullImageId })
utils.podmanCall("PullImage", { name: pullImageId }, system)
.then(() => {
this.setState({ imageDownloadInProgress: undefined });
})
Expand Down Expand Up @@ -95,7 +95,7 @@ class Images extends React.Component {
this.setState({
selectImageDeleteModal: false,
});
utils.podmanCall("RemoveImage", { name: image })
utils.podmanCall("RemoveImage", { name: image }, this.state.imageWillDelete.isSystem)
.catch(ex => {
this.imageRemoveErrorMsg = ex.parameters.reason;
this.setState({
Expand All @@ -106,7 +106,7 @@ class Images extends React.Component {

handleForceRemoveImage() {
const id = this.state.imageWillDelete ? this.state.imageWillDelete.id : "";
utils.podmanCall("RemoveImage", { name: id, force: true })
utils.podmanCall("RemoveImage", { name: id, force: true }, this.state.imageWillDelete.isSystem)
.then(reply => {
this.setState({
setImageRemoveErrorModal: false
Expand Down Expand Up @@ -147,6 +147,7 @@ class Images extends React.Component {
vulnerabilityColumn,
moment(image.created, utils.GOLANG_TIME_FORMAT).calendar(),
cockpit.format_bytes(image.size),
image.isSystem ? _("system") : this.props.user,
{
element: runImage,
tight: true
Expand All @@ -172,7 +173,7 @@ class Images extends React.Component {
name: _("Used By"),
renderer: ImageUsedBy,
data: {
containers: this.props.imageContainerList !== null ? this.props.imageContainerList[image.id] : null,
containers: this.props.imageContainerList !== null ? this.props.imageContainerList[image.id + image.isSystem.toString()] : null,
showAll: this.props.showAll,
}
});
Expand All @@ -186,8 +187,8 @@ class Images extends React.Component {
];
return (
<Listing.ListingRow
key={image.id}
rowId={image.id}
key={image.id + image.isSystem.toString()}
rowId={image.id + image.isSystem.toString()}
columns={columns}
tabRenderers={tabs}
listingActions={actions} />
Expand All @@ -201,7 +202,7 @@ class Images extends React.Component {
}

render() {
const columnTitles = [ _("Name"), _(''), _("Created"), _("Size"), _('') ];
const columnTitles = [ _("Name"), '', _("Created"), _("Size"), _("Owner"), '' ];
let emptyCaption = _("No images");
if (this.props.images === null)
emptyCaption = "Loading...";
Expand All @@ -216,17 +217,18 @@ class Images extends React.Component {
</a>
];
let filtered = [];
if (this.props.images !== null)
filtered = Object.keys(this.props.images).filter(id => id === this.props.images[id].id);
if (this.props.textFilter.length > 0)
filtered = filtered.filter(id => {
for (let i = 0; i < this.props.images[id].repoTags.length; i++) {
let tag = this.props.images[id].repoTags[i].toLowerCase();
if (tag.indexOf(this.props.textFilter.toLowerCase()) >= 0)
return true;
}
return false;
});
if (this.props.images !== null) {
filtered = Object.keys(this.props.images);
if (this.props.textFilter.length > 0)
filtered = filtered.filter(id => {
for (let i = 0; i < this.props.images[id].repoTags.length; i++) {
let tag = this.props.images[id].repoTags[i].toLowerCase();
if (tag.indexOf(this.props.textFilter.toLowerCase()) >= 0)
return true;
}
return false;
});
}
let imageRows = filtered.map(id => this.renderRow(this.props.images[id]));
const imageDeleteModal =
<ModalExample
Expand Down Expand Up @@ -263,7 +265,10 @@ class Images extends React.Component {
{this.state.showSearchImageModal &&
<ImageSearchModal
close={() => this.setState({ showSearchImageModal: false })}
downloadImage={this.downloadImage} /> }
downloadImage={this.downloadImage}
user={this.props.user}
userServiceAvailable={this.props.userServiceAvailable}
systemServiceAvailable={this.props.systemServiceAvailable} /> }
{this.state.imageDownloadInProgress && <div className='download-in-progress'> {_("Pulling")} {this.state.imageDownloadInProgress}... </div>}
</div>
);
Expand Down
Loading

0 comments on commit 9c3d9bb

Please sign in to comment.