This toolkit helps your run devstack on cloud (currently GCP). It will also provide you with the necessary tools to help you using your local machine for development, and your cloud instance for showing and testing.
The ultimate goal of this toolkit is to help you running projects under development on the cloud while having the luxury to run the engineering side on your machine. No dependencies headaches anymore.
Some available and ready-to-use devstack images are going to help you running the project in a couple of minutes. You can write, delete, and start from scratch anytime with no regrets.
An extensive documentation on the architecture and the toolkit commands can be found in the repo's wiki page here.
Appsembler Internal Doc here.
- Make sure you have your SSH key added into our GCP Appsembler Devstack (appsembler-devstack-30) project. You can check that at GCP Compute Metadata.
- Make sure you have GCloud command-line tools installed.
- Make sure you have a working python 3.7 environment.
If you're on Linux, follow the next steps to set up your Sultan devstack
$ git clone [email protected]:appsembler/sultan.git
$ cd sultan
$ sultan config init # Make sure you're in the correct python environment, this will install the required package immediatly one you run it.
## configs/.configs.username is created
If you're on macOS, follow the steps to set up your Sultan devstack
$ git clone [email protected]:appsembler/sultan.git
$ cd sultan
$ ./sultan config init
NOTE
All the generated files will exist in
$SULTAN_HOME
, you can change the value of this from you configurations file.
The following configurations must be overridden in your recently-created config file:
SSH_KEY
: The private key that has access to the GCP project where we will create your instancePROJECT_ID
: The GCloud project ID.SERVICE_ACCOUNT_EMAIL
: A string that we will use to create a service account.SERVICE_KEY_PATH
: Path to the service account key created in the steps above.
More about this later in Working with configurations section.
Create an instance from a pre-packaged image
$ sultan instance setup --image devstack-juniper
To setup the configurations on your local machine, we need to make sure that your local environment is correctly set up.
- You'll need to create a service account in the GCloud project that will host your devstack instance (official docs here).
- Grant the service account permission to create an instance (official docs here).
- Grant the service account
roles/compute.instanceAdmin
role (See also the list of roles). - Download the service account on your machine.
- After downloading the service account, edit the value of
SERVICE_KEY_PATH
to match its location. (Follow the official docs (here) to generate a key for your service account). - Edit (uncomment, set) the following values in your configs file
## File configs/.configs.$USER
SSH_KEY="$(HOME)/.ssh/id_rsa"
PROJECT_ID=<gcp-project-id>
SERVICE_ACCOUNT_EMAIL=email@<gcp-project-id>.iam.gserviceaccount.com
SERVICE_KEY_PATH=/path/to/service/key.json
NOTE
- This example has my values
- You should change the value
SERVICE_KEY_PATH
if you decided to copy and paste the configurations above.
Preemptible VMs are highly affordable, short-lived compute instances suitable for fault-tolerant workloads. They offer the same machine types and options as regular compute instances and last for up to 24 hours, and can reduce your Compute Engine costs by up to 80%!
Sultan allows you to setup a preemptible machine, you can do that by setting
the configuration variable PREEMPTIBLE
to true
. Just something to note
here, preemptible machines are not suitable for long provisioning work, we only
recommend using them with sultan instance setup --image
command. If you
noticed a freeze in your machine's shell, it means that your machine got
interrupted, and you might have to restart the session again.
When you create a sultan instance, the instance will be configured to run for
a specific amount of time configured in ALIVE_TIME
in the configurations
file. We sat the default lifespan to 6 hours, when your machine powers off
you can start it again using
$ sultan instance start
To stop the machine manually before the timeout use
$ sultan instance stop
For security reasons, Sultan firewall will restrict access to the ports in
EXPOSED_PORTS
in your .configs file. Here's the full list of the ports you
might want to enable.
NOTE
You need to run
sultan instance restrict
everytime you change the port.
Service | Port | Role |
---|---|---|
ssh |
22 | Machine |
lms |
18000 | Default |
studio |
18010 | Default |
forum |
44567 | Default |
amc |
22 | Extra |
discovery |
18381 | Default |
ecommerce |
18130 | Default |
credentials |
18150 | Default |
edx_notes_api |
18120 | Default |
frontend-app-publisher |
18400 | Default |
gradebook |
1994 | Default |
registrar |
18734 | Extra |
program-console |
1976 | Extra |
frontend-app-learning |
2000 | Extra |
frontend-app-library-authoring |
3001 | Extra |
course-authoring |
2001 | Extra |
xqueue |
18040 | Extra |
If you want to access sultan
command line from any directory, add this repo
dir to your PATH
$ export PATH=$PATH:$(pwd) # pwd should translate to /path/to/projects/sultan
To enable auto completion
$ source extras/sultan-completion.bash # For bash shell
$ source extras/sultan-completion.zsh # For zsh shell
NOTE
You can add the command above to your ~/.bashrc or ~/.zshrc
This is in order to have as small latency to your machine and mounted dirs as possible. You can check it here: http://www.gcping.com/ Following example will be how I’ve set it up (the ZONE value) in Europe.
For minimum latency. You can set ZONE
value to match the nearest GCP zone to
you.
## File configs/.configs.$USER
ZONE=europe-west3-c
If this is your first time creating your instance, we recommend
enabling DEBUG
mode to be able to to see a verbose output in case something
fails:
## File configs/.configs.$USER
DEBUG=false
We created a custom env variable for the devstack run command. EdX
uses dev.up
to get the devstack services running. However, in Appsembler we
use some other services that requires extra environment variables such as
HOST
. So simply what we can do here is
## File configs/.configs.$USER
DEVSTACK_RUN_COMMAND="HOST=tahoe dev.up"
NOTE
You need to configure GCloud on your machine before setting the variables above.
Simple as running
$ IMAGE_NAME=devstack-juniper # Or any other devstack image name
$ sultan instance setup --image $IMAGE_NAME
The previous command will spin an instance for you from an already created
image. However, if you prefer to run the full setup from scratch just don't
supply an image
argument.
$ sultan instance setup
Make yourself some coffee. Go for a jog. Recreate the Sistine Chapel painting. Actually, go and built the chapel first. Then do the painting. You’ll have time. A full setup takes quite long. But, once it’s finished…
To run the devstack
$ sultan devstack up
It works. Noice!!
To verify that your instance has been created:
$ sultan instance status ## Prints your GCP instance status.
$ sultan instance ip ## Shows you the instance IP.
$ sultan instance ping ## Verifies that Ansible is able to reach your instance.
To verify that your devstack is running:
$ curl -I devstack.tahoe:18010 ## Curls your Studio site.
NOTE
LMS and Studio might take up to 3 minutes to fully spin. You can check their logs by running
sultan devstack make lms-logs
.
Our Devstack automatically creates your initial site:
Property | Value |
---|---|
LMS Port | 18000 |
Username | red |
[email protected] | |
Password | red |
Other information:
Property | Value |
---|---|
Studio Port | 18010 |
EDX admin username | edx |
EDX admin password | edx |
Once you’ve got everything set up the way you like it and it’s working super-duper, you’ll want to save this sweet sweet and highly unlikely state of our glorious Devstack. To do that you want to create an image of your VM so you can redeploy it quickly whenever you (inevitably) break your Devstack.
In order to do so, simply run:
$ sultan image create
You can also specify a name for your image using
$ sultan image create --name my-lovely-image
NOTE
Just don't forget to supply the image name later to the
setup
command when you wanna retrieve it:sultan instance setup --image my-lovely-image
.
To start your Devstack once it’s set up:
$ sultan instance start
## beep-boop the machine does some machine stuff
$ sultan devstack up
Stopping? No problem
$ sultan instance stop ## Will stop your devstack firts, then the instance.
Want to get rid of it?
$ sultan instance delete
It’s most likely a firewall issue. The instance is secured behind a firewall that only identifies your IP. Probably your IP happened to change (after a network disconnection for example). Here’s the remedy:
- If you didn’t already, do the
sultan instance start
- Try reaching it with
sultan instnace ping
- if it cannot reach it, do the
sultan instance restrict
to adjust the firewall rule.
I’m just gonna assume it worked and you self-high-fived.
Huh, could be something’s properly broken. But remember when we created the image of your instance?
$ sultan instance setup --image
NOTE
If you don't supply an image name to this command,
sultan
will default back to theIMAGE_NAME
value set in your configs file. So all is good.
Woah it’s so fast I cannot believe it! Yup, really works fast and resets it to that glorious state you saved. Nice.
NOTE
The instance is secured behind a firewall by default. To override this behavior, change
RESTRICT_INSTANCE
value in your configs tofalse
.
Sultan supports EDXAPP_EXTRA_REQUIREMENTS
in its unique way. If you are not
familiar with this variable, edX uses it in its production Ansible deployment
scripts, but they were never incorporated in the devstack.
We introduced a way in our devstack (devstack#42)
to install extra pip packages without modifying edx-platform codebase. This
variable has been added to Sultan as a comma-separated configuration variable
(EDXAPP_EXTRA_REQUIREMENTS
), and it utilizes our edxapp-pip
directory
to install extra packages. That's been said, this variable will have no effect
on your devstack unless your using Appsembler's version of the
devstack, unfortunately.
The configuration variable expects a comma-separated list of pip packages' git repos:
EDXAPP_EXTRA_REQUIREMENTS="https://github.com/appsembler/gestore.git==0.1.0-dev3,https://github.com/appsembler/course-access-groups.git"
Once you finish adding this requirement, you need to apply it to the machine:
- If you haven't created a machine yet, then you're all sit, the changes will be deployed in the next
sultan setup
. - If your machine is created and running, run
sultan instance deploy
to have these libraries cloned in your sultan instance.
To specify the version for your package, simply add ==<branch_or_tag>
after
the repo link. If no version is specified, we will default to the main branch
of the repo (HEAD
).
NOTE
If the package you're installing is a Django app, then you might need to consider adding the app name to your
ADDL_INSTALLED_APPS
in your lms/cms YAML configs.
To change or update edx-platform code from your machine and reflect on the server immediately, there are so many ways you can choose from. However, we recommend two common methods to ensure security, real-time transfer, and immediate reflection on the remote instance:
To use it all you have to do is to run sultan devstack mount
and then open
your favorite text editor and start editing files on the server from your
machine.
Some IDEs gives you the power to edit code on remote machines. Visual Studio Code for example, recently added Code Remote Extensions. With this extension, you'll be able to open any folder on your remote machine and take advantage of VS Code's full feature set.
NOTE
If you are using MacOS, make sure to install osxfuse and giving it the right permissions before running
sultan devstack mount
.
If you at a later point restart or whatever without unmounting first and it
doesn’t work, just do sultan devstack unmount
and then
again sultan devstack mount
. Works like a charm.
DISCLAIMER
Manually mounting your devstack locally is slow and laggy. Barely usable. But what I’ve found is that it works way way better with Visual Studio Code and its Code Remote Extensions.
We create a specific ignored .configs file for you when you ran sultan config init
,
to debug the interpreted values of your configs that sultan reads you can run
$ sultan config debug
To check sultan commands' documentation run
$ sultan -h
$ sultan --help
This repo is now being used to ensure our edX services work under our devstack expectations.
All CI/CD is currently done on GitHub. CD will run everytime we have a build triggered from the master branch on Sultan.
Errors are possible all the time. If an error's fired while executing commands from this toolkit it is recommended to do a little bit more debugging. While this might be an issue with the tool, we just want you to make sure that you have everything correct set up in place:
- Run
sultan config debug
and check if all of your environment variables hold the correct values. - Enable out debugging through the
DEBUG
setting in your env file. - Check our Wiki page for a detailed documentation on the configuration process.
If you couldn't identify the cause of the problem, please submit an issue on https://github.com/appsembler/sultan/issues.
The exception below shows up on every (or most) lms pages a full example log is available in this gist.
TypeError: _clone() takes exactly 1 argument (3 given)
Omar: While I don’t know why this happening, I know how to fix it.
Apparently, devstack installs an incorrect django-model-utils
package that
breaks the LMS. Install a specific version of jazzband/django-model-utils
so
the platform works:
$ ssh devstack
$ cd workspace/src
$ mkdir -p edxapp-pip
$ cd edxapp-pip
$ git clone https://github.com/jazzband/django-model-utils.git
$ cd django-model-utils
$ git checkout 3.0.0
$ exit
$ sultan devstack up
That should fix the problem.
┌── VERSION
├── EXPOSED_PORTS
├── BOOT_DISK_TYPE
├── DISK_SIZE
│ ┌── INVENTORY_CONFIGS_DIR ── INVENTORY
│ ┌─── SULTAN_HOME ─┤
├── HOME ──────────────┤ └── MOUNT_DIR
│ └─── SSH_KEY
│
│ ┌─── VERBOSITY
├── DEBUG ──────────────┤
│ └─── SHELL_OUTPUT
│
├── DEVSTACK_REPO_BRANCH ─── OPENEDX_RELEASE
│ ┌── DEVSTACK_DIR
│ ┌─── HOME_DIR ── DEVSTACK_WORKSPACE ──┤
│ │ └── VIRTUAL_ENV
├── USER_NAME ──────────┤
│ └──┐ ┌── ALLOW_FIREWALL
│ │ ├── DENY_FIREWALL
│ ├─────────── INSTANCE_NAME ────────┤
│ │ ├── INSTANCE_TAG
│ │ └── IMAGE_NAME
├── HOST_NAME ─────────────┘
├── PROJECT_ID
├── EDXAPP_EXTRA_REQUIREMENTS
├── BOOT_DISK_TYPE
├── DISK_SIZE
├── MACHINE_TYPE
├── ZONE
├── PREEMPTIBLE
├── ALIVE_TIME
├── SSH_AGENT_HOST_NAME
├── HOSTS_FILE
├── IMAGE_FAMILY
├── EDX_HOST_NAMES
├── SERVICE_ACCOUNT_EMAIL
├── DEVSTACK_REPO_URL
├── SERVICE_KEY_PATH
├── DEVSTACK_RUN_COMMAND
├── RESTRICT_INSTANCE
├── RESTRICT_INSTANCE
├── BOLD
├── NORMAL
├── WHITE
├── RED
├── GREEN
├── YELLOW
├── BLUE
├── PURPLE
├── CYAN
├── GRAY
├── DARK
├── PINK
├── COLS
├── SULTAN_ENV
└── ETC_HOSTS_HACK
Please add more stuff to this doc as you discover helpful information. Let’s all strive for a bright future where an engineer can follow a couple easy steps here and BOOM it’s done.