Skip to content

Commit

Permalink
Authorized SSH keys for VM's based on cloud image
Browse files Browse the repository at this point in the history
  • Loading branch information
skobyda committed Jul 14, 2023
1 parent 6b4cd77 commit e66ad82
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 8 deletions.
71 changes: 63 additions & 8 deletions src/components/create-vm-dialog/createVmDialog.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { debounce } from 'throttle-debounce';
import { Divider } from "@patternfly/react-core/dist/esm/components/Divider";
import { FileUpload } from '@patternfly/react-core/dist/esm/components/FileUpload';
import { Flex, FlexItem } from "@patternfly/react-core/dist/esm/layouts/Flex";
import { Form, FormGroup } from "@patternfly/react-core/dist/esm/components/Form";
import { FormSelect, FormSelectOption } from "@patternfly/react-core/dist/esm/components/FormSelect";
import { Grid, GridItem } from "@patternfly/react-core/dist/esm/layouts/Grid";
import { InputGroup } from "@patternfly/react-core/dist/esm/components/InputGroup";
import { Modal } from "@patternfly/react-core/dist/esm/components/Modal";
import { Select as PFSelect, SelectGroup, SelectOption } from "@patternfly/react-core/dist/esm/deprecated/components/Select";
Expand All @@ -33,7 +35,7 @@ import { Button } from "@patternfly/react-core/dist/esm/components/Button";
import { Tooltip } from "@patternfly/react-core/dist/esm/components/Tooltip";
import { TextArea } from "@patternfly/react-core/dist/esm/components/TextArea";
import { Spinner } from "@patternfly/react-core/dist/esm/components/Spinner";
import { ExternalLinkAltIcon } from '@patternfly/react-icons';
import { ExternalLinkAltIcon, MinusIcon } from '@patternfly/react-icons';

import { DialogsContext } from 'dialogs.jsx';
import cockpit from 'cockpit';
Expand Down Expand Up @@ -84,6 +86,7 @@ import { domainCreate } from '../../libvirtApi/domain.js';
import { storagePoolRefresh } from '../../libvirtApi/storagePool.js';
import { getAccessToken } from '../../libvirtApi/rhel-images.js';
import { PasswordFormFields, password_quality } from 'cockpit-components-password.jsx';
import { DynamicListForm } from '../common/DynamicListForm';

import './createVmDialog.scss';

Expand Down Expand Up @@ -748,20 +751,70 @@ const UsersConfigurationRow = ({
);
};

const SshKeysRow = ({
id, item, onChange, idx, removeitem,
}) => {
const [isLoading, setIsLoading] = useState(false);

const handleClear = (_event) => {
onChange(idx, "file", "");
onChange(idx, "value", "");
};

return (
<Grid id={id}>
<GridItem span={11}>
<FileUpload id={"create-vm-dialog-ssh-key-" + id}
type="text"
value={item.value}
filename={item.filename}
filenamePlaceholder="Drag and drop a file or upload one"
onFileInputChange={(_event, file) => onChange(idx, "file", file)}
onDataChange={(_event, value) => onChange(idx, "value", value)}
onTextChange={(_event, value) => onChange(idx, "value", value)}
onReadStarted={() => setIsLoading(true)}
onReadFinished={() => setIsLoading(false)}
onClearClick={_event => handleClear(_event)}
isLoading={isLoading}
allowEditingUploadedText
browseButtonText="Upload" />
</GridItem>
<GridItem span={1} className="pf-m-1-col-on-md remove-button-group">
<Button variant='secondary'
className="btn-close"
id={id + "-btn-close"}
isSmall
aria-label={_("Remove item")}
icon={<MinusIcon />}
onClick={() => removeitem(idx)} />
</GridItem>
</Grid>
);
};

const CloudInitOptionsRow = ({
onValueChanged,
rootPassword,
userLogin, userPassword,
validationFailed,
}) => {
return (
<UsersConfigurationRow rootPassword={rootPassword}
rootPasswordLabelInfo={_("Leave the password blank if you do not wish to set a root password")}
showUserFields
userLogin={userLogin}
userPassword={userPassword}
validationFailed={validationFailed}
onValueChanged={onValueChanged} />
<>
<UsersConfigurationRow rootPassword={rootPassword}
rootPasswordLabelInfo={_("Leave the password blank if you do not wish to set a root password")}
showUserFields
userLogin={userLogin}
userPassword={userPassword}
validationFailed={validationFailed}
onValueChanged={onValueChanged} />
<DynamicListForm id="create-vm-dialog-ssh-key"
emptyStateString={_("No SSH keys specified")}
label={_("SSH keys")}
actionLabel={_("Add SSH keys")}
onChange={value => onValueChanged('sshKeys', value)}
default={{ value: null, file: null }}
itemcomponent={ <SshKeysRow />} />
</>
);
};

Expand Down Expand Up @@ -979,6 +1032,7 @@ class CreateVmModal extends React.Component {
userLogin: '',
accessToken: '',
offlineToken: '',
sshKeys: [],
};
this.onCreateClicked = this.onCreateClicked.bind(this);
this.onValueChanged = this.onValueChanged.bind(this);
Expand Down Expand Up @@ -1172,6 +1226,7 @@ class CreateVmModal extends React.Component {
userPassword: this.state.userPassword,
rootPassword: this.state.rootPassword,
userLogin: this.state.userLogin,
sshKeys: this.state.sshKeys.map(key => key.value),
startVm,
accessToken: this.state.accessToken,
loggedUser
Expand Down
4 changes: 4 additions & 0 deletions src/scripts/install_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ def prepare_cloud_init(args):
if args['userLogin']:
user_data_file.write("users:\n")
user_data_file.write(f" - name: {args['userLogin']}\n")
if args['sshKeys'] and len(args['sshKeys']) > 9:
user_data_file.write(" ssh_authorized_keys:\n")
for key in args['sshKeys']:
user_data_file.write(f" - {key}\n")

if args['rootPassword'] or args['userPassword']:
# enable SSH password login if any password is set
Expand Down

0 comments on commit e66ad82

Please sign in to comment.