blob: e353902e39169cac1fabcc9eca2a390e11dbbb79 [file] [log] [blame]
# Copyright 2017 Google Inc. All rights reserved.
#
# 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.
"""Schedule Info APIs implemented using Google Cloud Endpoints."""
import datetime
import endpoints
from google.appengine.ext import ndb
from webapp.src import vtslab_status as Status
from webapp.src.endpoint import endpoint_base
from webapp.src.proto import model
from webapp.src.utils import email_util
SCHEDULE_INFO_RESOURCE = endpoints.ResourceContainer(model.ScheduleInfoMessage)
SCHEDULE_SUSPEND_RESOURCE = endpoints.ResourceContainer(
model.ScheduleSuspendMessage)
@endpoints.api(name="schedule", version="v1")
class ScheduleInfoApi(endpoint_base.EndpointBase):
"""Endpoint API for schedule_info."""
@endpoints.method(
SCHEDULE_INFO_RESOURCE,
model.DefaultResponse,
path="clear",
http_method="POST",
name="clear")
def clear(self, request):
"""Clears test schedule info in DB."""
schedule_query = model.ScheduleModel.query(
model.ScheduleModel.schedule_type != "green")
existing_schedules = schedule_query.fetch(keys_only=True)
if existing_schedules and len(existing_schedules) > 0:
ndb.delete_multi(existing_schedules)
return model.DefaultResponse(
return_code=model.ReturnCodeMessage.SUCCESS)
@endpoints.method(
SCHEDULE_INFO_RESOURCE,
model.DefaultResponse,
path="set",
http_method="POST",
name="set")
def set(self, request):
"""Sets the schedule info based on `request`."""
exist_on_both = self.GetCommonAttributes(request, model.ScheduleModel)
# check duplicates
exclusions = [
"name", "schedule_type", "schedule", "param", "timestamp",
"children_jobs", "error_count", "suspended"
]
# list of protorpc message fields.
duplicate_checklist = [x for x in exist_on_both if x not in exclusions]
empty_list_field = []
query = model.ScheduleModel.query()
for attr_name in duplicate_checklist:
if model.ScheduleModel._properties[attr_name]._repeated:
value = request.get_assigned_value(attr_name)
if value:
query = query.filter(
getattr(model.ScheduleModel, attr_name).IN(
request.get_assigned_value(attr_name)))
else:
# empty list cannot be queried.
empty_list_field.append(attr_name)
else:
query = query.filter(
getattr(model.ScheduleModel, attr_name) ==
request.get_assigned_value(attr_name))
duplicated_schedules = query.fetch()
if empty_list_field:
duplicated_schedules = [
schedule for schedule in duplicated_schedules
if all(
[not getattr(schedule, attr) for attr in empty_list_field])
]
if duplicated_schedules:
schedule = duplicated_schedules[0]
else:
schedule = model.ScheduleModel()
for attr_name in exist_on_both:
setattr(schedule, attr_name,
request.get_assigned_value(attr_name))
schedule.schedule_type = "test"
schedule.error_count = 0
schedule.suspended = False
schedule.priority_value = Status.GetPriorityValue(schedule.priority)
schedule.timestamp = datetime.datetime.now()
schedule.put()
return model.DefaultResponse(
return_code=model.ReturnCodeMessage.SUCCESS)
@endpoints.method(
endpoint_base.GET_REQUEST_RESOURCE,
model.ScheduleResponseMessage,
path="get",
http_method="POST",
name="get")
def get(self, request):
"""Gets the schedules from datastore."""
return_list, more = self.Get(request=request,
metaclass=model.ScheduleModel,
message=model.ScheduleInfoMessage)
return model.ScheduleResponseMessage(
schedules=return_list, has_next=more)
@endpoints.method(
endpoint_base.COUNT_REQUEST_RESOURCE,
model.CountResponseMessage,
path="count",
http_method="POST",
name="count")
def count(self, request):
"""Gets total number of ScheduleModel entities stored in datastore."""
filters = self.CreateFilterList(
filter_string=request.filter, metaclass=model.ScheduleModel)
count = self.Count(metaclass=model.ScheduleModel, filters=filters)
return model.CountResponseMessage(count=count)
@endpoints.method(
SCHEDULE_SUSPEND_RESOURCE,
model.ScheduleSuspendMessage,
path="suspend",
http_method="POST",
name="suspend")
def suspend(self, request):
"""Toggles a schedule from suspend to resume, or vice versa."""
schedules_to_put = []
schedules_to_return = []
for schedule in request.schedules:
schedule_key = ndb.key.Key(urlsafe=schedule.urlsafe_key)
schedule_entity = schedule_key.get()
if schedule.suspend: # to suspend
schedule_entity.suspended = True
else: # to resume
schedule_entity.error_count = 0
schedule_entity.suspended = False
schedules_to_put.append(schedule_entity)
schedules_to_return.append({"urlsafe_key": schedule.urlsafe_key,
"suspend": schedule_entity.suspended})
# TODO(jongmok): Minimize a number of emails by merging schedules.
email_util.send_schedule_suspension_notification(schedule_entity)
ndb.put_multi(schedules_to_put)
return model.ScheduleSuspendMessage(schedules=schedules_to_return)
@endpoints.api(name="green_schedule_info", version="v1")
class GreenScheduleInfoApi(endpoint_base.EndpointBase):
"""Endpoint API for green_schedule_info."""
@endpoints.method(
SCHEDULE_INFO_RESOURCE,
model.DefaultResponse,
path="clear",
http_method="POST",
name="clear")
def clear(self, request):
"""Clears green build schedule info in DB."""
schedule_query = model.ScheduleModel.query(
model.ScheduleModel.schedule_type == "green")
existing_schedules = schedule_query.fetch(keys_only=True)
if existing_schedules and len(existing_schedules) > 0:
ndb.delete_multi(existing_schedules)
return model.DefaultResponse(
return_code=model.ReturnCodeMessage.SUCCESS)
@endpoints.method(
SCHEDULE_INFO_RESOURCE,
model.DefaultResponse,
path="set",
http_method="POST",
name="set")
def set(self, request):
"""Sets the green build schedule info based on `request`."""
schedule = model.ScheduleModel()
schedule.name = request.name
schedule.manifest_branch = request.manifest_branch
schedule.build_target = request.build_target
schedule.device_pab_account_id = request.device_pab_account_id
schedule.test_name = request.test_name
schedule.schedule = request.schedule
schedule.priority = request.priority
schedule.device = request.device
schedule.shards = request.shards
schedule.gsi_branch = request.gsi_branch
schedule.gsi_build_target = request.gsi_build_target
schedule.gsi_pab_account_id = request.gsi_pab_account_id
schedule.gsi_vendor_version = request.gsi_vendor_version
schedule.test_branch = request.test_branch
schedule.test_build_target = request.test_build_target
schedule.test_pab_account_id = request.test_pab_account_id
schedule.timestamp = datetime.datetime.now()
schedule.schedule_type = "green"
schedule.put()
return model.DefaultResponse(
return_code=model.ReturnCodeMessage.SUCCESS)