Skip to content

Commit

Permalink
Use repository for aladdin config (#106)
Browse files Browse the repository at this point in the history
- Added git fetching of aladdin config using a "config_repo" option
- Replaced --dev flag with ALADDIN_DEV env variable
  • Loading branch information
jarojasm95 authored Nov 4, 2021
1 parent 8bdd11a commit 59ae2b7
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 46 deletions.
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ You can add these two commands to your profile file if desired.

You will now need to [create your aladdin configuration](./docs/create_aladdin_configuration.md), and link that to aladdin.

$ aladdin config set config_dir /path/to/aladdin/configuration
$ aladdin config set config_repo [email protected]:{git_account}/{repo}.git

NOTE:

When doing bootstrapping, initial setup or when developing on the aladdin codebase itself it might be useful to be able to point aladdin to a config on the local development environment (ie not yet in source control). This can be done by setting the `ALADDIN_DEV=true` environment variable and by setting the `config_dir` setting (`aladdin config set config_dir /path/to/your/config`).

### Manage configuration
#### Software dependencies
Expand Down Expand Up @@ -135,10 +139,11 @@ We have several aladdin commands used for development and deployment. Note that
- `-c/--cluster` which cluster to connect to, defaults to `LOCAL`.
- `-n/--namespace` which namespace to connect to, defaults to `default`.
- `--init` force initialization logic (i.e. pull latest aladdin image, test aws config, initialize helm, etc...). This is forced every hour for each cluster/namespace combo.
- `--dev` mount host's aladdin directory onto aladdin container. Useful when developing aladdin.
- `--skip-prompts` skip any confirmation messages during aladdin execution. Useful when automating commands.
- `--non-terminal` run aladdin container without tty.

Additionally aladdin checks for a `ALADDIN_DEV=true` environment variable, that when set aladdin will mount the host's aladdin directory onto the aladdin container. This means code changes should be reflected on the container without the need to re-build the image. Mostly useful when developing aladdin.

## Running several aladdin commands in the same cluster/namespace combo
Aladdin supports running several commands in the same cluster/namespace combo without having to "reinitialize" aladdin. To do this, go into `aladdin bash`. Then all the container commands will be aliased to be run without prefixing aladdin.
Example:
Expand Down
4 changes: 2 additions & 2 deletions aladdin-container.sh
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,13 @@ function environment_init() {
else
cp $HOME/.kube/config $HOME/.kube_local/$CLUSTER_NAME.config
kubectl config set-context "$NAMESPACE.$CLUSTER_NAME" --cluster "$CLUSTER_NAME" --namespace="$NAMESPACE" --user "$CLUSTER_NAME"
kubectl config use-context "$NAMESPACE.$CLUSTER_NAME"
kubectl config use-context "$NAMESPACE.$CLUSTER_NAME"
fi

_handle_authentication_config

if $INIT; then
$PY_MAIN create-namespace $NAMESPACE
$PY_MAIN create-namespace $NAMESPACE || true
$PY_MAIN namespace-init --force
fi
fi
Expand Down
33 changes: 8 additions & 25 deletions aladdin.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ function ctrl_trap(){ exit 1 ; }
trap ctrl_trap INT

# Set defaults on command line args
DEV=false
ALADDIN_DEV=${ALADDIN_DEV:-false}
INIT=false
CLUSTER_CODE=LOCAL
NAMESPACE=default
Expand All @@ -27,19 +27,6 @@ PATH="$ALADDIN_BIN":"$PATH"

source "$SCRIPT_DIR/shared.sh" # to load _extract_cluster_config_value

function get_config_path() {
if [[ ! -f "$HOME/.aladdin/config/config.json" ]]; then
echo "Unable to find config directory. Please use 'aladdin config set config_dir <config path location>' to set config directory"
exit 1
fi
ALADDIN_CONFIG_DIR=$(jq -r .config_dir $HOME/.aladdin/config/config.json)
if [[ "$ALADDIN_CONFIG_DIR" == null ]]; then
echo "Unable to find config directory. Please use 'aladdin config set config_dir <config path location>' to set config directory"
exit 1
fi
ALADDIN_CONFIG_FILE="$ALADDIN_CONFIG_DIR/config.json"
}

function get_plugin_dir() {
if [[ -f "$HOME/.aladdin/config/config.json" ]]; then
ALADDIN_PLUGIN_DIR=$(jq -r .plugin_dir $HOME/.aladdin/config/config.json)
Expand All @@ -59,7 +46,7 @@ function get_manage_software_dependencies() {
}
# Check for cluster name aliases and alias them accordingly
function check_cluster_alias() {
cluster_alias=$(jq -r --arg key "$CLUSTER_CODE" '.cluster_aliases[$key]' "$ALADDIN_CONFIG_FILE")
cluster_alias=$(jq -r --arg key "$CLUSTER_CODE" '.cluster_aliases[$key]' "$ALADDIN_CONFIG_DIR/config.json")
if [[ $cluster_alias != null ]]; then
export CLUSTER_CODE=$cluster_alias
fi
Expand Down Expand Up @@ -117,11 +104,11 @@ function check_and_handle_init() {
"$SCRIPT_DIR"/infra_k8s_check.sh --force
fi
check_or_start_k3d
readonly repo_login_command="$(jq -r '.aladdin.repo_login_command' "$ALADDIN_CONFIG_FILE")"
readonly repo_login_command="$(jq -r '.aladdin.repo_login_command' "$ALADDIN_CONFIG_DIR/config.json")"
if [[ "$repo_login_command" != "null" ]]; then
eval "$repo_login_command"
fi
local aladdin_image="$(jq -r '.aladdin.repo' "$ALADDIN_CONFIG_FILE"):$(jq -r '.aladdin.tag' "$ALADDIN_CONFIG_FILE")"
local aladdin_image="$(jq -r '.aladdin.repo' "$ALADDIN_CONFIG_DIR/config.json"):$(jq -r '.aladdin.tag' "$ALADDIN_CONFIG_DIR/config.json")"
if [[ $aladdin_image == *"/"* ]]; then
docker pull "$aladdin_image"
fi
Expand Down Expand Up @@ -245,7 +232,7 @@ function prepare_volume_mount_options() {
# if this is not production or staging, we are mounting kubernetes folder so that
# config maps and other settings can be customized by developers
VOLUME_MOUNTS_OPTIONS=""
if "$DEV"; then
if "$ALADDIN_DEV"; then
VOLUME_MOUNTS_OPTIONS="-v $(pathnorm "$ALADDIN_DIR")/aladdin:/root/aladdin/aladdin"
VOLUME_MOUNTS_OPTIONS="$VOLUME_MOUNTS_OPTIONS -v $(pathnorm "$ALADDIN_DIR")/scripts:/root/aladdin/scripts"
VOLUME_MOUNTS_OPTIONS="$VOLUME_MOUNTS_OPTIONS -v $(pathnorm "$ALADDIN_DIR")/aladdin-container.sh:/root/aladdin/aladdin-container.sh"
Expand All @@ -255,7 +242,7 @@ function prepare_volume_mount_options() {
VOLUME_MOUNTS_OPTIONS="$VOLUME_MOUNTS_OPTIONS -v $(pathnorm $ALADDIN_PLUGIN_DIR):/root/aladdin-plugins"
fi

if "$DEV" || "$IS_LOCAL"; then
if "$ALADDIN_DEV" || "$IS_LOCAL"; then
VOLUME_MOUNTS_OPTIONS="$VOLUME_MOUNTS_OPTIONS -v $HOST_DIR:/aladdin_root$HOST_DIR"
VOLUME_MOUNTS_OPTIONS="$VOLUME_MOUNTS_OPTIONS -w /aladdin_root$(pathnorm "$PWD")"
fi
Expand Down Expand Up @@ -297,11 +284,11 @@ function enter_docker_container() {
FLAGS+="t"
fi

local aladdin_image="${IMAGE:-"$(jq -r '.aladdin.repo' "$ALADDIN_CONFIG_FILE"):$(jq -r '.aladdin.tag' "$ALADDIN_CONFIG_FILE")"}"
local aladdin_image="${IMAGE:-"$(jq -r '.aladdin.repo' "$ALADDIN_CONFIG_DIR/config.json"):$(jq -r '.aladdin.tag' "$ALADDIN_CONFIG_DIR/config.json")"}"

docker run $FLAGS \
`# Environment` \
-e "DEV=$DEV" \
-e "ALADDIN_DEV=$ALADDIN_DEV" \
-e "INIT=$INIT" \
-e "CLUSTER_CODE=$CLUSTER_CODE" \
-e "NAMESPACE=$NAMESPACE" \
Expand Down Expand Up @@ -345,9 +332,6 @@ while [[ $# -gt 0 ]]; do
-i|--init)
INIT=true
;;
--dev)
DEV=true
;;
--non-terminal)
IS_TERMINAL=false
;;
Expand All @@ -364,7 +348,6 @@ while [[ $# -gt 0 ]]; do
done

exec_host_command "$@"
get_config_path
get_plugin_dir
get_host_addr
get_manage_software_dependencies
Expand Down
7 changes: 3 additions & 4 deletions aladdin/bash/container/cluster/cluster
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ set -eu -o pipefail
function usage {
cat <<-EOF
usage: aladdin [-h] [--cluster CLUSTER] [--namespace NAMESPACE] [--admin]
[--init] [--dev] cluster
[--init] cluster
{backup,create-at-aws,create-config,delete,export-config,import-config,init,populate,rolling-update-at-aws,update-at-aws,view-config}
...
Expand Down Expand Up @@ -33,7 +33,6 @@ function usage {
--namespace NAMESPACE, -n NAMESPACE
namespace name, defaults to default current : [default]
--init force the initialization steps (dl latest docker, aws auth, etc...)
--dev mount host's aladdin directory onto aladdin container
EOF
}

Expand Down Expand Up @@ -141,8 +140,8 @@ function populate {
# by running "aladdin backup-cluster".
# This script pulls from your backup folder in your $CLUSTER_CODE directory in your config directory
# It reads the namespaces.txt file and creates all those namepsaces, and then populates those
# namespaces with each namespace's yaml files to create all the k8s resources.
# We then call sync-ingress and sync-dns to update the route 53 records and ingress resource if necessary.
# namespaces with each namespace's yaml files to create all the k8s resources.
# We then call sync-ingress and sync-dns to update the route 53 records and ingress resource if necessary.

if ! "$SKIP_PROMPTS"; then
echo "Is the cluster you wish to populate $CLUSTER_CODE? [y/N] "
Expand Down
111 changes: 111 additions & 0 deletions aladdin/config.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
import json
import os
import pathlib
import subprocess
from distutils.util import strtobool

from aladdin import __version__
from aladdin.lib import logging
from aladdin.lib.utils import working_directory

logger = logging.getLogger(__name__)


PROJECT_ROOT = os.path.dirname(os.path.dirname(__file__))

Expand Down Expand Up @@ -39,3 +49,104 @@ def load_config_from_file(file):

def load_config():
return load_config_from_file(f'{os.environ["ALADDIN_CONFIG_DIR"]}/config.json')


def load_user_config_file() -> dict:
home = pathlib.Path.home()
return load_config_from_file(home / ".aladdin/config/config.json")


def set_user_config_file(config: dict):
home = pathlib.Path.home()
with open(home / ".aladdin/config/config.json", "w") as json_file:
json.dump(config, json_file, indent=2)


def set_config_path() -> bool:
"""
Function to set the "ALADDIN_CONFIG_DIR" env var
Uses git to fetch the latest revision of the config repo
NOTE:
If this function returns False it will short-circuit execution of
any aladdin command, so returning False should be preceded by some
user-friendly error statement about why we're exiting
"""
if os.getenv("ALADDIN_CONFIG_DIR"):
# Aladdin config is already set, nothing to do here
return True

err_message = (
"Unable to find config repo. "
"Please use "
"'aladdin config set config_repo <[email protected]:{git_account}/{repo}.git>' "
"to set config repo"
)
try:
config = load_user_config_file()
except FileNotFoundError:
logger.error(err_message)
return False

config_dir: str = config.get("config_dir")
config_repo: str = config.get("config_repo")
if not config_dir and not config_repo:
logger.error(err_message)
return False

if not config_repo:
# try to auto-set config_repo
if not os.path.isdir(config_dir):
logger.error(err_message)
return False
with working_directory(config_dir):
try:
remote = subprocess.run(
"git remote get-url origin".split(),
check=True,
capture_output=True,
encoding="utf-8"
).stdout.strip()
except subprocess.CalledProcessError:
logger.error(err_message)
return False
*_, git_account, repo = remote.split("/")
config_repo = f"[email protected]:{git_account}/{repo}"
config["config_repo"] = config_repo
set_user_config_file(config)

remote_config_path = pathlib.Path.home() / ".aladdin/remote_config"
commands = [f"git clone -b {__version__} {config_repo} remote_config"]
cwd = pathlib.Path.home() / ".aladdin"
if os.path.isdir(remote_config_path) and os.path.isdir(remote_config_path / ".git"):
cwd = remote_config_path
commands = [
"git fetch --tags --prune -f",
f"git checkout {__version__}"
]
with working_directory(cwd):
for command in commands:
try:
subprocess.run(
command.split(),
check=True,
encoding="utf-8",
capture_output=True
)
except subprocess.CalledProcessError as e:
logger.error(
"Failed to fetch aladdin config (%s) from remote: \n%s",
config_repo,
e.stderr.strip() or e.stdout.strip()
)
return False

os.environ["ALADDIN_CONFIG_DIR"] = str(remote_config_path)

if strtobool(os.getenv("ALADDIN_DEV", "false")) and config_dir and os.path.isdir(config_dir):
"""
Allow aladdin developers to use a custom config
"""
os.environ["ALADDIN_CONFIG_DIR"] = config_dir

return True
3 changes: 3 additions & 0 deletions aladdin/lib/cluster_rules.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
import boto3
from distutils.util import strtobool

from aladdin.lib.arg_tools import CURRENT_NAMESPACE
from aladdin.lib.aws.certificate import search_certificate_arn, new_certificate_arn
Expand Down Expand Up @@ -107,6 +108,8 @@ def dual_dns_prefix_annotation_name(self):

@property
def certificate_lookup(self):
if strtobool(os.getenv("IS_LOCAL", "false")):
return False
return self.rules.get("certificate_lookup", True)

@property
Expand Down
7 changes: 4 additions & 3 deletions aladdin/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import verboselogs
import coloredlogs

from aladdin import config
from aladdin.lib.arg_tools import get_bash_commands, bash_wrapper
from aladdin.commands import (
build,
Expand Down Expand Up @@ -84,9 +85,6 @@ def cli():
parser.add_argument("--cluster", "-c", help="The cluster name you want to interact with")
parser.add_argument("--namespace", "-n", help="The namespace name you want to interact with")
parser.add_argument("-i", "--init", action="store_true", help="Force initialization logic")
parser.add_argument(
"--dev", action="store_true", help="Mount host's aladdin directory onto aladdin container"
)
parser.add_argument("--image", help="Use the specified aladdin image (if building it yourself)")
parser.add_argument(
"--skip-prompts",
Expand Down Expand Up @@ -127,6 +125,9 @@ def cli():
if not sys.argv[1:] or sys.argv[1] in ["-h", "--help"]:
return parser.print_help()

if not config.set_config_path():
return sys.exit(1)

# if it's not a command we know about it might be a plugin
# currently the bash scripts handle plugins
cmd_args = list(filter(lambda arg: not arg.startswith("-"), sys.argv[1:]))
Expand Down
17 changes: 8 additions & 9 deletions docs/cluster_cmd.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Aladdin cluster command
The cluster command contains several subcommands to help create, modify, and delete your cluster.
The cluster command contains several subcommands to help create, modify, and delete your cluster.

Before creating your cluster, you will need to configure your DNS using the "Configure DNS" section from this [doc](https://github.com/kubernetes/kops/blob/master/docs/aws.md). Make sure the subdomain you create here matches your cluster's DNS_ZONE in your env.sh file and your root_dns in your config.json file.
Before creating your cluster, you will need to configure your DNS using the "Configure DNS" section from this [doc](https://github.com/kubernetes/kops/blob/master/docs/aws.md). Make sure the subdomain you create here matches your cluster's DNS_ZONE in your env.sh file and your root_dns in your config.json file.

You will now be able to use aladdin to create your cluster.
You will now be able to use aladdin to create your cluster.

## Sample cluster creation steps
```
Expand All @@ -19,16 +19,16 @@ Note: aladdin doesn't currently support creating instance groups. You will need
aladdin -c <CLUSTER NAME> bash
kops create ig {ig name} {flags}
```
You can then export these to make necessary modifications, and then import your modifications.
You can then export these to make necessary modifications, and then import your modifications.

Then, when the time comes, to delete your cluster:
```
aladdin -c <CLUSTER NAME> cluster delete
```
## Other aladdin cluster commands
`aladdin -c <CLUSTER NAME> cluster backup` create a folder called `backup` in your config folder, cluster subdirectory with all your k8s resources, separated on the namespace level.
`aladdin -c <CLUSTER NAME> cluster populate` use the `backup` folder in your config folder, cluster subdirectory, to populate your cluster with all the k8s resources.
Note: these above two commands are useful when upgrading a kubernetes cluster, by backing up the old cluster, moving the backup folder to your new cluster's config folder, and then populating the cluster.
`aladdin -c <CLUSTER NAME> cluster backup` create a folder called `backup` in your config folder, cluster subdirectory with all your k8s resources, separated on the namespace level.
`aladdin -c <CLUSTER NAME> cluster populate` use the `backup` folder in your config folder, cluster subdirectory, to populate your cluster with all the k8s resources.
Note: these above two commands are useful when upgrading a kubernetes cluster, by backing up the old cluster, moving the backup folder to your new cluster's config folder, and then populating the cluster.

`aladdin -c <CLUSTER NAME> cluster update-at-aws` update cluster configuration without restarting cluster nodes
`aladdin -c <CLUSTER NAME> cluster rolling-update-at-aws` update cluster configuration by restarting cluster nodes
Expand All @@ -37,7 +37,7 @@ Note: these above two commands are useful when upgrading a kubernetes cluster, b
## Usage
```
usage: aladdin [-h] [--cluster CLUSTER] [--namespace NAMESPACE] [--admin]
[--init] [--dev] cluster
[--init] cluster
{backup,create-at-aws,create-config,delete,export-config,import-config,init,populate,rolling-update-at-aws,update-at-aws,view-config}
...
Expand Down Expand Up @@ -66,5 +66,4 @@ optional arguments:
--namespace NAMESPACE, -n NAMESPACE
namespace name, defaults to default current : [default]
--init force the initialization steps (dl latest docker, aws auth, etc...)
--dev mount host's aladdin directory onto aladdin container
```
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "aladdin"
version = "1.19.7.13"
version = "1.19.7.14"
description = ""
authors = ["Fivestars <[email protected]>"]
include = [
Expand Down

0 comments on commit 59ae2b7

Please sign in to comment.