Merge "Parse function alias when job is running"

This commit is contained in:
Zuul 2019-07-18 13:21:54 +00:00 committed by Gerrit Code Review
commit 05387ff01a
8 changed files with 131 additions and 41 deletions

View File

@ -152,5 +152,5 @@ class FunctionAliasesController(rest.RestController):
alias = db_api.update_function_alias(alias_name, **values) alias = db_api.update_function_alias(alias_name, **values)
LOG.info("Alias updated.") LOG.info("Alias %s updated.", alias_name)
return resources.FunctionAlias.from_db_obj(alias) return resources.FunctionAlias.from_db_obj(alias)

View File

@ -56,37 +56,37 @@ class JobsController(rest.RestController):
'Either function_alias or function_id must be provided.' 'Either function_alias or function_id must be provided.'
) )
# Check the input params.
first_time, next_time, count = jobs.validate_job(params)
LOG.info("Creating %s, params: %s", self.type, params) LOG.info("Creating %s, params: %s", self.type, params)
version = params.get('function_version', 0) # Check the input params.
# if function_alias provided first_time, next_time, count = jobs.validate_job(params)
function_alias = params.get('function_alias')
if function_alias:
alias_db = db_api.get_function_alias(function_alias)
function_id = alias_db.function_id
version = alias_db.function_version
params.update({'function_id': function_id,
'version': version})
with db_api.transaction(): version = params.get('function_version', 0)
function_alias = params.get('function_alias')
if function_alias:
# Check if the alias exists.
db_api.get_function_alias(function_alias)
else:
# Check the function(version) exists.
db_api.get_function(params['function_id']) db_api.get_function(params['function_id'])
if version > 0: if version > 0:
# Check if the version exists.
db_api.get_function_version(params['function_id'], version) db_api.get_function_version(params['function_id'], version)
values = { values = {
'name': params.get('name'), 'name': params.get('name'),
'pattern': params.get('pattern'), 'pattern': params.get('pattern'),
'first_execution_time': first_time, 'first_execution_time': first_time,
'next_execution_time': next_time, 'next_execution_time': next_time,
'count': count, 'count': count,
'function_id': params['function_id'], 'function_alias': function_alias,
'function_version': version, 'function_id': params.get("function_id"),
'function_input': params.get('function_input'), 'function_version': version,
'status': status.RUNNING 'function_input': params.get('function_input'),
} 'status': status.RUNNING
db_job = db_api.create_job(values) }
db_job = db_api.create_job(values)
return resources.Job.from_db_obj(db_job) return resources.Job.from_db_obj(db_job)

View File

@ -0,0 +1,34 @@
# Copyright 2019 Catalyst Cloud Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Make function id nullable for jobs table
Revision ID: 007
Revises: 006
"""
revision = '007'
down_revision = '006'
from alembic import op
import sqlalchemy as sa
def upgrade():
op.alter_column(
'jobs',
'function_id',
existing_type=sa.String(length=36),
nullable=True
)

View File

@ -73,7 +73,8 @@ class Job(model_base.QinlingSecureModelBase):
count = sa.Column(sa.Integer) count = sa.Column(sa.Integer)
function_id = sa.Column( function_id = sa.Column(
sa.String(36), sa.String(36),
sa.ForeignKey(Function.id) sa.ForeignKey(Function.id),
nullable=True
) )
function = relationship('Function', back_populates="jobs") function = relationship('Function', back_populates="jobs")
function_input = sa.Column(sa.String(255), nullable=True) function_input = sa.Column(sa.String(255), nullable=True)

View File

@ -98,8 +98,16 @@ def handle_job(engine_client):
for job in jobs_db: for job in jobs_db:
job_id = job.id job_id = job.id
func_id = job.function_id func_alias = job.function_alias
func_version = job.function_version
if func_alias:
alias = db_api.get_function_alias(func_alias, insecure=True)
func_id = alias.function_id
func_version = alias.function_version
else:
func_id = job.function_id
func_version = job.function_version
LOG.debug("Processing job: %s, function: %s(version %s)", job_id, LOG.debug("Processing job: %s, function: %s(version %s)", job_id,
func_id, func_version) func_id, func_version)

View File

@ -32,7 +32,7 @@ class TestJobController(base.APITest):
db_function = self.create_function() db_function = self.create_function()
self.function_id = db_function.id self.function_id = db_function.id
def test_post(self): def test_create_with_function(self):
body = { body = {
'name': self.rand_name('job', prefix=self.prefix), 'name': self.rand_name('job', prefix=self.prefix),
'first_execution_time': str( 'first_execution_time': str(
@ -43,7 +43,7 @@ class TestJobController(base.APITest):
self.assertEqual(201, resp.status_int) self.assertEqual(201, resp.status_int)
def test_post_with_version(self): def test_create_with_version(self):
db_api.increase_function_version(self.function_id, 0) db_api.increase_function_version(self.function_id, 0)
body = { body = {
@ -58,13 +58,10 @@ class TestJobController(base.APITest):
self.assertEqual(201, resp.status_int) self.assertEqual(201, resp.status_int)
self.assertEqual(1, resp.json.get('function_version')) self.assertEqual(1, resp.json.get('function_version'))
def test_post_with_alias(self): def test_create_with_alias(self):
db_api.increase_function_version(self.function_id, 0,
description="version 1")
name = self.rand_name(name="alias", prefix=self.prefix) name = self.rand_name(name="alias", prefix=self.prefix)
body = { body = {
'function_id': self.function_id, 'function_id': self.function_id,
'function_version': 1,
'name': name 'name': name
} }
db_api.create_function_alias(**body) db_api.create_function_alias(**body)
@ -79,9 +76,21 @@ class TestJobController(base.APITest):
resp = self.app.post_json('/v1/jobs', job_body) resp = self.app.post_json('/v1/jobs', job_body)
self.assertEqual(201, resp.status_int) self.assertEqual(201, resp.status_int)
self.assertEqual(1, resp.json.get('function_version')) self.assertEqual(name, resp.json.get('function_alias'))
self.assertIsNone(resp.json.get('function_id'))
def test_post_without_required_params(self): def test_create_with_invalid_alias(self):
body = {
'function_alias': 'fake_alias',
'first_execution_time': str(
datetime.utcnow() + timedelta(hours=1)),
}
resp = self.app.post_json('/v1/jobs', body, expect_errors=True)
self.assertEqual(404, resp.status_int)
def test_create_without_required_params(self):
resp = self.app.post( resp = self.app.post(
'/v1/jobs', '/v1/jobs',
params={}, params={},
@ -90,7 +99,7 @@ class TestJobController(base.APITest):
self.assertEqual(400, resp.status_int) self.assertEqual(400, resp.status_int)
def test_post_pattern(self): def test_create_pattern(self):
body = { body = {
'name': self.rand_name('job', prefix=self.prefix), 'name': self.rand_name('job', prefix=self.prefix),
'function_id': self.function_id, 'function_id': self.function_id,
@ -107,7 +116,7 @@ class TestJobController(base.APITest):
res["next_execution_time"] res["next_execution_time"]
) )
def test_post_both_pattern_and_first_execution_time(self): def test_create_both_pattern_and_first_execution_time(self):
body = { body = {
'name': self.rand_name('job', prefix=self.prefix), 'name': self.rand_name('job', prefix=self.prefix),
'function_id': self.function_id, 'function_id': self.function_id,

View File

@ -203,12 +203,13 @@ class DbTestCase(BaseTest):
return function return function
def create_job(self, function_id=None, **kwargs): def create_job(self, function_id=None, function_alias=None, **kwargs):
if not function_id: if not function_id and not function_alias:
function_id = self.create_function().id function_id = self.create_function().id
job_params = { job_params = {
'name': self.rand_name('job', prefix=self.prefix), 'name': self.rand_name('job', prefix=self.prefix),
'function_alias': function_alias,
'function_id': function_id, 'function_id': function_id,
# 'auth_enable' is disabled by default # 'auth_enable' is disabled by default
'project_id': DEFAULT_PROJECT_ID, 'project_id': DEFAULT_PROJECT_ID,

View File

@ -117,7 +117,7 @@ class TestPeriodics(base.DbTestCase):
now = datetime.utcnow() now = datetime.utcnow()
db_job = self.create_job( db_job = self.create_job(
function_id, function_id=function_id,
status=status.RUNNING, status=status.RUNNING,
next_execution_time=now, next_execution_time=now,
count=2 count=2
@ -197,3 +197,40 @@ class TestPeriodics(base.DbTestCase):
db_execs = db_api.get_executions(function_id=function_id, db_execs = db_api.get_executions(function_id=function_id,
function_version=1) function_version=1)
self.assertEqual(2, len(db_execs)) self.assertEqual(2, len(db_execs))
@mock.patch('qinling.utils.jobs.get_next_execution_time')
def test_job_handler_with_alias(self, mock_next_time):
e_client = mock.Mock()
now = datetime.utcnow()
# It doesn't matter what's the returned value, but need to be in
# datetime type.
mock_next_time.return_value = now + timedelta(seconds=1)
# Create a alias for a function.
alias_name = self.rand_name(name="alias", prefix=self.prefix)
db_func = self.create_function()
function_id = db_func.id
db_api.create_function_alias(name=alias_name, function_id=function_id)
self.create_job(
function_alias=alias_name,
status=status.RUNNING,
next_execution_time=now,
)
periodics.handle_job(e_client)
context.set_ctx(self.ctx)
# Create function version 1 and update the alias.
db_api.increase_function_version(function_id, 0)
db_api.update_function_alias(alias_name, function_version=1)
periodics.handle_job(e_client)
context.set_ctx(self.ctx)
db_func = db_api.get_function(function_id)
self.assertEqual(1, db_func.count)
db_version = db_api.get_function_version(function_id, 1)
self.assertEqual(1, db_version.count)
db_execs = db_api.get_executions(function_id=function_id)
self.assertEqual(2, len(db_execs))