Commit 052ce3cc authored by Noe Nieto's avatar Noe Nieto 💬
Browse files

Merge hopefully

parent c33cf44c
*.sublime-*
*.retry
*~
.vscode/
......@@ -71,10 +71,10 @@ problem while doing so, please create an issue in the Shipwright
## Sharing and contributions
Shipwright (LDH developer)
<https://source.puri.sm/liberty/ldh_developer>
Copyright 2018 Purism SPC
SPDX-License-Identifier: AGPL-3.0-or-later
Shipwright (LDH developer)
<https://source.puri.sm/liberty/ldh_developer>
Copyright 2018 Purism SPC
SPDX-License-Identifier: AGPL-3.0-or-later
Shared under AGPL-3.0-or-later. We adhere to the Community Covenant
1.0 without modification, and certify origin per DCO 1.1 with a
......
#! /bin/sh
exec $HOME/.local/ldh_developer/box/command "$@"
#! /bin/sh
exec $HOME/.local/ldh_developer/shipyard/shipyard "$@"
......@@ -6,9 +6,10 @@ mkdir --parents $HOME/.config/ldh_developer/playbooks
rm --recursive --force $HOME/.local/ldh_developer
rm --force $HOME/.local/bin/shipwright
ln --symbolic --force $PWD $HOME/.local/ldh_developer
rm -f $HOME/.local/ldh_developer && ln --symbolic $PWD $HOME/.local/ldh_developer
ln --symbolic --force $PWD/shipwright $HOME/.local/bin/shipwright
ln --symbolic --force $PWD/playbooks $HOME/.config/ldh_developer/playbooks/ldh_developer
rm -f $HOME/.config/ldh_developer/playbooks/ldh_developer && ln --symbolic $PWD/playbooks $HOME/.config/ldh_developer/playbooks/ldh_developer
shipwright update dependencies
# The shipyard
# The box command
The `shipyard` is a small wrapper around vagrant and libvirt that allows you to manage virtual machines easily. For most commands you only need to provide the hostname.
The `box` command is a small wrapper around Vagrant that allows you to manage virtual machines easily. Currently the supported providers are libvirt and Digital Ocean. For most commands you only need to provide the hostname.
## How it works
Shipyard uses `~/.config/ldh_developer/shipyard` as configuration directory.
Every folder inside the `shipyard` folder represents a vagrant box, so for a box with hostname `floyd` the `$VAGRANT_HOME` directory is `~/.config/lds_developer/shipyard/floyd`:
The `box` command uses `~/.config/ldh_developer/box/` as configuration directory.
Every folder inside the `box` folder represents a box, so for a box with hostname `floyd` the `$VAGRANT_HOME` directory is `~/.config/lds_developer/box/floyd`:
```bash
ls -l ~/.config/ldh_developer/shipyard/
ls -l ~/.config/ldh_developer/box/
total 8
drwxr-xr-x 3 nnieto nnieto 4.0K Nov 27 21:46 floyd/
```
The `floyd` folder contains two files (`Vagrantfile` and `shim.yml`) and the vagrant hidden folder(`.vagrant`).
Once `shipyard` creates a box, you can manage it with the libvirt and vagrant tools of your choice. Recommended tools are:
The `floyd` folder contains two files (`Vagrantfile` and `shim.yml`) and the vagrant hidden folder(`.vagrant`).
Once `box` creates a box, you can manage it with the libvirt, digital ocean and vagrant tools of your choice. Recommended tools are:
- [GNOME Vagrant Indicator](https://github.com/fffilo/gnome-vagrant-indicator)
- virt-manager (apt install virt-manager)
## Commands
`shipyard` supports these commands:
`box` supports these commands:
- `status`: report the status of the virtual machines created/managed by `shipyard`.
- `status`: report the status of the virtual machines created/managed by `box`.
- `create`: create a new VM. You only need to provide the hostname.
- `up`: starts a VM.
- `halt`: stops a VM.
......@@ -37,11 +37,10 @@ Once `shipyard` creates a box, you can manage it with the libvirt and vagrant to
### The `status` command
Prints a summary of the state of all VM's managed by `shipyard`. Example:
Prints a summary of the state of all VM's managed by `box`. Example:
```
$ shipyard status
$ box status
hostname State IP Address
nina running 192.168.121.185
pinta shutoff <N/A>
......@@ -57,7 +56,7 @@ This command creates a new VM. You only need to provide the hostname. But you ca
The following example creates a VM with the hostname `usoland`. The default values for ram size is 512 MB, and 1 CPU.
```
$ shipyard create usoland
$ box create usoland
Bringing machine 'usoland' up with 'libvirt' provider...
==> usoland: Checking if box 'debian/stretch64' is up to date...
[...]
......@@ -67,10 +66,10 @@ Bringing machine 'usoland' up with 'libvirt' provider...
[...]
```
The following example creates a VM with the hostname `usoland` with 4 cpus and 1GB of ram:
The following example creates a VM with the hostname `usoland` with 4 cpus and 1GB of ram:
```
$ shipyard create usoland --cpus 4 --ram 1024
$ box create usoland --cpus 4 --ram 1024
Bringing machine 'usoland' up with 'libvirt' provider...
[...]
==> usoland: -- Cpus: 4
......@@ -84,15 +83,36 @@ Bringing machine 'usoland' up with 'libvirt' provider...
$
```
**Note**: Vagrant/libvirt need root access to create and modify networks on the machine. Vagrant will try to use sudo and will request your passowrd.
**Note**: Vagrant/libvirt needs root access to create and modify networks on the machine. Vagrant will try to use sudo and will request your passowrd.
Finally the following example creates a box using Digital Ocean as provider.
```
$ shipwright vm create starblade --provider digital_ocean --token 2f17c...808c50ae9
Creating ssh key required by Vagrant's Digital Ocean plugin ...
Bringing machine 'starblade' up with 'digital_ocean' provider...
==> starblade: Using existing SSH key: Vagrant
==> starblade: Creating a new droplet...
==> starblade: Assigned IP address: 104.248.176.67
[...]
Bringing machine 'starblade' up with 'digital_ocean' provider...
==> starblade: Creating new SSH key: Vagrant...
==> starblade: Creating a new droplet...
==> starblade: Assigned IP address: 178.128.79.235
[...]
```
**Known issue**: The create command freezes on this message: `==> starblade: Assigned IP address: ...` for some minutes before continuing to destroy the droplet. If you hit Ctrl-C shortly after the `.. Assigned IP adress [..]` messages, the droplet stays alive.
**default provider**: The default provider is `libvirt`, you need to specify `--provider digital_ocean` and `--token` on the command line to spin the machine in Digital Ocean. If you don't have a token yet, you ca generate one on _Manage_ / _API_ section in your DO's control panel.
### The `up`, `halt` and `restart` commands
Use these commands to start and shutdown, or restart the VM's. As an example, the previous section we created one vm. If we check the status we find that it's running.
Use these commands to start, shutdown, or restart a box. As an example, the previous section we created one. If we check the status we find that it's running.
```
$ shipyard status
$ box status
hostname State IP Address
usoland running 192.168.121.57
Total 1 machine(s)
......@@ -101,15 +121,15 @@ $
Now, let's use the `halt` command.
```
shipyard halt usoland
```
box halt usoland
==> usoland: Halting domain...
$
```
We can see that the VM status is `shutoff`:
```
$ shipyard status
$ box status
hostname State IP Address
usoland shutoff <N/A>
Total 1 machine(s)
......@@ -120,7 +140,7 @@ $
We use the `up` command to start the VM again.
```
$ shipyard up usoland
$ box up usoland
Bringing machine 'usoland' up with 'libvirt' provider...
==> usoland: Checking if box 'debian/stretch64' is up to date...
==> usoland: Starting domain.
......@@ -138,7 +158,7 @@ $
Now `status` shows that the vm is running.
```
$ shipyard status
$ box status
hostname State IP Address
usoland running 192.168.121.57
Total 1 machine(s)
......@@ -149,7 +169,7 @@ $
Now, `restart` is very straightforward.
```
$ shipyard restart starblade
$ box restart starblade
==> starblade: Halting domain...
Bringing machine 'starblade' up with 'libvirt' provider...
==> starblade: Checking if box 'debian/stretch64' is up to date...
......@@ -171,7 +191,7 @@ $
The ssh command opens an ssh to the VM.
```bash
$ shipyard ssh usoland
$ box ssh usoland
Linux usoland 4.9.0-8-amd64 #1 SMP Debian 4.9.130-2 (2018-10-27) x86_64
The programs included with the Debian GNU/Linux system are free software;
......@@ -192,8 +212,8 @@ $
The `which` command prints the full path to the `$VAGRANT_HOME` directory of the VM.
```
$ shipyard which usoland
/home/nnieto/.config/ldh_developer/shipyard/usoland
$ box which usoland
/home/nnieto/.config/ldh_developer/box/usoland
$
```
......@@ -203,17 +223,17 @@ $
This command opens a new window of your file manager pointing to the `$VAGRANT_HOME` of the VM.
```bash
./shipyard open --hostname=starone0
./box open --hostname=starone0
[... nautilis shows up ...]
```
### The `ansible` command
This command allows you to run an ansible playbook against one of the VMs. For example: I have two VM's managed by `shipyard`:
This command allows you to run an ansible playbook against one of the VMs. For example: I have two VM's managed by `box`:
```
./shipyard status
./box status
hostname State IP Address
usoland shutoff <N/A>
going-merry running 192.168.121.89
......@@ -235,7 +255,7 @@ Let's install rust on`going-merry`. The playbook looks like this:
Let's save it as `rust.yml` and run the playbook against `going-merry`:
```
./shipyard playbook going-merry rust.yaml
./box playbook going-merry rust.yaml
PLAY [Rust Playbook] *************************************************************************************
......@@ -246,14 +266,14 @@ TASK [Install Rust] ************************************************************
changed: [going-merry]
PLAY RECAP ***********************************************************************************************
going-merry : ok=2 changed=1 unreachable=0 failed=0
going-merry : ok=2 changed=1 unreachable=0 failed=0
```
Now I can use `rustc` on the VM:
```bash
./shipyard ssh going-merry
./box ssh going-merry
Linux going-merry 4.9.0-8-amd64 #1 SMP Debian 4.9.130-2 (2018-10-27) x86_64
The programs included with the Debian GNU/Linux system are free software;
......
#!/usr/bin/python3
import sys
import os
import os, stat
import argparse
import tempfile
import subprocess
......@@ -10,26 +10,6 @@ from pathlib import Path
import ipaddress
vagrant_template = """
Vagrant.configure("2") do |config|
config.vm.hostname = "{hostname}"
config.vm.define :{hostname} do |{hostname}|
{hostname}.vm.box = "debian/stretch64"
{hostname}.vm.hostname = "{hostname}"
{hostname}.vm.provider :libvirt do |libvirt|
libvirt.driver = "kvm"
libvirt.memory = "{ram}"
libvirt.username = "root"
libvirt.graphics_type = "spice"
libvirt.cpus = {cpus}
end
{hostname}.vm.provision "ansible" do |ansible|
ansible.playbook = "shim.yml"
end
end
end
"""
ansible_shim = """
---
- hosts: all
......@@ -37,23 +17,45 @@ ansible_shim = """
tasks:
- name: Shim file for ansible
file:
path: /etc/shipyard_shim.txt
path: /etc/ansible_shim.txt
state: touch
"""
XDG_VM_CONFIG_HOME = Path(os.environ['HOME'],'.config','ldh_developer','shipyard')
XDG_BOX_CONFIG_HOME = Path(os.environ['HOME'],'.config','ldh_developer','box')
XDG_PB_CONFIG_HOME = Path(os.environ['HOME'],'.config','ldh_developer','playbooks')
VG_REQ_PLUGINS = {'libvirt': 'vagrant-libvirt', 'digital_ocean': 'vagrant-digitalocean'}
HERE = Path(__file__).parent
DO_SSH_KEY_PATH = Path('~/.ssh/shipwright/').expanduser()
def ensure_plugins():
cp = subprocess.run(
['vagrant', 'plugin', 'list'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True
)
if cp.returncode != 0:
print("Ooops, there's be something wrong with vagrant!!?")
print(cp.stdout)
print(cp.stderr)
sys.exit(1)
if set(VG_REQ_PLUGINS.values()) != set([l.split()[0] for l in cp.stdout.splitlines()]):
print('There are some missing vagrant plugins.')
print('Install them with: apt install ' + ' '.join(VG_REQ_PLUGINS))
print('Or run the bootstrap script')
sys.exit(1)
def only_if_box_exist(func):
def wrapper(*args, **kwargs):
hostname = args[0]
vagrant_wd = XDG_VM_CONFIG_HOME.joinpath(hostname)
vagrant_wd = XDG_BOX_CONFIG_HOME.joinpath(hostname)
if vagrant_wd.exists():
func(*args, **kwargs)
else:
print("Shipyard error: no vm managed by me has the hostname '{}'".format(hostname))
print("Error: no vm managed by shipwrigth has the hostname '{}'".format(hostname))
exit(1)
return wrapper
......@@ -68,20 +70,20 @@ def is_ipaddress(ip_addr):
def print_status():
"""
Prints the status of all the virtual machines managed by shipyard
Prints the status of all the virtual machines managed by Shipwright
"""
shpyrd_paths = [str(d) for d in XDG_VM_CONFIG_HOME.iterdir() if d.is_dir()]
vm_paths = [str(d) for d in XDG_BOX_CONFIG_HOME.iterdir() if d.is_dir()]
vgt_db = Path(
os.environ.get('VAGRANT_HOME', str(Path.home().joinpath('.vagrant.d'))),
'data', 'machine-index', 'index'
)
count = 0
if vgt_db.exists():
print('hostname \t State\t IP Address')
print('hostname \t State\t IP Address \t Provider')
db = json.loads(vgt_db.open().read())
for k, v in db['machines'].items():
vagrant_wd = v['vagrantfile_path']
if vagrant_wd in shpyrd_paths:
if vagrant_wd in vm_paths:
# get the ip address
cp = subprocess.run(
['vagrant','ssh-config'], cwd=vagrant_wd,
......@@ -100,26 +102,42 @@ def print_status():
print('Total {} machine(s)'.format(count))
def create_box(hostname, ram, cpus):
def vm_create(hostname, ram, cpus, provider, token):
"""
This creates a box using the template
"""
vagrant_wd = XDG_VM_CONFIG_HOME.joinpath(hostname)
vagrant_wd = XDG_BOX_CONFIG_HOME.joinpath(hostname)
if vagrant_wd.exists():
print("Shipyard error: There's already a vm with that hostname")
exit(0)
vagrant_wd.mkdir(parents=True)
# Generate Vagrantfile
with vagrant_wd.joinpath('Vagrantfile').open(mode='w') as vfile:
vfile.write(vagrant_template.format(
hostname=hostname,
ram=ram,
cpus=cpus,
))
# The Ansible shim
vagrant_wd.mkdir(parents=True)
os.chmod(vagrant_wd, stat.S_IRWXU)
vagrant_wd.joinpath('shim.yml').open(mode='w').write(ansible_shim)
if provider == 'digital_ocean':
if not DO_SSH_KEY_PATH.joinpath('id_rsa').exists():
print("Creating ssh key required by Vagrant's Digital Ocean plugin ...")
DO_SSH_KEY_PATH.mkdir(parents=True, exist_ok=True)
os.chmod(DO_SSH_KEY_PATH, stat.S_IRWXU)
subprocess.run(['ssh-keygen', '-f', 'id_rsa', '-t', 'rsa', '-C', 'Created automatically by shipwrigth', '-N', ''], cwd=DO_SSH_KEY_PATH)
vagrant_template = open(HERE.joinpath('digital_ocean.tpl'), 'r').read()
with vagrant_wd.joinpath('Vagrantfile').open(mode='w') as vfile:
vfile.write(vagrant_template.format(
hostname=hostname,
do_token=token,
username=os.environ['USER']
))
else:
vagrant_template = open(HERE.joinpath('libvirt.tpl'), 'r').read()
with vagrant_wd.joinpath('Vagrantfile').open(mode='w') as vfile:
vfile.write(vagrant_template.format(
hostname=hostname,
ram=ram,
cpus=cpus
))
# Execute vagrant with the generated vagrantfile
subprocess.run(['vagrant','up'], cwd=vagrant_wd)
......@@ -129,7 +147,7 @@ def destroy_vm(hostname):
"""
Destroy a box, or all
"""
vagrant_wd = XDG_VM_CONFIG_HOME.joinpath(hostname)
vagrant_wd = XDG_BOX_CONFIG_HOME.joinpath(hostname)
subprocess.run(['vagrant','destroy'], cwd=vagrant_wd)
shutil.rmtree(vagrant_wd)
......@@ -139,7 +157,7 @@ def run_playbook(hostname, playbook, retry_file=None):
"""
run an Ansible playbook against this vm
"""
vagrant_wd = XDG_VM_CONFIG_HOME.joinpath(hostname)
vagrant_wd = XDG_BOX_CONFIG_HOME.joinpath(hostname)
inventory_file = vagrant_wd.joinpath('.vagrant', 'provisioners', 'ansible', 'inventory', 'vagrant_ansible_inventory')
_args = [
'ansible-playbook', '-u', 'vagrant', '-i', f'{inventory_file}',
......@@ -157,7 +175,7 @@ def start_vm(hostname):
"""
Starts the vm with the provided hostname
"""
vagrant_wd = XDG_VM_CONFIG_HOME.joinpath(hostname)
vagrant_wd = XDG_BOX_CONFIG_HOME.joinpath(hostname)
subprocess.run(['vagrant','up'], cwd=vagrant_wd)
......@@ -166,7 +184,7 @@ def halt_vm(hostname):
"""
Stops the vm with the provided hostname
"""
vagrant_wd = XDG_VM_CONFIG_HOME.joinpath(hostname)
vagrant_wd = XDG_BOX_CONFIG_HOME.joinpath(hostname)
subprocess.run(['vagrant','halt'], cwd=vagrant_wd)
......@@ -175,7 +193,7 @@ def invoke_shell(hostname):
"""
Open a SSH session to the hostname
"""
vagrant_wd = XDG_VM_CONFIG_HOME.joinpath(hostname)
vagrant_wd = XDG_BOX_CONFIG_HOME.joinpath(hostname)
subprocess.run(['vagrant','ssh'], cwd=vagrant_wd)
......@@ -184,7 +202,7 @@ def which(hostname):
"""
Print the directory of a vm by it's hostname
"""
vagrant_wd = XDG_VM_CONFIG_HOME.joinpath(hostname)
vagrant_wd = XDG_BOX_CONFIG_HOME.joinpath(hostname)
print(vagrant_wd)
......@@ -193,50 +211,58 @@ def gio_open_vm(hostname):
"""
Open the vm directory in nautilis or any other file manager
"""
vagrant_wd = XDG_VM_CONFIG_HOME.joinpath(hostname)
vagrant_wd = XDG_BOX_CONFIG_HOME.joinpath(hostname)
subprocess.run(['gio','open', vagrant_wd])
COMMANDS = {
'status': "Prints the status of all the VM's managed by shipyard",
'create': 'Creates a new VM using vagrant and libvirt (KVM)',
'up': 'Start VM',
'halt': 'Stop/shutdown a VM',
'restart': 'Restarts the VM',
'destroy': 'Destroy the VM and do cleanup',
'ssh': 'Connect to the vm using SSH',
'status': "Prints the status of all the machines's managed by vm",
'create': 'Creates a new machine using either libvirt(default) or Digital Ocean',
'up': 'Start box',
'halt': 'Stop/shutdown a box',
'restart': 'Restarts the box',
'destroy': 'Destroy the box and do cleanup',
'ssh': 'Connect to the box using SSH',
'playbook': 'Run a playbook against a machine',
'which': 'Print the path to the Vagrantfile',
'open': 'Show the working directory of the VM using the file manager.'
'open': 'Show the working directory of the box using the file manager.'
}
if __name__ == '__main__':
cmd_parser = argparse.ArgumentParser(
prog='shipyard',
prog='vm',
description='This utility helps you mange virtual machines with Vagrant without dealing with configuration details',
)
cmd_parser.add_argument('command', choices=COMMANDS,)
cmd_args = cmd_parser.parse_args(sys.argv[1:2])
# Ensure XDG_VM_CONFIG_HOME exists
XDG_VM_CONFIG_HOME.mkdir(parents=True, exist_ok=True)
# Ensure XDG_BOX_CONFIG_HOME exists
XDG_BOX_CONFIG_HOME.mkdir(parents=True, exist_ok=True)
ensure_plugins()
if cmd_args.command == 'status':
print_status()
sys.exit()
sub_parser = argparse.ArgumentParser(prog='shipyard',)
sub_parser = argparse.ArgumentParser(prog='vm',)
if cmd_args.command == 'create':
sub_parser.usage = 'shipyard create <hostname> [--ram RAM] [--cpus CPUS]'
sub_parser.usage = 'vm create <hostname> [--ram RAM] [--cpus CPUS] [--provider libvirt|digital_ocean] [--token]'
sub_parser.add_argument('hostname', help='This is the hostname for the new the box')
sub_parser.add_argument('--ram', help='Hoy much RAM for this box (default is 512)', default=512)
sub_parser.add_argument('--ram', help='Hoy much RAM for this box (default is 512MB for libvirt and 1GB for digital ocean.)', default=512)
sub_parser.add_argument('--cpus', help='Hoy many CPUs for this box (default is 1)', default=1)
sub_parser.add_argument('--provider', help='Tells shipwrigth which vagrant provider to use. Default is libvirt', default='libvirt')
sub_parser.add_argument('--token', help="This is your personal access token for Digital Ocean's API")
sub_args = sub_parser.parse_args(sys.argv[2:])
create_box(sub_args.hostname, sub_args.ram, sub_args.cpus)
if sub_args.provider == 'digital_ocean' and sub_args.token is None:
print('Error: When using the digital_ocean provider you must provide the access token\n')
print('Example: shipwright vm create foobar --provider digital_ocean --token 0d74f0a...')
sys.exit(1)
vm_create(sub_args.hostname, sub_args.ram, sub_args.cpus, sub_args.provider, sub_args.token)
sys.exit()
sub_parser.add_argument('hostname', help='This is the hostname of the box')
if cmd_args.command == 'playbook':
sub_parser.usage = 'shipyard playbook hostname path/to/playbook.yml'
sub_parser.usage = 'vm playbook hostname path/to/playbook.yml'
sub_parser.add_argument('playbook', help='The path to the playbook file')
sub_parser.add_argument('--retry', help='The path to the playbook retry file.', required=False)
sub_args = sub_parser.parse_args(sys.argv[2:])
......@@ -246,9 +272,9 @@ if __name__ == '__main__':
sub_args = sub_parser.parse_args(sys.argv[2:])
if cmd_args.command == 'up':
start_vm(sub_args.hostname)
if cmd_args.command == 'halt':
elif cmd_args.command == 'halt':
halt_vm(sub_args.hostname)
if cmd_args.command == 'restart':
elif cmd_args.command == 'restart':
halt_vm(sub_args.hostname)
start_vm(sub_args.hostname)
elif cmd_args.command == 'destroy':
......
Vagrant.configure("2") do |config|
config.vm.hostname = '{hostname}'
config.vm.define '{hostname}' do |config|
config.vm.provider :digital_ocean do |provider, override|
override.ssh.private_key_path = '~/.ssh/shipwright/id_rsa'
override.vm.box = 'digital_ocean'
override.vm.box_url = "https://github.com/devopsgroup-io/vagrant-digitalocean/raw/master/box/digital_ocean.box"
override.nfs.functional = false
provider.ssh_key_name = 'Shipwright-{username}'
provider.token = '{do_token}'
provider.image = "debian-9-x64"
provider.region = 'sfo2'
provider.size = '512mb'
end
config.vm.provision "ansible" do |ansible|
ansible.playbook = "shim.yml"
end
end
end
Vagrant.configure("2") do |config|
config.vm.hostname = "{hostname}"
config.vm.define :{hostname} do |{hostname}|
{hostname}.vm.box = "debian/stretch64"
{hostname}.vm.hostname = "{hostname}"
{hostname}.vm.provider :libvirt do |libvirt|
libvirt.driver = "kvm"
libvirt.memory = "{ram}"
libvirt.username = "root"
libvirt.graphics_type = "spice"
libvirt.cpus = {cpus}
end
{hostname}.vm.provision "ansible" do |ansible|
ansible.playbook = "shim.yml"
end
end
end
\ No newline at end of file
......@@ -36,7 +36,7 @@
php_enable_php_fpm: true
php_fpm_listen: "127.0.0.1:9000"
php_fpm_listen_allowed_clients: "127.0.0.1"
php_packages_extra:
php_packages_extra:
- php-mysql
- php-intl
- php-pear
......@@ -86,8 +86,11 @@
activate: true
- name: jwt-authentication-for-wp-rest-api
activate: true
- name: ldh-wp-username-policy
activate: true
url: https://source.puri.sm/liberty/ldh_wp_username_policy/-/archive/master/ldh_wp_username_policy-master.zip
users: {}
options:
options:
- name: woocommerce_api_enabled
command: update
value: yes
......
#! /bin/sh
exec $HOME/.local/ldh_developer/bin/"$@"
LDH_BIN=$HOME/.local/ldh_developer/bin/
if [ $# -eq 0 ] ; then
$LDH_BIN/list
else