Skip to content

Commit be5f44d

Browse files
authored
Merge branch 'main' into feat/root-squash-compute-init
2 parents 536a31c + 120bcfc commit be5f44d

File tree

6 files changed

+135
-94
lines changed

6 files changed

+135
-94
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ It requires an OpenStack cloud, and an Ansible "deploy host" with access to that
3131

3232
Before starting ensure that:
3333
- You have root access on the deploy host.
34-
- You can create instances from the [latest Slurm appliance image](https://github.com/stackhpc/ansible-slurm-appliance/releases), which already contains the required packages. This is built and tested in StackHPC's CI. Although you can use a Rocky Linux 9 GenericCloud instead, it is not recommended.
34+
- You can create instances from the [latest Slurm appliance image](https://github.com/stackhpc/ansible-slurm-appliance/releases), which already contains the required packages. This is built and tested in StackHPC's CI.
3535
- You have an SSH keypair defined in OpenStack, with the private key available on the deploy host.
3636
- Created instances have access to internet (note proxies can be setup through the appliance if necessary).
3737
- Created instances have accurate/synchronised time (for VM instances this is usually provided by the hypervisor; if not or for bare metal instances it may be necessary to configure a time service via the appliance).
@@ -49,6 +49,7 @@ These instructions assume the deployment host is running Rocky Linux 8:
4949
sudo yum install -y git python38
5050
git clone https://github.com/stackhpc/ansible-slurm-appliance
5151
cd ansible-slurm-appliance
52+
git checkout ${latest-release-tag}
5253
./dev/setup-env.sh
5354

5455
You will also need to install [OpenTofu](https://opentofu.org/docs/intro/install/rpm/).

ansible/roles/basic_users/README.md

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,44 +11,52 @@ without requiring LDAP etc. Features:
1111
- Login to the control node is prevented (by default).
1212
- When deleting users, systemd user sessions are terminated first.
1313

14-
> [!IMPORTANT] This role assumes that `$HOME` for users managed by this role
15-
(e.g. not `rocky` and other system users) is on a shared filesystem. The export
16-
of this shared filesystem may be root squashed if its server is in the
17-
`basic_user` group - see configuration examples below.
14+
> [!IMPORTANT] The defaults for this role assumes that `$HOME` for users
15+
managed by this role (e.g. not `rocky` and other system users) is on a shared
16+
filesystem. The export of this shared filesystem may be root squashed if its
17+
server is in the `basic_user` group - see configuration examples below.
1818

1919
Role Variables
2020
--------------
2121

22-
- `basic_users_users`: Optional, default empty list. A list of mappings defining information for each user. In general, mapping keys/values are passed through as parameters to [ansible.builtin.user](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/user_module.html) and default values are as given there. However:
23-
- `create_home` and `generate_ssh_key`: Normally set automatically. Can be
24-
set `false` if necessary to disable home directory creation/cluster ssh
25-
key creation. Should not be set `true` to avoid trying to modify home
26-
directories from multiple nodes simultaneously.
22+
- `basic_users_homedir_server`: Optional inventory hostname in the `basic_users`
23+
group defining the host to use to create home directories. If the home
24+
directory export is root squashed, this host *must* be the home directory
25+
server. Default is the `control` node which is appropriate for the default
26+
appliance configuration. Not relevant if `create_home` is false for all users.
27+
- `basic_users_homedir_server_path`: Optional path prefix for home directories on
28+
the `basic_users_homedir_server`, i.e. on the "server side". Default is
29+
`/exports/home` which is appropriate for the default appliance configuration.
30+
- `basic_users_homedir_client`: Optional inventory hostname in the `basic_users`
31+
group defining the host to use to create ssh keys etc in home directories.
32+
This should be a host mounting the home directories. Default is the first
33+
node in the `login` group which is appropriate for the default appliance
34+
configuration.
35+
- `basic_users_users`: Optional, default empty list. A list of mappings defining
36+
information for each user. In general, mapping keys/values are passed through
37+
as parameters to [ansible.builtin.user](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/user_module.html)
38+
and default values are as given there, with the following differences:
39+
- `generate_ssh_key`: Default is `true`, and the generated key is added to
40+
the user's authorized keys.
2741
- `ssh_key_comment`: Default is user name.
2842
- `home`: Set automatically based on the user name and
29-
`basic_users_homedir_host_path`. Can be overriden if required for e.g.
30-
users with non-standard home directory paths.
43+
`basic_users_homedir_server_path`. Can be overriden for users with
44+
non-standard home directory paths.
3145
- `uid`: Should be set, so that the UID/GID is consistent across the cluster
3246
(which Slurm requires).
3347
- `shell`: If *not* set will be `/sbin/nologin` on the `control` node to
3448
prevent users logging in to this node, and the default shell on other
3549
nodes. Explicitly setting this defines the shell for all nodes and if the
3650
shared home directories are mounted on the control node will allow the
3751
user to log in to the control node.
38-
- An additional key `public_key` may optionally be specified to define a key to log into the cluster.
39-
- An additional key `sudo` may optionally be specified giving a string (possibly multiline) defining sudo rules to be templated.
40-
- `ssh_key_type` defaults to `ed25519` instead of the `ansible.builtin.user` default of `rsa`.
52+
- `public_key`: Optional, define a key to log into the cluster with.
53+
- `sudo`: Optional, a (possibly multiline) string defining sudo rules for the
54+
user.
55+
- `ssh_key_type` defaults to `ed25519` instead of the `ansible.builtin.user`
56+
default of `rsa`.
4157
- Any other keys may present for other purposes (i.e. not used by this role).
4258
- `basic_users_groups`: Optional, default empty list. A list of mappings defining information for each group. Mapping keys/values are passed through as parameters to [ansible.builtin.group](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/group_module.html) and default values are as given there.
4359
- `basic_users_override_sssd`: Optional bool, default false. Whether to disable `sssd` when ensuring users/groups exist with this role. Permits creating local users/groups even if they clash with users provided via sssd (e.g. from LDAP). Ignored if host is not in group `sssd` as well. Note with this option active `sssd` will be stopped and restarted each time this role is run.
44-
- `basic_users_homedir_host`: Optional inventory hostname defining the host
45-
to use to create home directories. If the home directory export is root
46-
squashed, this host *must* be the home directory server. Default is the
47-
`control` node which is appropriate for the default appliance configuration.
48-
Not relevant if `create_home` is false for all users.
49-
- `basic_users_homedir_host_path`: Optional path prefix for home directories on
50-
the `basic_users_homedir_host`, i.e. on the "server side". Default is
51-
`/exports/home` which is appropriate for the default appliance configuration.
5260

5361
Dependencies
5462
------------

ansible/roles/basic_users/defaults/main.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
basic_users_homedir_host: "{{ groups['control'] | first }}" # no way, generally, to find the nfs_server
2-
basic_users_homedir_host_path: /exports/home
3-
# _basic_users_manage_homedir: "{{ ansible_hostname == basic_users_homedir_host }}"
1+
basic_users_homedir_server: "{{ groups['control'] | first }}" # no way, generally, to find the nfs_server
2+
basic_users_homedir_server_path: /exports/home
3+
basic_users_homedir_client: "{{ groups['login'] | first }}"
44
basic_users_userdefaults:
55
state: present # need this here so don't have to add default() everywhere
66
generate_ssh_key: true

ansible/roles/basic_users/tasks/main.yml

Lines changed: 69 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -49,88 +49,90 @@
4949
state: started
5050
when: _stop_sssd is changed
5151

52-
# This task runs (only) on the home directory server, if in the group, so it can
53-
# handle root squashed exports
52+
# This task runs only on the home directory server so it can handle
53+
# root-squashed exports
5454
- name: Create home directories
5555
# doesn't delete with state=absent, same as ansible.builtin.user
5656
ansible.builtin.copy:
5757
remote_src: true
5858
src: "{{ item.skeleton | default('/etc/skel/') }}"
59-
dest: "{{ item.home | default( basic_users_homedir_host_path + '/' + item.name ) }}"
59+
dest: "{{ item.home | default( basic_users_homedir_server_path + '/' + item.name ) }}"
6060
owner: "{{ item.name }}"
6161
group: "{{ item.name }}"
6262
mode: u=rwX,go=
63-
delegate_to: "{{ basic_users_homedir_host }}"
64-
run_once: true
6563
loop: "{{ basic_users_users }}"
6664
loop_control:
6765
label: "{{ item.name }}"
6866
when:
6967
- item.state | default('present') == 'present'
7068
- item.create_home | default(true) | bool
69+
- inventory_hostname == basic_users_homedir_server
7170

72-
# The following tasks deliberately run on a (single) *client* node, so that
73-
# home directory paths are easily constructed, becoming each user so that root
74-
# squash doesn't matter
75-
- delegate_to: "{{ groups['basic_users'] | difference([basic_users_homedir_host]) | first }}"
76-
run_once: true
77-
block:
78-
- name: Create ~/.ssh directories
79-
file:
80-
state: directory
81-
path: ~/.ssh/
82-
owner: "{{ item.name }}"
83-
group: "{{ item.name }}"
84-
mode: u=rwX,go=
85-
become_user: "{{ item.name }}"
86-
loop: "{{ basic_users_users }}"
87-
loop_control:
88-
label: "{{ item.name }}"
89-
when:
90-
- item.state | default('present') == 'present'
71+
# The following tasks run on a single *client* node, so that home directory
72+
# paths are easily constructed, becoming each user so that root-squash
73+
# doesn't matter
74+
- name: Create ~/.ssh directories
75+
file:
76+
state: directory
77+
path: ~/.ssh/
78+
owner: "{{ item.name }}"
79+
group: "{{ item.name }}"
80+
mode: u=rwX,go=
81+
become_user: "{{ item.name }}"
82+
loop: "{{ basic_users_users }}"
83+
loop_control:
84+
label: "{{ item.name }}"
85+
when:
86+
- item.state | default('present') == 'present'
87+
- item.generate_ssh_key | default(true) | bool or item.public_key is defined
88+
- inventory_hostname == basic_users_homedir_client
9189

92-
- name: Generate cluster ssh key
93-
community.crypto.openssh_keypair:
94-
path: "{{ item.ssh_key_file | default('~/.ssh/id_' + _ssh_key_type )}}" # NB: ssh_key_file is from ansible.builtin.user
95-
type: "{{ _ssh_key_type }}"
96-
comment: "{{ item.ssh_key_comment | default(item.name) }}"
97-
vars:
98-
_ssh_key_type: "{{ item.ssh_key_type | default('ed25519') }}"
99-
become_user: "{{ item.name }}"
100-
loop: "{{ basic_users_users }}"
101-
loop_control:
102-
label: "{{ item.name }}"
103-
when:
104-
- item.state | default('present') == 'present'
105-
- item.generate_ssh_key | default(true) | bool
106-
register: _cluster_ssh_keypair
90+
- name: Generate cluster ssh key
91+
community.crypto.openssh_keypair:
92+
path: "{{ item.ssh_key_file | default('~/.ssh/id_' + _ssh_key_type )}}" # NB: ssh_key_file is from ansible.builtin.user
93+
type: "{{ _ssh_key_type }}"
94+
comment: "{{ item.ssh_key_comment | default(item.name) }}"
95+
vars:
96+
_ssh_key_type: "{{ item.ssh_key_type | default('ed25519') }}"
97+
become_user: "{{ item.name }}"
98+
loop: "{{ basic_users_users }}"
99+
loop_control:
100+
label: "{{ item.name }}"
101+
when:
102+
- item.state | default('present') == 'present'
103+
- item.generate_ssh_key | default(true)
104+
- inventory_hostname == basic_users_homedir_client
105+
register: _cluster_ssh_keypair
107106

108-
- name: Write generated cluster ssh key to authorized_keys
109-
ansible.posix.authorized_key:
110-
user: "{{ item.item.name }}"
111-
state: present
112-
manage_dir: false
113-
key: "{{ item.public_key }}"
114-
path: ~/.ssh/authorized_keys
115-
become_user: "{{ item.item.name }}"
116-
loop: "{{ _cluster_ssh_keypair.results }}"
117-
loop_control:
118-
label: "{{ item.item.name }}"
119-
when:
120-
- item.item.state | default('present') == 'present'
121-
- "'public_key' in item"
107+
- name: Write generated cluster ssh key to authorized_keys
108+
ansible.posix.authorized_key:
109+
user: "{{ item.item.name }}"
110+
state: present
111+
manage_dir: false
112+
key: "{{ item.public_key }}"
113+
path: ~/.ssh/authorized_keys
114+
become_user: "{{ item.item.name }}"
115+
loop: "{{ _cluster_ssh_keypair.results }}"
116+
loop_control:
117+
label: "{{ item.item.name }}"
118+
when:
119+
- item.item.state | default('present') == 'present'
120+
- item.item.generate_ssh_key | default(true)
121+
- inventory_hostname == basic_users_homedir_client
122+
- item.public_key is defined # NB this is the *returned* public key
122123

123-
- name: Write supplied public key to authorized_keys
124-
ansible.posix.authorized_key:
125-
user: "{{ item.name }}"
126-
state: present
127-
manage_dir: false
128-
key: "{{ item.public_key }}"
129-
path: ~/.ssh/authorized_keys
130-
become_user: "{{ item.name }}"
131-
loop: "{{ basic_users_users }}"
132-
loop_control:
133-
label: "{{ item.name }}"
134-
when:
135-
- item.state | default('present') == 'present'
136-
- item.public_key is defined
124+
- name: Write supplied public key to authorized_keys
125+
ansible.posix.authorized_key:
126+
user: "{{ item.name }}"
127+
state: present
128+
manage_dir: false
129+
key: "{{ item.public_key }}"
130+
path: ~/.ssh/authorized_keys
131+
become_user: "{{ item.name }}"
132+
loop: "{{ basic_users_users }}"
133+
loop_control:
134+
label: "{{ item.name }}"
135+
when:
136+
- item.state | default('present') == 'present'
137+
- inventory_hostname == basic_users_homedir_client
138+
- item.public_key is defined # NB this is the *provided* public key

dev/image-share.sh

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/usr/bin/env bash
2+
# Share images from one project to another
3+
#
4+
# usage:
5+
# share-images SOURCE_PROJECT DEST_PROJECT IMAGE_NAME
6+
#
7+
# NB: This requires a clouds.yaml file which uses project names as cloud keys
8+
9+
set -euo pipefail
10+
11+
SOURCE=$1
12+
DEST=$2
13+
IMAGE_NAME=$3
14+
15+
export OS_CLOUD=$SOURCE
16+
SOURCE_PROJECT=$(openstack project show -c id -f value $SOURCE)
17+
export OS_CLOUD=$DEST
18+
DEST_PROJECT=$(openstack project show -c id -f value $DEST)
19+
export OS_CLOUD=$SOURCE
20+
IMAGE=$(openstack image show -c id -f value $IMAGE_NAME)
21+
22+
echo "Sharing $IMAGE_NAME ($IMAGE) from $SOURCE ($SOURCE_PROJECT) ..."
23+
openstack image set --shared $IMAGE
24+
echo "Adding destination project $DEST ($DEST_PROJECT) ..."
25+
openstack image add project $IMAGE $DEST_PROJECT
26+
27+
export OS_CLOUD=$DEST
28+
echo "Accepting share ..."
29+
openstack image set --accept $IMAGE
30+
echo "Done"

docs/openondemand.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ This appliance can deploy and configure:
1010
- The Open OnDemand server itself (usually on a single login node).
1111
- User authentication using one of:
1212
- An external OIDC provider.
13-
- HTTP basic authenication and PAM.
13+
- HTTP basic authentication and PAM.
1414
- Virtual desktops on compute nodes.
1515
- Jupyter nodebook servers on compute nodes.
1616
- Proxying of Grafana (usually deployed on the control node) via the Open OnDemand portal.

0 commit comments

Comments
 (0)