Skip to content

Commit

Permalink
Expose run function; Cleanup logging;
Browse files Browse the repository at this point in the history
  • Loading branch information
markwylde committed May 10, 2023
1 parent 6520843 commit c982445
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 86 deletions.
83 changes: 61 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,49 @@ With this setup, you can leverage the power of GitHub Actions and DeploySteps to

To use DeploySteps, you'll need to create a script that defines a set of servers and task you want to run.

### Basic example

```javascript
import fs from 'fs';
import {
run,
copy,
enforceSshPublicKeyOnly,
syncUsers,
updateDebian
} from '@deploysteps/core';
const users = [
{
username: 'user1',
password: 'Password@12345',
publicKeys: [
fs.readFileSync('/Users/user1/.ssh/id_rsa.pub', 'utf8')
],
groups: ['sudo']
}
];
const servers = [
{
host: '192.168.1.100',
port: 22,
username: 'myAccount',
password: 'Password@12345',
privateKey: fs.readFileSync('/Users/user1/.ssh/id_rsa', 'utf8'),
tasks: [
updateDebian(),
syncUsers(users),
enforceSshPublicKeyOnly(),
copy('./stacks/example-voting-app', '/Users/myAccount/Documents/example-voting-app', { clean: true }),
]
}
];
run(servers);
```

### Users Configuration

Create a list of users you want to manage on your servers. Each user object should contain the following properties:
Expand Down Expand Up @@ -192,6 +235,14 @@ import {

Iterate over your list of servers and create an SSH connection for each server. Then, execute the tasks on the server and close the connection when done.

A helper `run` function does this for you:

```javascript
run(servers)
```

But it essentially does the following:

```javascript
for (const server of servers)
const connection = await createSshConnection({
Expand All @@ -200,7 +251,8 @@ for (const server of servers)
});
for (const task of server.tasks) {
await task(connection);
console.log('starting', task.name);
await task.handler(connection);
}
connection.close();
Expand Down Expand Up @@ -269,26 +321,13 @@ This is how a `installVim` script could be implemented.
```javascript
import kleur from "kleur";
export const installVim = () => async (connection) => {
console.log(kleur.magenta('tsk:'), 'installVim');
await connection.exec(`
sudo apt-get -qy update
sudo apt-get -qy install vim
`);
};
```

Then you can add this to your script.

```javascript
const servers = [
{
host: '192.168.1.100',
// ...
tasks: [
updateDebian(),
installVim()
]
export const installVim = () => ({
name: 'Install VIM',
handler: async (connection) => {
await connection.exec(`
sudo apt-get -qy update
sudo apt-get -qy install vim
`);
}
];
});
```
19 changes: 2 additions & 17 deletions example/provision.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import fs from 'fs';
import {
createSshConnection,
run,

copy,
enforceSshPublicKeyOnly,
Expand Down Expand Up @@ -35,19 +35,4 @@ const servers = [
}
];

for (const server of servers) {
const connection = await createSshConnection({
ip: server.host,
username: server.username,
password: server.password,
port: server.port,
otpSecret: server.otpSecret,
privateKey: server.privateKey
});

for (const task of server.tasks) {
await task(connection);
}

connection.close();
}
run(servers);
21 changes: 21 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,27 @@
import createSshConnection from './utils/createSshConnection.js';

export { copy } from './tasks/copy.js';
export { enforceSshPublicKeyOnly } from './tasks/enforceSshPublicKeyOnly.js';
export { syncUsers } from './tasks/syncUsers.js';
export { updateDebian } from './tasks/updateDebian.js';

export { createSshConnection } from './utils/createSshConnection.js';

export async function run (servers) {
for (const server of servers) {
const connection = await createSshConnection({
ip: server.host,
username: server.username,
password: server.password,
port: server.port,
otpSecret: server.otpSecret,
privateKey: server.privateKey
});

for (const task of server.tasks) {
await task.handler(connection);
}

connection.close();
}
}
11 changes: 6 additions & 5 deletions lib/tasks/copy.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import kleur from "kleur";
import { sshCopyFile } from "../utils/sshCopyFile.js";

export const copy = (source, destination, options) => async (connection) => {
console.log(kleur.magenta('tsk:'), 'copy');
return sshCopyFile(connection, source, destination, options);
};
export const copy = (source, destination, options) => ({
name: 'Copy',
handler: async (connection) => {
return sshCopyFile(connection, source, destination, options);
}
});

export default copy;
17 changes: 8 additions & 9 deletions lib/tasks/enforceSshPublicKeyOnly.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import kleur from "kleur";

const ensureSettingValue = (file, key, value) => async (connection) => {
await connection.script(`
#!/bin/bash
Expand All @@ -21,12 +19,13 @@ const ensureSettingValue = (file, key, value) => async (connection) => {
`);
};

export const enforceSshPublicKeyOnly = () => async (connection) => {
console.log(kleur.magenta('tsk:'), 'enforceSshPublicKeyOnly');

await ensureSettingValue('/etc/ssh/sshd_config', 'PasswordAuthentication', 'no')(connection);
await ensureSettingValue('/etc/ssh/sshd_config', 'ChallengeResponseAuthentication', 'no')(connection);
await ensureSettingValue('/etc/ssh/sshd_config', 'PubkeyAuthentication', 'yes')(connection);
}
export const enforceSshPublicKeyOnly = () => ({
name: 'Enforce SSH PublicKey Only',
handler: async (connection) => {
await ensureSettingValue('/etc/ssh/sshd_config', 'PasswordAuthentication', 'no')(connection);
await ensureSettingValue('/etc/ssh/sshd_config', 'ChallengeResponseAuthentication', 'no')(connection);
await ensureSettingValue('/etc/ssh/sshd_config', 'PubkeyAuthentication', 'yes')(connection);
}
});

export default enforceSshPublicKeyOnly;
46 changes: 23 additions & 23 deletions lib/tasks/syncUsers.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import kleur from "kleur";

const syncPublicKeys = async (connection, username, publicKeys) => {
if (!publicKeys || publicKeys.length === 0) {
return;
Expand Down Expand Up @@ -35,32 +33,34 @@ const syncPublicKeys = async (connection, username, publicKeys) => {
`);
};

export const syncUsers = (users) => async (connection) => {
console.log(kleur.magenta('tsk:'), 'syncUsers');
for (const user of users) {
const userExists = await connection.exec(`
id -u ${user.username} >/dev/null 2>&1; echo $?
`);

if (userExists.trim() === '1') {
await connection.exec(`
sudo useradd -m -p "$(openssl passwd -1 '${user.password}')" ${user.username}
export const syncUsers = (users) => ({
name: 'Sync Users',
handler: async (connection) => {
for (const user of users) {
const userExists = await connection.exec(`
id -u ${user.username} >/dev/null 2>&1; echo $?
`);
} else {

if (userExists.trim() === '1') {
await connection.exec(`
sudo useradd -m -p "$(openssl passwd -1 '${user.password}')" ${user.username}
`);
} else {
await connection.exec(`
echo '${user.username}:${user.password}' | sudo chpasswd
`);
}

const groupsString = user.groups.join(',');
await connection.exec(`
echo '${user.username}:${user.password}' | sudo chpasswd
sudo usermod -aG ${groupsString} ${user.username}
`);
}

const groupsString = user.groups.join(',');
await connection.exec(`
sudo usermod -aG ${groupsString} ${user.username}
`);

if (user.publicKeys) {
await syncPublicKeys(connection, user.username, user.publicKeys);
if (user.publicKeys) {
await syncPublicKeys(connection, user.username, user.publicKeys);
}
}
}
};
});

export default syncUsers;
20 changes: 10 additions & 10 deletions lib/tasks/updateDebian.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import kleur from "kleur";

export const updateDebian = () => async (connection) => {
console.log(kleur.magenta('tsk:'), 'updateDebian');
await connection.exec(`
sudo apt-get -qy update
sudo apt-get -qy upgrade
sudo apt-get -qy autoremove
`);
};
export const updateDebian = () => ({
name: 'Update Debian',
handler: async (connection) => {
await connection.exec(`
sudo apt-get -qy update
sudo apt-get -qy upgrade
sudo apt-get -qy autoremove
`);
}
});

export default updateDebian;

0 comments on commit c982445

Please sign in to comment.