Skip to content

Commit

Permalink
Introduce registries selection
Browse files Browse the repository at this point in the history
Related #85
Closes #447
  • Loading branch information
marusak committed Jul 29, 2020
1 parent 37305e2 commit 7f4ffb1
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 22 deletions.
53 changes: 39 additions & 14 deletions src/ImageSearchModal.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react';
import { ListGroup, ListGroupItem, Modal } from 'patternfly-react';
import { Button, InputGroup, InputGroupText } from '@patternfly/react-core';
import { SearchIcon } from '@patternfly/react-icons';
import { Button, InputGroup } from '@patternfly/react-core';

import * as Select from '../lib/cockpit-components-select.jsx';
import { ErrorNotification } from './Notification.jsx';
import cockpit from 'cockpit';
import rest from './rest.js';
Expand All @@ -22,6 +22,7 @@ export class ImageSearchModal extends React.Component {
searchInProgress: false,
searchFinished: false,
isSystem: props.systemServiceAvailable,
registry: "",
};
this.onDownloadClicked = this.onDownloadClicked.bind(this);
this.onItemSelected = this.onItemSelected.bind(this);
Expand Down Expand Up @@ -72,12 +73,16 @@ export class ImageSearchModal extends React.Component {
this.setState({ searchInProgress: true });

this.activeConnection = rest.connect(client.getAddress(this.state.isSystem), this.state.isSystem);

const rr = this.state.registry;
const registry = rr.length < 1 || rr[rr.length - 1] === "/" ? rr : rr + "/";

const options = {
method: "GET",
path: "/v1.12/libpod/images/search",
body: "",
params: {
term: this.state.imageIdentifier,
term: registry + this.state.imageIdentifier,
},
};
this.activeConnection.call(options)
Expand Down Expand Up @@ -136,17 +141,37 @@ export class ImageSearchModal extends React.Component {
</form>
}
<InputGroup>
<InputGroupText id="username" aria-label={_("Search")}>
<SearchIcon />
</InputGroupText>
<input id='search-image-dialog-name'
autoFocus
className='form-control'
type='text'
placeholder={_("Search by name or description")}
value={this.state.imageIdentifier}
onKeyPress={this.onKeyPress}
onChange={e => this.onValueChanged('imageIdentifier', e.target.value)} />
<div className="ct-form">
<label htmlFor="search-image-dialog-name" className="control-label">{_("Search for")}</label>
<input id='search-image-dialog-name'
autoFocus
className='form-control ct-form-split'
type='text'
placeholder={_("Search by name or description")}
value={this.state.imageIdentifier}
onKeyPress={this.onKeyPress}
onChange={e => this.onValueChanged('imageIdentifier', e.target.value)} />
<label htmlFor="registry-select" aria-label="Registry" className="control-label">{_("in")}</label>
<div className="ct-form-split">
<Select.Select id='registry-select'
initial={this.state.registry}
// Why isn't it taking on this class?!
className='ct-form-split'
onChange={value =>
this.setState({ registry: value }, () => this.onSearchTriggered(false))
}>
<Select.SelectEntry data="" key="all">
{_("All registries")}
</Select.SelectEntry>
{(this.props.registries.search || []).map(r => {
return <Select.SelectEntry data={r} key={r}>
{r}
</Select.SelectEntry>;
})
}
</Select.Select>
</div>
</div>
</InputGroup>

{this.state.searchInProgress && <div id='search-image-dialog-waiting' className='spinner' />}
Expand Down
1 change: 1 addition & 0 deletions src/Images.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ class Images extends React.Component {
close={() => this.setState({ showSearchImageModal: false })}
downloadImage={this.downloadImage}
user={this.props.user}
registries={this.props.registries}
userServiceAvailable={this.props.userServiceAvailable}
systemServiceAvailable={this.props.systemServiceAvailable} /> }
{this.state.imageDownloadInProgress && <div className='download-in-progress'> {_("Pulling")} {this.state.imageDownloadInProgress}... </div>}
Expand Down
7 changes: 6 additions & 1 deletion src/app.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,11 @@ class Application extends React.Component {
init(system) {
client.getInfo(system)
.then(reply => {
this.setState({ [system ? "systemServiceAvailable" : "userServiceAvailable"]: true, version: reply.version.Version });
this.setState({
[system ? "systemServiceAvailable" : "userServiceAvailable"]: true,
version: reply.version.Version,
registries: reply.registries,
});
this.updateImagesAfterEvent(system);
this.updateContainersAfterEvent(system, true);
client.streamEvents(system,
Expand Down Expand Up @@ -544,6 +548,7 @@ class Application extends React.Component {
user={permission.user || _("user")}
userServiceAvailable={this.state.userServiceAvailable}
systemServiceAvailable={this.state.systemServiceAvailable}
registries={this.state.registries}
/>;
const containerList =
<Containers
Expand Down
1 change: 0 additions & 1 deletion src/podman.scss
Original file line number Diff line number Diff line change
Expand Up @@ -235,4 +235,3 @@
padding: 0 0.5em 0 1em;
font-weight: 400;
}

28 changes: 22 additions & 6 deletions test/check-application
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ from machine_core import ssh_connection

REGISTRIES_CONF="""
[registries.search]
registries = ['localhost:5000']
registries = ['localhost:5000', 'localhost:6000']
[registries.insecure]
registries = ['localhost:5000']
registries = ['localhost:5000', 'localhost:6000']
"""

def checkImage(browser, name, owner):
Expand Down Expand Up @@ -408,12 +408,14 @@ class TestApplication(testlib.MachineCase):
execute = self.execute

def prepare():
# Create and start registry container
# Create and start registry containers
self.execute(True, "podman run -d -p 5000:5000 --name registry registry:2")
self.execute(True, "podman run -d -p 6000:5000 --name registry_alt registry:2")
# Add local insecure registry into registries conf
self.execute(True, "echo \"{0}\" > /etc/containers/registries.conf && systemctl stop podman.service".format(REGISTRIES_CONF))
# Push busybox image to the local registry
# Push busybox image to the local registries
self.execute(True, "podman tag busybox localhost:5000/my-busybox && podman push localhost:5000/my-busybox")
self.execute(True, "podman tag busybox localhost:6000/my-busybox && podman push localhost:6000/my-busybox")
# Untag busybox image which duplicates the image we are about to download
self.execute(True, "podman rmi -f busybox")

Expand All @@ -435,6 +437,7 @@ class TestApplication(testlib.MachineCase):
def fillDialog(self):
# Search for image specified with self.imageName and self.imageTag
b.click("#{0}".format(self.user))
b.set_val('#registry-select', "localhost:5000")
# HACK: Sometimes the value is not shown fully. FIXME
b.set_input_text("#search-image-dialog-name", self.imageName, value_check=False)
if self.imageTag:
Expand Down Expand Up @@ -470,7 +473,7 @@ class TestApplication(testlib.MachineCase):
checkImage(b, "localhost:5000/{0}:{1}".format(self.imageName, self.imageTag or "latest"), "system" if self.user == "system" else "admin")

# Find out this image ID
self.imageSha = execute(self.user == "system", "podman inspect --format '{{{{.Id}}}}' {0}:{1}".format(self.imageName, self.imageTag or "latest")).strip()
self.imageSha = execute(self.user == "system", "podman inspect --format '{{{{.Id}}}}' localhost:5000/{0}:{1}".format(self.imageName, self.imageTag or "latest")).strip()

return self

Expand Down Expand Up @@ -507,6 +510,19 @@ class TestApplication(testlib.MachineCase):
self.login_and_go("/podman", authorized=True, superuser=True)
b.wait_present("#app")

# Test registries
b.click("header button:contains(Get new image)")
b.wait_present('div.modal-dialog div.modal-header h4.modal-title:contains("Search Image")')
# HACK: Sometimes the value is not shown fully. FIXME
b.set_input_text("#search-image-dialog-name", "my-busybox", value_check=False)

b.wait_present("div.list-group .image-list-item label:contains('localhost:5000/my-busybox')")
b.wait_present("div.list-group .image-list-item label:contains('localhost:6000/my-busybox')")

b.set_val('#registry-select', "localhost:6000")
b.wait_not_present("div.list-group .image-list-item label:contains('localhost:5000/my-busybox')")
b.wait_present("div.list-group .image-list-item label:contains('localhost:6000/my-busybox')")

dialog0 = DownloadImageDialog('my-busybox', user="system")
dialog0.openDialog() \
.fillDialog() \
Expand All @@ -520,7 +536,7 @@ class TestApplication(testlib.MachineCase):
.expectDownloadSuccess()
dialog1.deleteImage(True)

dialog0.deleteImage()
dialog0.deleteImage(True)

dialog = DownloadImageDialog('my-busybox', 'latest', user="system")
dialog.openDialog() \
Expand Down

0 comments on commit 7f4ffb1

Please sign in to comment.