def upload_component_file(user, c_id): COMPONENT_FILES = models.COMPONENT_FILES component = v1_utils.verify_existence_and_get(c_id, _TABLE) if str(component['topic_id']) not in v1_utils.user_topic_ids(user): raise dci_exc.Unauthorized() store = dci_config.get_store('components') file_id = utils.gen_uuid() file_path = files_utils.build_file_path(component['topic_id'], c_id, file_id) content = files_utils.get_stream_or_content_from_request(flask.request) store.upload(file_path, content) s_file = store.head(file_path) values = dict.fromkeys(['md5', 'mime', 'component_id', 'name']) values.update({ 'id': file_id, 'component_id': c_id, 'name': file_id, 'created_at': datetime.datetime.utcnow().isoformat(), 'md5': s_file['etag'], 'mime': s_file['content-type'], 'size': s_file['content-length'] }) query = COMPONENT_FILES.insert().values(**values) flask.g.db_conn.execute(query) result = json.dumps({'component_file': values}) return flask.Response(result, 201, content_type='application/json')
def _validate_input(values, user): topic_id = values.pop('topic_id') remoteci_id = values.get('remoteci_id') values.update({ 'id': utils.gen_uuid(), 'created_at': datetime.datetime.utcnow().isoformat(), 'updated_at': datetime.datetime.utcnow().isoformat(), 'etag': utils.gen_etag(), 'status': 'new' }) remoteci = v1_utils.verify_existence_and_get(remoteci_id, models.REMOTECIS) v1_utils.verify_existence_and_get(topic_id, models.TOPICS) # let's kill existing running jobs for the remoteci where_clause = sql.expression.and_( _TABLE.c.remoteci_id == remoteci_id, _TABLE.c.status.in_(('new', 'pre-run', 'running', 'post-run')) ) kill_query = _TABLE .update().where(where_clause).values(status='killed') flask.g.db_conn.execute(kill_query) if remoteci['state'] != 'active': message = 'RemoteCI "%s" is disabled.' % remoteci_id raise dci_exc.DCIException(message, status_code=412) # The user belongs to the topic then we can start the scheduling v1_utils.verify_team_in_topic(user, topic_id) return topic_id, remoteci
def upload_component_file(user, c_id): if not auth.is_admin(user): raise auth.UNAUTHORIZED COMPONENT_FILES = models.COMPONENT_FILES component = v1_utils.verify_existence_and_get(c_id, _TABLE) swift = dci_config.get_store('components') file_id = utils.gen_uuid() file_path = swift.build_file_path(component['topic_id'], c_id, file_id) swift = dci_config.get_store('components') swift.upload(file_path, flask.request.stream) s_file = swift.head(file_path) values = dict.fromkeys(['md5', 'mime', 'component_id', 'name']) values.update({ 'id': file_id, 'component_id': c_id, 'name': file_id, 'created_at': datetime.datetime.utcnow().isoformat(), 'md5': s_file['etag'], 'mime': s_file['content-type'], 'size': s_file['content-length'] }) query = COMPONENT_FILES.insert().values(**values) flask.g.db_conn.execute(query) result = json.dumps({'component_file': values}) return flask.Response(result, 201, content_type='application/json')
def insert_jobstate(user, values): values.update({ 'id': utils.gen_uuid(), 'created_at': datetime.datetime.utcnow().isoformat() }) query = _TABLE.insert().values(**values) flask.g.db_conn.execute(query)
def create_new_upgrade_job_from_an_existing_job(user): """Create a new job in the 'next topic' of the topic of the provided job_id.""" values = flask.request.json check_json_is_valid(upgrade_job_schema, values) values.update({ 'id': utils.gen_uuid(), 'created_at': get_utc_now().isoformat(), 'updated_at': get_utc_now().isoformat(), 'etag': utils.gen_etag(), 'status': 'new' }) original_job_id = values.pop('job_id') original_job = v1_utils.verify_existence_and_get(original_job_id, models.JOBS) if user.is_not_in_team(original_job['team_id']) and user.is_not_epm(): raise dci_exc.Unauthorized() # get the remoteci remoteci_id = str(original_job['remoteci_id']) remoteci = v1_utils.verify_existence_and_get(remoteci_id, models.REMOTECIS) values.update({'remoteci_id': remoteci_id}) # get the associated topic topic_id = str(original_job['topic_id']) topic = v1_utils.verify_existence_and_get(topic_id, models.TOPICS) values.update({ 'user_agent': flask.request.environ.get('HTTP_USER_AGENT'), 'client_version': flask.request.environ.get('HTTP_CLIENT_VERSION'), }) next_topic_id = topic['next_topic_id'] if not next_topic_id: raise dci_exc.DCIException("topic %s does not contains a next topic" % topic_id) topic = v1_utils.verify_existence_and_get(next_topic_id, models.TOPICS) product_id = topic['product_id'] # instantiate a new job in the next_topic_id # todo(yassine): make possible the upgrade to choose specific components values = _build_job(product_id, next_topic_id, remoteci, [], values, previous_job_id=original_job_id) return flask.Response(json.dumps({'job': values}), 201, headers={'ETag': values['etag']}, content_type='application/json')
def create_files(user): file_info = get_file_info_from_headers(dict(flask.request.headers)) values = dict.fromkeys( ['md5', 'mime', 'jobstate_id', 'job_id', 'name', 'test_id']) values.update(file_info) if values.get('jobstate_id') is None and values.get('job_id') is None: raise dci_exc.DCIException('HTTP headers DCI-JOBSTATE-ID or ' 'DCI-JOB-ID must be specified') if values.get('name') is None: raise dci_exc.DCIException('HTTP header DCI-NAME must be specified') if values.get('jobstate_id') and values.get('job_id') is None: jobstate = v1_utils.verify_existence_and_get(values.get('jobstate_id'), models.JOBSTATES) values['job_id'] = jobstate['job_id'] job = v1_utils.verify_existence_and_get(values.get('job_id'), models.JOBS) if (user.is_not_in_team(job['team_id']) and user.is_read_only_user() and user.is_not_epm()): raise dci_exc.Unauthorized() file_id = utils.gen_uuid() file_path = files_utils.build_file_path(job['team_id'], values['job_id'], file_id) content = files_utils.get_stream_or_content_from_request(flask.request) store = dci_config.get_store('files') store.upload(file_path, content) s_file = store.head(file_path) etag = utils.gen_etag() values.update({ 'id': file_id, 'created_at': datetime.datetime.utcnow().isoformat(), 'updated_at': datetime.datetime.utcnow().isoformat(), 'team_id': job['team_id'], 'md5': None, 'size': s_file['content-length'], 'state': 'active', 'etag': etag, }) with flask.g.db_conn.begin(): q_insert_file = _TABLE.insert().values(**values) flask.g.db_conn.execute(q_insert_file) result = json.dumps({'file': values}) if values['mime'] == 'application/junit': _, junit_file = store.get(file_path) _process_junit_file(values, junit_file, job) return flask.Response(result, 201, content_type='application/json')
def attach_issue(resource_id, table, user_id): """Attach an issue to a specific job.""" values = schemas.issue.post(flask.request.json) if 'github.com' in values['url']: type = 'github' else: type = 'bugzilla' issue_id = utils.gen_uuid() values.update({ 'id': issue_id, 'created_at': datetime.datetime.utcnow().isoformat(), 'tracker': type, }) # First, insert the issue if it doesn't already exist # in the issues table. If it already exists, ignore the # exceptions, and keep proceeding. query = _TABLE.insert().values(**values) try: flask.g.db_conn.execute(query) except sa_exc.IntegrityError: # It is not a real failure it the issue have been tried # to inserted a second time. As long as it is once, we are # good to proceed query = (sql.select([_TABLE]).where(_TABLE.c.url == values['url'])) rows = list(flask.g.db_conn.execute(query)) issue_id = rows[0][0] # the 'id' field of the issues table. # Second, insert a join record in the JOIN_JOBS_ISSUES or # JOIN_COMPONENTS_ISSUES database. if table.name == 'jobs': join_table = models.JOIN_JOBS_ISSUES else: join_table = models.JOIN_COMPONENTS_ISSUES key = '%s_id' % table.name[0:-1] query = join_table.insert().values({ 'user_id': user_id, 'issue_id': issue_id, key: resource_id }) try: flask.g.db_conn.execute(query) except sa_exc.IntegrityError: raise dci_exc.DCICreationConflict(join_table.name, '%s, issue_id' % key) result = json.dumps({'issue': values}) return flask.Response(result, 201, content_type='application/json')
def upgrade_jobs(user): values = schemas.job_upgrade.post(flask.request.json) values.update({ 'id': utils.gen_uuid(), 'created_at': datetime.datetime.utcnow().isoformat(), 'updated_at': datetime.datetime.utcnow().isoformat(), 'etag': utils.gen_etag(), 'status': 'new' }) original_job_id = values.pop('job_id') original_job = v1_utils.verify_existence_and_get(original_job_id, models.JOBS) v1_utils.verify_user_in_team(user, original_job['team_id']) # get the remoteci remoteci_id = str(original_job['remoteci_id']) remoteci = v1_utils.verify_existence_and_get(remoteci_id, models.REMOTECIS) values.update({'remoteci_id': remoteci_id}) # get the jobdefinition jobdefinition_id = str(original_job['jobdefinition_id']) jobdefinition = v1_utils.verify_existence_and_get(jobdefinition_id, models.JOBDEFINITIONS) # get the associated topic topic_id = str(jobdefinition['topic_id']) topic = v1_utils.verify_existence_and_get(topic_id, models.TOPICS) values.update({ 'user_agent': flask.request.environ.get('HTTP_USER_AGENT'), 'client_version': flask.request.environ.get( 'HTTP_CLIENT_VERSION' ), }) next_topic_id = topic['next_topic'] if not next_topic_id: raise dci_exc.DCIException( "topic %s does not contains a next topic" % topic_id) # instantiate a new job in the next_topic_id values = _build_new_template(next_topic_id, remoteci, values, previous_job_id=original_job_id) return flask.Response(json.dumps({'job': values}), 201, headers={'ETag': values['etag']}, content_type='application/json')
def create_new_update_job_from_an_existing_job(user, job_id): """Create a new job in the same topic as the job_id provided and associate the latest components of this topic.""" values = { 'id': utils.gen_uuid(), 'created_at': get_utc_now().isoformat(), 'updated_at': get_utc_now().isoformat(), 'etag': utils.gen_etag(), 'status': 'new' } original_job_id = job_id original_job = v1_utils.verify_existence_and_get(original_job_id, models.JOBS) if user.is_not_in_team(original_job['team_id']) and user.is_not_epm(): raise dci_exc.Unauthorized() # get the remoteci remoteci_id = str(original_job['remoteci_id']) remoteci = v1_utils.verify_existence_and_get(remoteci_id, models.REMOTECIS) values.update({'remoteci_id': remoteci_id}) # get the associated topic topic_id = str(original_job['topic_id']) topic = v1_utils.verify_existence_and_get(topic_id, models.TOPICS) product_id = topic['product_id'] v1_utils.verify_existence_and_get(topic_id, models.TOPICS) values.update({ 'user_agent': flask.request.environ.get('HTTP_USER_AGENT'), 'client_version': flask.request.environ.get('HTTP_CLIENT_VERSION'), }) values = _build_job(product_id, topic_id, remoteci, [], values, update_previous_job_id=original_job_id) return flask.Response(json.dumps({'job': values}), 201, headers={'ETag': values['etag']}, content_type='application/json')
def common_values_dict(): """Build a basic values object used in every create method. All our resources contain a same subset of value. Instead of redoing this code everytime, this method ensures it is done only at one place. """ now = datetime.datetime.utcnow().isoformat() etag = utils.gen_etag() values = { 'id': utils.gen_uuid(), 'created_at': now, 'updated_at': now, 'etag': etag } return values
def common_values_dict(user): """Build a basic values object used in every create method. All our resources contain a same subset of value. Instead of redoing this code everytime, this method ensures it is done only at one place. """ created_at, updated_at = utils.get_dates(user) etag = utils.gen_etag() values = { 'id': utils.gen_uuid(), 'created_at': created_at, 'updated_at': updated_at, 'etag': etag } return values
def upgrade(): op.add_column('components', sa.Column('topic_id', sa.String(36), sa.ForeignKey('topics.id', ondelete="CASCADE"), nullable=True)) op.add_column('tests', sa.Column('topic_id', sa.String(36), sa.ForeignKey('topics.id', ondelete="CASCADE"), nullable=True)) op.add_column('jobdefinitions', sa.Column('topic_id', sa.String(36), sa.ForeignKey('topics.id', ondelete="CASCADE"), nullable=True)) db_conn = op.get_bind() # Create a default topic topic_id = utils.gen_uuid() topic_values = { 'id': topic_id, 'created_at': datetime.datetime.utcnow().isoformat(), 'updated_at': datetime.datetime.utcnow().isoformat(), 'etag': utils.gen_etag(), 'name': 'default' } db_conn.execute(TOPICS.insert().values(**topic_values)) # Adds all components, jobdefinitions and tests to the default topics values = {'topic_id': topic_id} db_conn.execute(COMPONENTS.update().values(**values)) db_conn.execute(models.JOBDEFINITIONS.update().values(**values)) db_conn.execute(TESTS.update().values(**values)) # Adds all teams to the default topics all_teams = db_conn.execute(TEAMS.select()).fetchall() teams_topic = [{'topic_id': topic_id, 'team_id': team['id']} for team in all_teams] if teams_topic: db_conn.execute(models.JOINS_TOPICS_TEAMS.insert(), teams_topic)
def _process_junit_file(values, junit_file, job): jsonunit = tsfm.junit2dict(junit_file) previous_jsonunit = _get_previous_jsonunit(job, values['name']) jsonunit = _compute_regressions_successfix(jsonunit, previous_jsonunit) jsonunit = _compute_known_tests_cases(jsonunit, job) query = models.TESTS_RESULTS.insert().values({ 'id': utils.gen_uuid(), 'created_at': values['created_at'], 'updated_at': datetime.datetime.utcnow().isoformat(), 'file_id': values['id'], 'job_id': job['id'], 'name': values['name'], 'success': jsonunit['success'], 'failures': jsonunit['failures'], 'errors': jsonunit['errors'], 'regressions': jsonunit['regressions'], 'successfixes': jsonunit['successfixes'], 'skips': jsonunit['skips'], 'total': jsonunit['total'], 'time': jsonunit['time'] }) flask.g.db_conn.execute(query)
def schedule_jobs(user): """Dispatch jobs to remotecis. The remoteci can use this method to request a new job. Before a job is dispatched, the server will flag as 'killed' all the running jobs that were associated with the remoteci. This is because they will never be finished. """ values = flask.request.json check_json_is_valid(schedule_job_schema, values) values.update({ 'id': utils.gen_uuid(), 'created_at': get_utc_now().isoformat(), 'updated_at': get_utc_now().isoformat(), 'etag': utils.gen_etag(), 'status': 'new', 'remoteci_id': user.id, 'duration': 0, 'user_agent': flask.request.environ.get('HTTP_USER_AGENT'), 'client_version': flask.request.environ.get('HTTP_CLIENT_VERSION'), }) topic_id = values.pop('topic_id') dry_run = values.pop('dry_run') if dry_run: component_types = components.get_component_types_from_topic(topic_id) _components = components.get_last_components_by_type( component_types, topic_id) return flask.Response(json.dumps({ 'components': _components, 'job': None }), 201, content_type='application/json') # check remoteci remoteci = v1_utils.verify_existence_and_get(user.id, models.REMOTECIS) if remoteci['state'] != 'active': message = 'RemoteCI "%s" is disabled.' % remoteci['id'] raise dci_exc.DCIException(message, status_code=412) # check primary topic topic = v1_utils.verify_existence_and_get(topic_id, models.TOPICS) product_id = topic['product_id'] if topic['state'] != 'active': msg = 'Topic %s:%s not active.' % (topic_id, topic['name']) raise dci_exc.DCIException(msg, status_code=412) export_control.verify_access_to_topic(user, topic) # check secondary topic topic_id_secondary = values.pop('topic_id_secondary') if topic_id_secondary: topic_secondary = v1_utils.verify_existence_and_get( topic_id_secondary, models.TOPICS) if topic_secondary['state'] != 'active': msg = 'Topic %s:%s not active.' % (topic_id_secondary, topic['name']) raise dci_exc.DCIException(msg, status_code=412) export_control.verify_access_to_topic(user, topic_secondary) remotecis.kill_existing_jobs(remoteci['id']) components_ids = values.pop('components_ids') values = _build_job(product_id, topic_id, remoteci, components_ids, values, topic_id_secondary=topic_id_secondary) return flask.Response(json.dumps({'job': values}), 201, headers={'ETag': values['etag']}, content_type='application/json')
def create_files(user): file_info = get_file_info_from_headers(dict(flask.request.headers)) swift = dci_config.get_store('files') values = dict.fromkeys( ['md5', 'mime', 'jobstate_id', 'job_id', 'name', 'test_id']) values.update(file_info) if values.get('jobstate_id') is None and values.get('job_id') is None: raise dci_exc.DCIException('HTTP headers DCI-JOBSTATE-ID or ' 'DCI-JOB-ID must be specified') if values.get('name') is None: raise dci_exc.DCIException('HTTP header DCI-NAME must be specified') if values['jobstate_id']: query = v1_utils.QueryBuilder(models.JOBSTATES) query.add_extra_condition( models.JOBSTATES.c.id == values['jobstate_id']) row = query.execute(fetchone=True) if row is None: raise dci_exc.DCINotFound('Jobstate', values['jobstate_id']) values['job_id'] = row['jobstates_job_id'] query = v1_utils.QueryBuilder(models.JOBS) if not auth.is_admin(user): query.add_extra_condition(models.JOBS.c.team_id == user['team_id']) query.add_extra_condition(models.JOBS.c.id == values['job_id']) row = query.execute(fetchone=True) if row is None: raise dci_exc.DCINotFound('Job', values['job_id']) file_id = utils.gen_uuid() # ensure the directory which will contains the file actually exist file_path = swift.build_file_path(user['team_id'], values['job_id'], file_id) content = files.get_stream_or_content_from_request(flask.request) swift.upload(file_path, content) s_file = swift.head(file_path) etag = utils.gen_etag() values.update({ 'id': file_id, 'created_at': datetime.datetime.utcnow().isoformat(), 'updated_at': datetime.datetime.utcnow().isoformat(), 'team_id': user['team_id'], 'md5': None, 'size': s_file['content-length'], 'state': 'active', 'etag': etag, }) query = _TABLE.insert().values(**values) with flask.g.db_conn.begin(): flask.g.db_conn.execute(query) result = json.dumps({'file': values}) if values['mime'] == 'application/junit': _, file_descriptor = swift.get(file_path) junit = tsfm.junit2dict(file_descriptor.read()) query = models.TESTS_RESULTS.insert().values({ 'id': utils.gen_uuid(), 'created_at': values['created_at'], 'updated_at': datetime.datetime.utcnow().isoformat(), 'file_id': file_id, 'job_id': values['job_id'], 'name': values['name'], 'success': junit['success'], 'failures': junit['failures'], 'errors': junit['errors'], 'skips': junit['skips'], 'total': junit['total'], 'time': junit['time'] }) flask.g.db_conn.execute(query) files_events.create_event(file_id, models.FILES_CREATE) return flask.Response(result, 201, content_type='application/json')
def upgrade(): op.create_table( 'components', sa.Column('id', sa.String(36), primary_key=True, default=utils.gen_uuid), sa.Column('created_at', sa.DateTime(), default=datetime.datetime.utcnow, nullable=False), sa.Column('updated_at', sa.DateTime(), onupdate=datetime.datetime.utcnow, default=datetime.datetime.utcnow, nullable=False), sa.Column('etag', sa.String(40), nullable=False, default=utils.gen_etag, onupdate=utils.gen_etag), sa.Column('name', sa.String(255), unique=True, nullable=False), sa.Column('type', sa.String(255), nullable=False), sa.Column('canonical_project_name', sa.String), sa.Column('data', sa_utils.JSONType), sa.Column('sha', sa.Text), sa.Column('title', sa.Text), sa.Column('message', sa.Text), sa.Column('url', sa.Text), sa.Column('git', sa.Text), sa.Column('ref', sa.Text)) op.create_table( 'tests', sa.Column('id', sa.String(36), primary_key=True, default=utils.gen_uuid), sa.Column('created_at', sa.DateTime(), default=datetime.datetime.utcnow, nullable=False), sa.Column('updated_at', sa.DateTime(), onupdate=datetime.datetime.utcnow, default=datetime.datetime.utcnow, nullable=False), sa.Column('name', sa.String(255), nullable=False, unique=True), sa.Column('etag', sa.String(40), nullable=False, default=utils.gen_etag, onupdate=utils.gen_etag), sa.Column('data', sa_utils.JSONType)) op.create_table( 'jobdefinitions', sa.Column('id', sa.String(36), primary_key=True, default=utils.gen_uuid), sa.Column('created_at', sa.DateTime(), default=datetime.datetime.utcnow, nullable=False), sa.Column('updated_at', sa.DateTime(), onupdate=datetime.datetime.utcnow, default=datetime.datetime.utcnow, nullable=False), sa.Column('etag', sa.String(40), nullable=False, default=utils.gen_etag, onupdate=utils.gen_etag), sa.Column('name', sa.String(255)), sa.Column('priority', sa.Integer, default=0), sa.Column('test_id', sa.String(36), sa.ForeignKey('tests.id', ondelete="CASCADE"), nullable=False)) op.create_table( 'jobdefinition_components', sa.Column('id', sa.String(36), primary_key=True, default=utils.gen_uuid), sa.Column('created_at', sa.DateTime(), default=datetime.datetime.utcnow, nullable=False), sa.Column('updated_at', sa.DateTime(), onupdate=datetime.datetime.utcnow, default=datetime.datetime.utcnow, nullable=False), sa.Column('etag', sa.String(40), nullable=False, default=utils.gen_etag, onupdate=utils.gen_etag), sa.Column('component_id', sa.String(36), sa.ForeignKey('components.id', ondelete="CASCADE"), nullable=False), sa.Column('jobdefinition_id', sa.String(36), sa.ForeignKey('jobdefinitions.id', ondelete="CASCADE"), nullable=False), sa.UniqueConstraint('component_id', 'jobdefinition_id')) op.create_table( 'teams', sa.Column('id', sa.String(36), primary_key=True, default=utils.gen_uuid), sa.Column('created_at', sa.DateTime(), default=datetime.datetime.utcnow, nullable=False), sa.Column('updated_at', sa.DateTime(), onupdate=datetime.datetime.utcnow, default=datetime.datetime.utcnow, nullable=False), sa.Column('etag', sa.String(40), nullable=False, default=utils.gen_etag, onupdate=utils.gen_etag), sa.Column('name', sa.String(255), unique=True, nullable=False)) op.create_table( 'remotecis', sa.Column('id', sa.String(36), primary_key=True, default=utils.gen_uuid), sa.Column('created_at', sa.DateTime(), default=datetime.datetime.utcnow, nullable=False), sa.Column('updated_at', sa.DateTime(), onupdate=datetime.datetime.utcnow, default=datetime.datetime.utcnow, nullable=False), sa.Column('etag', sa.String(40), nullable=False, default=utils.gen_etag, onupdate=utils.gen_etag), sa.Column('name', sa.String(255), unique=True), sa.Column('data', sa_utils.JSONType), sa.Column('active', sa.BOOLEAN, default=True), sa.Column('team_id', sa.String(36), sa.ForeignKey('teams.id', ondelete="CASCADE"), nullable=False)) op.create_table( 'jobs', sa.Column('id', sa.String(36), primary_key=True, default=utils.gen_uuid), sa.Column('created_at', sa.DateTime(), default=datetime.datetime.utcnow, nullable=False), sa.Column('updated_at', sa.DateTime(), onupdate=datetime.datetime.utcnow, default=datetime.datetime.utcnow, nullable=False), sa.Column('etag', sa.String(40), nullable=False, default=utils.gen_etag, onupdate=utils.gen_etag), sa.Column('recheck', sa.Boolean, default=False), # new, pre-run, running, post-run, success, failure sa.Column('status', sa.String(255), default='new'), sa.Column('jobdefinition_id', sa.String(36), sa.ForeignKey('jobdefinitions.id', ondelete="CASCADE"), nullable=False), sa.Column('remoteci_id', sa.String(36), sa.ForeignKey('remotecis.id', ondelete="CASCADE"), nullable=False), sa.Column('team_id', sa.String(36), sa.ForeignKey('teams.id', ondelete="CASCADE"), nullable=False)) op.create_table( 'jobstates', sa.Column('id', sa.String(36), primary_key=True, default=utils.gen_uuid), sa.Column('created_at', sa.DateTime(), default=datetime.datetime.utcnow, nullable=False), sa.Column('updated_at', sa.DateTime(), onupdate=datetime.datetime.utcnow, default=datetime.datetime.utcnow, nullable=False), sa.Column('etag', sa.String(40), nullable=False, default=utils.gen_etag, onupdate=utils.gen_etag), # new, pre-run, running, post-run, success, failure sa.Column('status', sa.String(255), nullable=False), sa.Column('comment', sa.Text), sa.Column('job_id', sa.String(36), sa.ForeignKey('jobs.id', ondelete="CASCADE"), nullable=False), sa.Column('team_id', sa.String(36), sa.ForeignKey('teams.id', ondelete="CASCADE"), nullable=False)) op.create_table( 'files', sa.Column('id', sa.String(36), primary_key=True, default=utils.gen_uuid), sa.Column('created_at', sa.DateTime(), default=datetime.datetime.utcnow, nullable=False), sa.Column('updated_at', sa.DateTime(), onupdate=datetime.datetime.utcnow, default=datetime.datetime.utcnow, nullable=False), sa.Column('etag', sa.String(40), nullable=False, default=utils.gen_etag, onupdate=utils.gen_etag), sa.Column('name', sa.String(255), nullable=False), sa.Column('content', sa.Text, nullable=False), sa.Column('mime', sa.String), sa.Column('md5', sa.String(32)), sa.Column('jobstate_id', sa.String(36), sa.ForeignKey('jobstates.id', ondelete="CASCADE"), nullable=False), sa.Column('team_id', sa.String(36), sa.ForeignKey('teams.id', ondelete="CASCADE"), nullable=False)) op.create_table( 'users', sa.Column('id', sa.String(36), primary_key=True, default=utils.gen_uuid), sa.Column('created_at', sa.DateTime(), default=datetime.datetime.utcnow, nullable=False), sa.Column('updated_at', sa.DateTime(), onupdate=datetime.datetime.utcnow, default=datetime.datetime.utcnow, nullable=False), sa.Column('etag', sa.String(40), nullable=False, default=utils.gen_etag, onupdate=utils.gen_etag), sa.Column('name', sa.String(255), unique=True, nullable=False), sa.Column('password', sa.Text, nullable=False), sa.Column('role', sa.String(255), default='user', nullable=False), sa.Column('team_id', sa.String(36), sa.ForeignKey('teams.id', ondelete="CASCADE"), nullable=False)) op.create_table( 'user_remotecis', sa.Column('id', sa.String(36), primary_key=True, default=utils.gen_uuid), sa.Column('created_at', sa.DateTime(), default=datetime.datetime.utcnow, nullable=False), sa.Column('updated_at', sa.DateTime(), onupdate=datetime.datetime.utcnow, default=datetime.datetime.utcnow, nullable=False), sa.Column('etag', sa.String(40), nullable=False, default=utils.gen_etag, onupdate=utils.gen_etag), sa.Column('user_id', sa.String(36), sa.ForeignKey('users.id', ondelete="CASCADE"), nullable=False), sa.Column('remoteci_id', sa.String(36), sa.ForeignKey('remotecis.id', ondelete="CASCADE"), nullable=False), sa.UniqueConstraint('user_id', 'remoteci_id')) db_conn = op.get_bind() team_id = utils.gen_uuid() team_values = { 'id': team_id, 'created_at': datetime.datetime.utcnow().isoformat(), 'updated_at': datetime.datetime.utcnow().isoformat(), 'etag': utils.gen_etag(), 'name': 'admin' } db_conn.execute(TEAMS.insert().values(**team_values)) user_id = utils.gen_uuid() user_values = { 'id': user_id, 'created_at': datetime.datetime.utcnow().isoformat(), 'updated_at': datetime.datetime.utcnow().isoformat(), 'etag': utils.gen_etag(), 'name': 'admin', 'role': 'admin', 'team_id': team_id, 'password': auth.hash_password('admin'), } db_conn.execute(USERS.insert().values(**user_values))
def upgrade(): op.add_column('users', sa.Column('role_id', pg.UUID(as_uuid=True), sa.ForeignKey('roles.id', ondelete='SET NULL'))) db_conn = op.get_bind() team_admin_id = str( db_conn.execute( TEAMS.select().where(TEAMS.c.name == 'admin') ).fetchone()['id'] ) super_admin_role_id = utils.gen_uuid() super_admin_role = { 'id': super_admin_role_id, 'created_at': datetime.datetime.utcnow().isoformat(), 'updated_at': datetime.datetime.utcnow().isoformat(), 'etag': utils.gen_etag(), 'name': 'Super Admin', 'label': 'SUPER_ADMIN', 'description': 'Admin of the platform', } admin_role_id = utils.gen_uuid() admin_role = { 'id': admin_role_id, 'created_at': datetime.datetime.utcnow().isoformat(), 'updated_at': datetime.datetime.utcnow().isoformat(), 'etag': utils.gen_etag(), 'name': 'Admin', 'label': 'ADMIN', 'description': 'Admin of a team', } user_role_id = utils.gen_uuid() user_role = { 'id': user_role_id, 'created_at': datetime.datetime.utcnow().isoformat(), 'updated_at': datetime.datetime.utcnow().isoformat(), 'etag': utils.gen_etag(), 'name': 'User', 'label': 'USER', 'description': 'Regular User', } db_conn.execute(ROLES.insert().values(**super_admin_role)) db_conn.execute(ROLES.insert().values(**admin_role)) db_conn.execute(ROLES.insert().values(**user_role)) db_conn.execute( USERS.update(). where(sql.and_(USERS.c.role == 'admin', USERS.c.team_id == team_admin_id)). values(role_id=super_admin_role_id) ) db_conn.execute( USERS.update(). where(sql.and_(USERS.c.role == 'admin', USERS.c.team_id != team_admin_id)). values(role_id=admin_role_id) ) db_conn.execute( USERS.update().where(USERS.c.role == 'user'). values(role_id=user_role_id) )