Adds project/user bootstrap command to dbsync

So far we have been using external mysql command
to insert project/user to bootstrap the process.
This caused much frustration since operators needed
to insert records in the db. This patch adds commands
to dbsync to allow creating project/users. This method
also takes care of association_id.

To initiate a bootstrap:
craton-dbsync --config-file=craton.conf bootstrap

which will create a project with a root user.

Users using Dockerfile can look at docker logs
after creating the container to find this info.

Closes Bug: 1670561

Change-Id: I9372961ca6623d530d7844b9f38aade544d961e8
This commit is contained in:
Sulochan Acharya 2017-03-08 15:18:14 +00:00
parent 0f7ee6d791
commit 109b4b6dd2
6 changed files with 106 additions and 53 deletions

View File

@ -11,12 +11,13 @@
# under the License.
############################################################################
# Usage:
# docker build --pull -t craton-api:latest .
# docker run -t --name craton-api -p 127.0.0.1:7780:7780 -d craton-api:latest
# python tools/generate_fake_data.py --url http://127.0.0.1:7780/v1 --user demo --project b9f10eca66ac4c279c139d01e65f96b4 --key demo
# curl http://127.0.0.1:7780/v1/regions -H "Content-Type: application/json" -H "X-Auth-Token: demo" -H "X-Auth-User: demo" -H "X-Auth-Project: b9f10eca66ac4c279c139d01e65f96b4"
#############################################################################
## Usage:
## docker build --pull -t craton-api:latest .
## docker run -t --name craton-api -p 127.0.0.1:7780:7780 -d craton-api:latest
## docker logs <container> and copy the username, api_key, and project_id
## python tools/generate_fake_data.py --url http://127.0.0.1:7780/v1 --user bootstrap --project <project-id from above> --key <api_key from above>
## Use the credentials from above to try different commands using python-cratonclient.
##############################################################################
# Get Ubuntu base image
FROM ubuntu:16.04

View File

@ -1,3 +1,5 @@
import binascii
import os
from flask import url_for
from oslo_serialization import jsonutils
@ -57,3 +59,11 @@ def add_up_link(context, device):
links = device.setdefault("links", [])
links.append(link)
def gen_api_key():
"""Generates crypto strong 16 bytes api key."""
# NOTE(sulo): this implementation is taken from secrets
# moudule available in python 3.6
tbytes = os.urandom(16)
return binascii.hexlify(tbytes).decode('ascii')

View File

@ -23,6 +23,20 @@ class DBCommand(object):
def create_schema(self):
migration.create_schema()
def bootstrap_project(self):
name = 'bootstrap'
project = migration.create_bootstrap_project(
name,
db_uri=CONF.database.connection)
user = migration.create_bootstrap_user(
project.id,
name,
db_uri=CONF.database.connection)
msg = ("\nProjectId: %s\nUsername: %s\nAPIKey: %s"
% (user.project_id, user.username, user.api_key))
print(msg)
def add_command_parsers(subparsers):
command_object = DBCommand()
@ -57,6 +71,9 @@ def add_command_parsers(subparsers):
help=("Create the database schema."))
parser.set_defaults(func=command_object.create_schema)
parser = subparsers.add_parser('bootstrap')
parser.set_defaults(func=command_object.bootstrap_project)
def main():
command_opt = cfg.SubCommandOpt('command',

View File

@ -1,10 +1,18 @@
import os
import alembic
import os
import uuid
from alembic import config as alembic_config
import alembic.migration as alembic_migration
from sqlalchemy import create_engine
from sqlalchemy import exc
from sqlalchemy.orm import sessionmaker
import sqlalchemy.orm.exc as sa_exc
from oslo_db.sqlalchemy import enginefacade
from craton.api.v1.resources import utils
from craton.db.sqlalchemy import models
def _alembic_config():
path = os.path.join(os.path.dirname(__file__), 'alembic.ini')
@ -50,3 +58,57 @@ def revision(message=None, autogenerate=False, config=None):
config = config or _alembic_config()
return alembic.command.revision(config, message=message,
autogenerate=autogenerate)
def create_bootstrap_project(name, project_id=None, db_uri=None):
"""Creates a new project.
:param name: Name of the new project
"""
if not project_id:
project_id = str(uuid.uuid4())
engine = create_engine(db_uri)
Session = sessionmaker(bind=engine)
session = Session()
project = models.Project(name=name,
id=project_id)
try:
project = session.query(models.Project).filter_by(name=name).one()
except sa_exc.NoResultFound:
session.add(project)
session.commit()
return project
def create_bootstrap_user(project_id, username, db_uri=None):
"""Creates a new project.
:param username: Username for new user
:param project_id: Project ID for the user
"""
engine = create_engine(db_uri)
Session = sessionmaker(bind=engine)
session = Session()
api_key = utils.gen_api_key()
user = models.User(project_id=project_id,
username=username,
api_key=api_key,
is_admin=True,
is_root=True)
try:
session.add(user)
session.commit()
except exc.IntegrityError as err:
if err.orig.args[0] == 1062:
# NOTE(sulo): 1062 is the normal sql duplicate error code
# also see pymysql/constants/ER.py#L65
session.rollback()
user = session.query(models.User).filter_by(username=username)
user = user.filter_by(project_id=project_id).one()
return user
else:
raise
return user

View File

@ -143,31 +143,11 @@ Run dbsync
# craton-dbsync --config-file=etc/craton
-api-conf.sample upgrade
-----------------------
Create Project and User
-----------------------
* Make sure to run dbsync bootstrap to create initial project and root user::
# craton-dbsync --config-file=etc/craton-api-conf.sample bootstrap
.. note:: These goes away once the API has been setup
* Connect to database server as root user::
# mysql -u root -p
* Use the database craton::
# use craton;
* Modify the projects and users as following::
# insert into projects (created_at, updated_at, name, id) values
(NOW(), NOW(), "osic", "717e9a216e2d44e0bc848398563bda06");
# insert into users (created_at, updated_at, project_id, username
, api_key, is_admin)
values (NOW(), NOW(), "717e9a216e2d44e0bc848398563bda06", "demo", "demo", False);
* Logout from the database server::
# exit
Note: The above command outputs user, project-id and API key to use with
python-cratonclient to interact with craton server.
---------------------
Start the API Service

View File

@ -19,31 +19,14 @@ mysqladmin flush-privileges
##############
/craton/bin/craton-dbsync --config-file=/craton/etc/craton-api-conf.sample upgrade
PROJECT="b9f10eca66ac4c279c139d01e65f96b4"
BOOTSTRAP_USERNAME="bootstrap"
BOOTSTRAP_TOKEN="bootstrap"
USERNAME="demo"
TOKEN="demo"
ADMIN_USERNAME="demo_admin"
ADMIN_TOKEN="demo_admin"
ROOT_USERNAME="demo_root"
ROOT_TOKEN="demo_root"
PROJECT_DISCRIMINATOR='project'
####################################
# Create initial project and users #
####################################
PROJECT_VA_ID=$(mysql -u root craton -e "INSERT into variable_association (created_at, updated_at, discriminator) values (NOW(), NOW(), '$PROJECT_DISCRIMINATOR'); SELECT LAST_INSERT_ID();" | grep -Eo '[0-9]+')
mysql -u root craton -e "INSERT into projects (created_at, updated_at, name, variable_association_id, id) values (NOW(), NOW(), '$USERNAME', $PROJECT_VA_ID, '$PROJECT')"
mysql -u root craton -e "INSERT into users (created_at, updated_at, project_id, username, api_key, is_root, is_admin) values (NOW(), NOW(), '$PROJECT', '$BOOTSTRAP_USERNAME', '$BOOTSTRAP_TOKEN', True, False)"
mysql -u root craton -e "INSERT into users (created_at, updated_at, project_id, username, api_key, is_root, is_admin) values (NOW(), NOW(), '$PROJECT', '$USERNAME', '$TOKEN', False, False)"
mysql -u root craton -e "INSERT into users (created_at, updated_at, project_id, username, api_key, is_root, is_admin) values (NOW(), NOW(), '$PROJECT', '$ADMIN_USERNAME', '$ADMIN_TOKEN', False, True)"
mysql -u root craton -e "INSERT into users (created_at, updated_at, project_id, username, api_key, is_root, is_admin) values (NOW(), NOW(), '$PROJECT', '$ROOT_USERNAME', '$ROOT_TOKEN', True, True)"
# NOTE(sulo): One initial bootstrap project with root user will be created by the
# bootstrap process. Users can docker logs -f <container-id> to view their api-key
# to use with the client.
/craton/bin/craton-dbsync --config-file=etc/craton-api-conf.sample bootstrap
#########################
# Start the API service #