Skip to content

Commit

Permalink
bug 1310217: Make Agent Aware of Release and Permissions Scheduled Ch…
Browse files Browse the repository at this point in the history
…anges (#214). r=bhearsum
  • Loading branch information
nurav authored and bhearsum committed Jan 23, 2017
1 parent 870a1dc commit eda43c6
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 44 deletions.
63 changes: 35 additions & 28 deletions agent/balrogagent/cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,43 +7,50 @@
from .changes import get_telemetry_uptake, telemetry_is_ready, time_is_ready
from .log import configure_logging

SCHEDULED_CHANGE_ENDPOINTS = ['rules',
'releases',
'permissions']


async def run_agent(loop, balrog_api_root, balrog_username, balrog_password, telemetry_api_root, sleeptime=30,
once=False, raise_exceptions=False):
auth = aiohttp.BasicAuth(balrog_username, balrog_password)

while True:
try:
logging.debug("Looking for active scheduled changes...")
resp = await client.request(balrog_api_root, "/scheduled_changes/rules", auth=auth, loop=loop)
sc = (await resp.json())["scheduled_changes"]
resp.close()
logging.debug("Found %s", len(sc))
for change in sc:
logging.debug("Processing change %s", change["sc_id"])
ready = False
for endpoint in SCHEDULED_CHANGE_ENDPOINTS:
logging.debug("Looking for active scheduled changes for endpoint %s..." % endpoint)
resp = await client.request(balrog_api_root,
"/scheduled_changes/%s" % endpoint,
auth=auth, loop=loop)
sc = (await resp.json())["scheduled_changes"]
resp.close()
logging.debug("Found %s", len(sc))
for change in sc:
logging.debug("Processing change %s", change["sc_id"])
ready = False

# Figure out if the change is ready, which is type-specific.
if change["telemetry_uptake"]:
# TODO: maybe replace this with a simple client.request()...
current_uptake = await get_telemetry_uptake(change["telemetry_product"], change["telemetry_channel"], loop=loop)
ready = telemetry_is_ready(change, current_uptake)
elif change["when"]:
# "when" is to-the-millisecond timestamp that gets stored as an int.
# It needs to be converted back to a float before it can be compared
# against other timestamps.
ready = time_is_ready(change, time.time())
else:
logging.debug("Unknown change type!")
# Figure out if the change is ready, which is type-specific.
if change.get("telemetry_uptake"):
# TODO: maybe replace this with a simple client.request()...
current_uptake = await get_telemetry_uptake(change["telemetry_product"], change["telemetry_channel"], loop=loop)
ready = telemetry_is_ready(change, current_uptake)
elif change["when"]:
# "when" is to-the-millisecond timestamp that gets stored as an int.
# It needs to be converted back to a float before it can be compared
# against other timestamps.
ready = time_is_ready(change, time.time())
else:
logging.debug("Unknown change type!")

# If it *is* ready, enact it!
if ready:
logging.debug("Change %s is ready, enacting", change["sc_id"])
endpoint = "/scheduled_changes/rules/{}/enact".format(change["sc_id"])
resp = await client.request(balrog_api_root, endpoint, method="POST", auth=auth, loop=loop)
resp.close()
else:
logging.debug("Change %s is not ready", change["sc_id"])
# If it *is* ready, enact it!
if ready:
logging.debug("Change %s is ready, enacting", change["sc_id"])
endpoint = "/scheduled_changes/{}/{}/enact".format(endpoint, change["sc_id"])
resp = await client.request(balrog_api_root, endpoint, method="POST", auth=auth, loop=loop)
resp.close()
else:
logging.debug("Change %s is not ready", change["sc_id"])

except:
logging.error("Encountered exception:", exc_info=True)
Expand Down
94 changes: 78 additions & 16 deletions agent/balrogagent/test/test_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,56 +14,118 @@ def setUp(self):
self.loop = asyncio.get_event_loop()

async def _runAgent(self, scheduled_changes, request):
request.return_value = aiohttp.client.ClientResponse("GET", "http://balrog.fake/api/scheduled_changes")
request.return_value.headers = {"Content-Type": "application/json"}
body = {"count": len(scheduled_changes), "scheduled_changes": scheduled_changes}
request.return_value._content = bytes(json.dumps(body), "utf-8")
def side_effect(balrog_api_root, endpoint, auth, loop, method='GET'):
endpoint = endpoint.split('/')[-1]
response = aiohttp.client.ClientResponse("GET",
"http://balrog.fake/scheduled_changes/%s" % endpoint)
response.headers = {"Content-Type": "application/json"}
changes = scheduled_changes.get(endpoint) or []
if method != 'GET':
body = ""
else:
body = {"count": len(changes), "scheduled_changes": changes}
response._content = bytes(json.dumps(body), "utf-8")
return response

request.side_effect = side_effect

return await run_agent(self.loop, "http://balrog.fake", "balrog", "balrog", "telemetry", once=True, raise_exceptions=True)

async def testNoChanges(self, time_is_ready, telemetry_is_ready, request):
sc = []
sc = {}
await self._runAgent(sc, request)
self.assertEquals(telemetry_is_ready.call_count, 0)
self.assertEquals(time_is_ready.call_count, 0)
self.assertEquals(request.call_count, 1)
self.assertEquals(request.call_count, 3)

@asynctest.patch("time.time")
async def testTimeBasedNotReadyRules(self, time, time_is_ready, telemetry_is_ready, request):
time.return_value = 0
time_is_ready.return_value = False
sc = {'rules': [{"sc_id": 4, "when": 23456789, "telemetry_uptake": None, "telemetry_product": None, "telemetry_channel": None}]}
await self._runAgent(sc, request)
self.assertEquals(telemetry_is_ready.call_count, 0)
self.assertEquals(time_is_ready.call_count, 1)
self.assertEquals(request.call_count, 3)

@asynctest.patch("time.time")
async def testTimeBasedNotReadyReleases(self, time, time_is_ready, telemetry_is_ready, request):
time.return_value = 0
time_is_ready.return_value = False
sc = {'releases': [{"sc_id": 4, "when": 23456789, "telemetry_uptake": None, "telemetry_product": None, "telemetry_channel": None}]}
await self._runAgent(sc, request)
self.assertEquals(telemetry_is_ready.call_count, 0)
self.assertEquals(time_is_ready.call_count, 1)
self.assertEquals(request.call_count, 3)

@asynctest.patch("time.time")
async def testTimeBasedNotReady(self, time, time_is_ready, telemetry_is_ready, request):
async def testTimeBasedNotReadyPermissions(self, time, time_is_ready, telemetry_is_ready, request):
time.return_value = 0
time_is_ready.return_value = False
sc = [{"sc_id": 4, "when": 23456789, "telemetry_uptake": None, "telemetry_product": None, "telemetry_channel": None}]
sc = {'permissions': [{"sc_id": 4, "when": 23456789, "telemetry_uptake": None, "telemetry_product": None, "telemetry_channel": None}]}
await self._runAgent(sc, request)
self.assertEquals(telemetry_is_ready.call_count, 0)
self.assertEquals(time_is_ready.call_count, 1)
self.assertEquals(request.call_count, 1)
self.assertEquals(request.call_count, 3)

@asynctest.patch("time.time")
async def testTimeBasedIsReady(self, time, time_is_ready, telemetry_is_ready, request):
async def testTimeBasedIsReadyRules(self, time, time_is_ready, telemetry_is_ready, request):
time.return_value = 999999999
time_is_ready.return_value = True
sc = [{"sc_id": 4, "when": 234, "telemetry_uptake": None, "telemetry_product": None, "telemetry_channel": None}]
sc = {'rules': [{"sc_id": 4, "when": 234, "telemetry_uptake": None, "telemetry_product": None, "telemetry_channel": None}]}
await self._runAgent(sc, request)
self.assertEquals(telemetry_is_ready.call_count, 0)
self.assertEquals(time_is_ready.call_count, 1)
self.assertEquals(request.call_count, 2)
self.assertEquals(request.call_count, 4)

@asynctest.patch("time.time")
async def testTimeBasedIsReadyReleases(self, time, time_is_ready, telemetry_is_ready, request):
time.return_value = 999999999
time_is_ready.return_value = True
sc = {'releases': [{"sc_id": 4, "when": 234, "telemetry_uptake": None, "telemetry_product": None, "telemetry_channel": None}]}
await self._runAgent(sc, request)
self.assertEquals(telemetry_is_ready.call_count, 0)
self.assertEquals(time_is_ready.call_count, 1)
self.assertEquals(request.call_count, 4)

@asynctest.patch("time.time")
async def testTimeBasedIsReadyPermissions(self, time, time_is_ready, telemetry_is_ready, request):
time.return_value = 999999999
time_is_ready.return_value = True
sc = {'permissions': [{"sc_id": 4, "when": 234, "telemetry_uptake": None, "telemetry_product": None, "telemetry_channel": None}]}
await self._runAgent(sc, request)
self.assertEquals(telemetry_is_ready.call_count, 0)
self.assertEquals(time_is_ready.call_count, 1)
self.assertEquals(request.call_count, 4)

@asynctest.patch("balrogagent.cmd.get_telemetry_uptake")
async def testTelemetryBasedNotReady(self, get_telemetry_uptake, time_is_ready, telemetry_is_ready, request):
telemetry_is_ready.return_value = False
get_telemetry_uptake.return_value = 0
sc = [{"sc_id": 4, "when": None, "telemetry_uptake": 1000, "telemetry_product": "foo", "telemetry_channel": "bar"}]
sc = {'rules': [{"sc_id": 4, "when": None, "telemetry_uptake": 1000, "telemetry_product": "foo", "telemetry_channel": "bar"}]}
await self._runAgent(sc, request)
self.assertEquals(telemetry_is_ready.call_count, 1)
self.assertEquals(time_is_ready.call_count, 0)
self.assertEquals(request.call_count, 1)
self.assertEquals(request.call_count, 3)

@asynctest.patch("balrogagent.cmd.get_telemetry_uptake")
async def testTelemetryBasedIsReady(self, get_telemetry_uptake, time_is_ready, telemetry_is_ready, request):
telemetry_is_ready.return_value = True
get_telemetry_uptake.return_value = 20000
sc = [{"sc_id": 4, "when": None, "telemetry_uptake": 1000, "telemetry_product": "foo", "telemetry_channel": "bar"}]
sc = {'rules': [{"sc_id": 4, "when": None, "telemetry_uptake": 1000, "telemetry_product": "foo", "telemetry_channel": "bar"}]}
await self._runAgent(sc, request)
self.assertEquals(telemetry_is_ready.call_count, 1)
self.assertEquals(time_is_ready.call_count, 0)
self.assertEquals(request.call_count, 2)
self.assertEquals(request.call_count, 4)

@asynctest.patch("time.time")
async def testMultipleEndpointsAtOnce(self, time, time_is_ready, telemetry_is_ready, request):
time.return_value = 999999999
time_is_ready.return_value = True
sc = {'releases': [{"sc_id": 4, "when": 234, "telemetry_uptake": None, "telemetry_product": None, "telemetry_channel": None}],
'rules': [{"sc_id": 5, "when": 234, "telemetry_uptake": None, "telemetry_product": None, "telemetry_channel": None}],
'permissions': [{"sc_id": 6, "when": 234, "telemetry_uptake": None, "telemetry_product": None, "telemetry_channel": None}]}
await self._runAgent(sc, request)
self.assertEquals(telemetry_is_ready.call_count, 0)
self.assertEquals(time_is_ready.call_count, 3)
self.assertEquals(request.call_count, 6)

0 comments on commit eda43c6

Please sign in to comment.