예제 #1
0
    def ActionDone(self, action_report, context):

        db = None
        if self.useRealDatabase:
            db = database.Database(in_memory=False)  # sql schema was already instantiated
        else:
            db = database.Database(in_memory=True)
            db.recreate_database()

        if self.verbose:
            print("Got ActionReport", action_report, context)

        # prepare empty response
        response = protobufs_pb2.Response()
        response.action = protobufs_pb2.Response.DO_NOTHING

        if action_report.authentication_token != constants.AUTHENTICATION_TOKEN:
            print('Invalid token provided', action_report.authentication_token, "ignoring")
            return response

        db.save_action_report(action_report)

        # prepare empty response
        response = protobufs_pb2.Response()
        response.action = protobufs_pb2.Response.DO_NOTHING
        return response
예제 #2
0
파일: web_test.py 프로젝트: lbarman/gaia
def test_command_no_data(client):
    data = dict()
    data['passphrase'] = constants.AUTHENTICATION_TOKEN
    data['newCommand'] = '1'  # ='SHUTDOWN'
    data['updateConfig'] = '1'
    data['feedingEnabled'] = '1'
    data['wateringEnabled'] = '1'
    data['feedingCron'] = '15h 0,3,4,5,6'
    data['wateringCron'] = '14h 1,2'
    data['pump1Duration'] = '101'
    data['pump2Duration'] = '102'
    data['pump3Duration'] = '103'
    data['pump4Duration'] = '104'

    rv = client.post('/command', data=data)
    assert rv.status_code == 201


    db = database.Database()
    cmd = db.get_command()
    assert cmd is not None
    assert cmd['text'] == 'SHUTDOWN'
    assert cmd['config'] is not None

    assert cmd['config']['feeding_module_activated'] == int(data['feedingEnabled'])
    assert cmd['config']['watering_module_activated'] == int(data['wateringEnabled'])
    assert cmd['config']['feeding_module_cronstring'] == data['feedingCron']
    assert cmd['config']['watering_module_cronstring'] == data['wateringCron']
    assert cmd['config']['watering_pump_1_duration'] == int(data['pump1Duration'])
    assert cmd['config']['watering_pump_2_duration'] == int(data['pump2Duration'])
    assert cmd['config']['watering_pump_3_duration'] == int(data['pump3Duration'])
    assert cmd['config']['watering_pump_4_duration'] == int(data['pump4Duration'])
예제 #3
0
    def test_real_file_wrong_auth_auth(self):

        db = database.Database(in_memory=False)
        db.recreate_database()

        # add a dummy command to the server
        config = database_test.dummy_config()
        db.save_command("REBOOT", config)

        server = server_grpc.start_grpc_server(verbose=True)
        sleep(1)

        # create the gRPC stub
        channel = grpc.insecure_channel('127.0.0.1:' +
                                        str(constants.GRPC_SERVER_PORT))
        stub = protobufs_pb2_grpc.GaiaServiceStub(channel)

        with pytest.raises(Exception):
            response = stub.Ping(dummy_status_message())
            assert response is None

        with pytest.raises(Exception):
            response = stub.ActionDone(dummy_action_report())
            assert response is None

        server.stop(0)
예제 #4
0
    def test_status_creation(self):
        db = database.Database(in_memory=True)
        db.recreate_database()

        # initially, there should be no command
        self.assertEqual(db.get_all_status(), [])

        # save and retrieve one
        status1 = dummy_status_update()

        db.save_status(status1)
        all_status = db.get_all_status()
        self.assertNotEqual(all_status, None)
        self.assertEqual(len(all_status), 1)
        status2 = all_status[0]

        self.assertEqual(
            status2['local_timestamp'].strftime("%Y-%m-%d %H:%M:%S"),
            status1.local_timestamp)
        self.assertEqual(status2['feeding_module_activated'],
                         status1.current_config.feeding_module_activated)
        self.assertEqual(status2['watering_module_activated'],
                         status1.current_config.watering_module_activated)
        self.assertEqual(status2['feeding_module_cronstring'],
                         status1.current_config.feeding_module_cronstring)
        self.assertEqual(status2['watering_module_cronstring'],
                         status1.current_config.watering_module_cronstring)
        self.assertEqual(status2['watering_pump_1_duration'],
                         status1.current_config.watering_pump_1_duration)
        self.assertEqual(status2['watering_pump_2_duration'],
                         status1.current_config.watering_pump_2_duration)
        self.assertEqual(status2['watering_pump_3_duration'],
                         status1.current_config.watering_pump_3_duration)
        self.assertEqual(status2['watering_pump_4_duration'],
                         status1.current_config.watering_pump_4_duration)
        self.assertEqual(status2['uptime'], status1.system_status.uptime)
        self.assertEqual(status2['memory'], status1.system_status.memory)
        self.assertEqual(status2['disk_usage'],
                         status1.system_status.disk_usage)
        self.assertEqual(status2['processes'], status1.system_status.processes)

        self.assertEqual(1, count_records('configs', db.cursor))
        self.assertEqual(1, count_records('system_status', db.cursor))
        self.assertEqual(1, count_records('status', db.cursor))

        db.save_status(status1)
        self.assertEqual(2, count_records('configs', db.cursor))
        self.assertEqual(2, count_records('system_status', db.cursor))
        self.assertEqual(2, count_records('status', db.cursor))

        # should remove all things older than X days, here with X=0 => table should be truncated
        db.save_status(status1, number_of_days_to_keep_status=0)
        self.assertEqual(1, count_records('configs', db.cursor))
        self.assertEqual(1, count_records('system_status', db.cursor))
        self.assertEqual(1, count_records('status', db.cursor))

        db.truncate()
        self.assertEqual(0, count_records('configs', db.cursor))
        self.assertEqual(0, count_records('system_status', db.cursor))
        self.assertEqual(0, count_records('status', db.cursor))
예제 #5
0
    def Ping(self, status, context):

        db = None
        if self.useRealDatabase:
            db = database.Database(in_memory=False)  # sql schema was already instantiated
        else:
            db = database.Database(in_memory=True)
            db.recreate_database()

        if self.verbose:
            print("Got Ping", status, context)

        # prepare empty response
        response = protobufs_pb2.Response()
        response.action = protobufs_pb2.Response.DO_NOTHING

        if status.authentication_token != constants.AUTHENTICATION_TOKEN:
            print('Invalid token provided', status.authentication_token, "ignoring")
            return response

        db.save_status(status)


        # check if we have to transmit a command
        command = db.get_command()
        if command is not None:
            if command['text'] == 'SHUTDOWN':
                    response.action = protobufs_pb2.Response.SHUTDOWN
            elif command['text'] == 'REBOOT':
                    response.action = protobufs_pb2.Response.REBOOT

            if command['config'] is not None:
                response.config.feeding_module_activated = command['config']['feeding_module_activated']
                response.config.watering_module_activated = command['config']['watering_module_activated']
                response.config.feeding_module_cronstring = command['config']['feeding_module_cronstring']
                response.config.watering_module_cronstring = command['config']['watering_module_cronstring']
                response.config.watering_pump_1_duration = command['config']['watering_pump_1_duration']
                response.config.watering_pump_2_duration = command['config']['watering_pump_2_duration']
                response.config.watering_pump_3_duration = command['config']['watering_pump_3_duration']
                response.config.watering_pump_4_duration = command['config']['watering_pump_4_duration']

        db.delete_all_commands()

        if self.verbose:
            print("Answering with", response)

        return response
예제 #6
0
def insert_dummy_pings():
    db = database.Database()
    db.recreate_database()

    for day in range(0, 7):
        for hour in range(0, 24):
            for min in range(0, 6):
                db.save_status(dummy_status_update(day, hour, min))
예제 #7
0
파일: web_test.py 프로젝트: lbarman/gaia
def client():
    server_web.webserver.config['TESTING'] = True
    web_client = server_web.webserver.test_client()

    db = database.Database()
    db.recreate_database()
    db.delete_all_commands()

    yield web_client
예제 #8
0
    def test_real_file_valid_auth(self):

        db = database.Database(in_memory=False)
        db.recreate_database()

        # add a dummy command to the server
        config = database_test.dummy_config()
        db.save_command("REBOOT", config)

        server = server_grpc.start_grpc_server(verbose=True)
        sleep(1)

        # create the gRPC stub
        channel = grpc.insecure_channel('127.0.0.1:' +
                                        str(constants.GRPC_SERVER_PORT))
        stub = protobufs_pb2_grpc.GaiaServiceStub(channel)

        # send message
        status = dummy_status_message()
        status.authentication_token = constants.AUTHENTICATION_TOKEN
        response = stub.Ping(status)

        # this should be the default
        self.assertEqual(response.action, protobufs_pb2.Response.REBOOT)
        self.assertEqual(response.HasField('config'), True)

        self.assertEqual(response.config.feeding_module_activated,
                         config.feeding_module_activated)
        self.assertEqual(response.config.watering_module_activated,
                         config.feeding_module_activated)
        self.assertEqual(response.config.feeding_module_cronstring,
                         config.feeding_module_cronstring)
        self.assertEqual(response.config.watering_module_cronstring,
                         config.watering_module_cronstring)
        self.assertEqual(response.config.watering_pump_1_duration,
                         config.watering_pump_1_duration)
        self.assertEqual(response.config.watering_pump_2_duration,
                         config.watering_pump_2_duration)
        self.assertEqual(response.config.watering_pump_3_duration,
                         config.watering_pump_3_duration)
        self.assertEqual(response.config.watering_pump_4_duration,
                         config.watering_pump_4_duration)

        # send message
        report = dummy_action_report()
        report.authentication_token = constants.AUTHENTICATION_TOKEN
        response = stub.ActionDone(report)

        # this should be the default
        self.assertEqual(response.action, protobufs_pb2.Response.DO_NOTHING)
        self.assertEqual(response.HasField('config'), False)

        server.stop(0)
예제 #9
0
파일: server_web.py 프로젝트: lbarman/gaia
def save_new_config_to_db(cmd_text='UNKNOWN_COMMAND'):
    new_config = None

    if request.form.get('updateConfig') == '1':
        new_config = protobufs_pb2.Config()

        # manually parse those
        new_config.feeding_module_activated = False
        if request.form.get('feedingEnabled') == '1':
            new_config.feeding_module_activated = True

        new_config.watering_module_activated = False
        if request.form.get('wateringEnabled') == '1':
            new_config.watering_module_activated = True

        # regex-validate those
        feeding_cron = request.form.get('feedingCron')
        watering_cron = request.form.get('wateringCron')

        pattern = re.compile(constants.CRON_REGEX_TESTER)
        if not pattern.match(feeding_cron):
            raise ValueError('Feeding cron is invalid:', feeding_cron)
        if not pattern.match(watering_cron):
            raise ValueError('Watering cron is invalid:', feeding_cron)

        new_config.feeding_module_cronstring = feeding_cron
        new_config.watering_module_cronstring = watering_cron

        # manual sanity check on those values
        d1 = int(request.form.get('pump1Duration'))
        d2 = int(request.form.get('pump2Duration'))
        d3 = int(request.form.get('pump3Duration'))
        d4 = int(request.form.get('pump4Duration'))

        if d1 < 0 or d2 < 0 or d3 < 0 or d4 < 0:
            raise ValueError('A watering duration is below zero:', d1, d2, d3,
                             d4)

        m = constants.WATERING_DURATION_MAX_VALUE
        if d1 > m or d2 > m or d3 > m or d4 > m:
            raise ValueError('A watering duration exceeds the max value:', d1,
                             d2, d3, d4)

        # protobuf raise exception if we're not actually inputting numbers
        new_config.watering_pump_1_duration = d1
        new_config.watering_pump_2_duration = d2
        new_config.watering_pump_3_duration = d3
        new_config.watering_pump_4_duration = d4

    db = database.Database()
    db.save_command(cmd_text, new_config)
예제 #10
0
파일: web_test.py 프로젝트: lbarman/gaia
def test_command_data_but_no_update(client):
    data = dict()
    data['passphrase'] = constants.AUTHENTICATION_TOKEN
    data['newCommand'] = '2'  # ='REBOOT'
    # no update config

    rv = client.post('/command', data=data)
    assert rv.status_code == 201

    db = database.Database()
    cmd = db.get_command()
    assert cmd is not None
    assert cmd['text'] == 'REBOOT'
    assert cmd['config'] is None
예제 #11
0
파일: server_web.py 프로젝트: lbarman/gaia
def update_command():
    try:
        # very weak protection against bruteforce
        time.sleep(constants.WEB_SERVER_NEW_COMMAND_SLEEP_TIME)

        if request.form is None:
            return Response(status=400)
        if request.form.get('passphrase') != constants.COMMAND_PASSPHRASE:
            return Response(status=401)

        cmd_id = request.form.get('newCommand')
        if cmd_id == '0':
            save_new_config_to_db('DO_NOTHING')
        elif cmd_id == '1':
            save_new_config_to_db('SHUTDOWN')
        elif cmd_id == '2':
            save_new_config_to_db('REBOOT')
        elif cmd_id == '3':  # empty server db
            db = database.Database()
            db.recreate_database()
            db.truncate()
        elif cmd_id == '4':  # reset server db to dummy config
            db = database.Database()
            db.recreate_database()
            db.truncate()
            import tests.dummy_data as dummy_data
            dummy_data.insert_dummy_action_report()
            dummy_data.insert_dummy_pings()
        else:
            return Response(status=406)

        return Response(status=201)

    except Exception as e:
        print("Exception: ", e)
        return Response(status=400)
예제 #12
0
    def test_action_report(self):
        db = database.Database(in_memory=True)
        db.recreate_database()

        # initially, there should be no command
        self.assertEqual(db.get_all_action_reports(), [])

        # save and retrieve one
        report1 = dummy_action_report()

        db.save_action_report(report1)
        all_reports = db.get_all_action_reports()
        self.assertNotEqual(all_reports, None)
        self.assertEqual(len(all_reports), 1)
        report2 = all_reports[0]

        self.assertEqual(
            report2['local_timestamp'].strftime("%Y-%m-%d %H:%M:%S"),
            report1.local_timestamp)
        self.assertEqual(report2['action_type'], 1)
        self.assertEqual(report2['action_details'], report1.action_details)

        # save and retrieve two
        report3 = dummy_action_report()
        report3.action = protobufs_pb2.ActionReport.WATERING
        report3.action_details = 'test'

        db.save_action_report(report3)
        all_reports = db.get_all_action_reports()
        self.assertNotEqual(all_reports, None)
        self.assertEqual(len(all_reports), 2)

        self.assertEqual(
            all_reports[0]['local_timestamp'].strftime("%Y-%m-%d %H:%M:%S"),
            report3.local_timestamp)
        self.assertEqual(all_reports[0]['action_type'], 2)
        self.assertEqual(all_reports[0]['action_details'],
                         report3.action_details)
        self.assertEqual(
            all_reports[1]['local_timestamp'].strftime("%Y-%m-%d %H:%M:%S"),
            report1.local_timestamp)
        self.assertEqual(all_reports[1]['action_type'], 1)
        self.assertEqual(all_reports[1]['action_details'],
                         report1.action_details)

        # should remove all things older than X days, here with X=0 => table should be truncated
        db.save_action_report(report3, number_of_days_to_keep_status=0)
        self.assertEqual(1, count_records('action_reports', db.cursor))
예제 #13
0
    def test_db_creation(self):
        db = database.Database(in_memory=True)
        self.assertNotEqual(db.db, None)
        self.assertNotEqual(db.cursor, None)

        db.recreate_database()

        self.assertNotEqual(db.db, None)
        self.assertNotEqual(db.cursor, None)

        tables = db.cursor.execute(
            'SELECT name FROM sqlite_master WHERE type=\'table\'').fetchall()
        tables = [x[0] for x in tables]

        for expectedTable in [
                "status", "configs", "system_status", "commands"
        ]:
            if expectedTable not in tables:
                self.fail("Table " + expectedTable + " wasn't created")
예제 #14
0
파일: server_web.py 프로젝트: lbarman/gaia
def main():

    template_source = ''
    template_file = os.path.join(os.getcwd(), "templates",
                                 constants.TEMPLATE_FILE)
    with open(template_file, 'r') as file:
        template_source = file.read()

    # query the database
    db = database.Database()
    next_command = db.get_command()
    all_status = db.get_all_status()
    all_reports = db.get_all_action_reports()

    next_cmd_string = '&bot;'
    if next_command is not None:
        next_cmd_string = next_command['text']

    # prepare the array to replace in the template
    tokens = dict()
    tokens['STATUS'] = helpers.build_status_data_html(all_status)
    tokens['REPORTS'] = helpers.build_reports_data_html(all_reports)
    if len(all_status) > 0:
        tokens['CURRENT_CONFIG'] = helpers.build_current_config(all_status[0])
    else:
        tokens[
            'CURRENT_CONFIG'] = '<div id="current_config"><h3>Current Config</h3>No config</div>'
    tokens['JS_ARRAYS'] = helpers.build_js_arrays(all_status, all_reports)
    tokens['NEXT_COMMAND'] = next_cmd_string
    tokens['PORT_VIDEO'] = str(constants.PORT_VIDEO)
    helpers.build_water_levels_dict(None, None, 100, None, tokens)

    # build the template
    html = template_source
    for key in tokens:
        html = html.replace('{{' + key + '}}', tokens[key])

    return Response(html, 200)
예제 #15
0
    def test_command_creation(self):
        db = database.Database(in_memory=True)
        db.recreate_database()

        # initially, there should be no command
        self.assertEqual(db.get_command(), None)

        db.save_command("SOME_COMMAND")

        # save a command without config
        cmd = db.get_command()
        self.assertNotEqual(cmd, None)
        self.assertEqual(cmd["text"], "SOME_COMMAND")
        self.assertEqual(cmd["config"], None)

        # save a new command, should only keep the most recent
        db.save_command("SOME_COMMAND2")
        cmd = db.get_command()
        self.assertNotEqual(cmd, None)
        self.assertEqual(cmd["text"], "SOME_COMMAND2")
        self.assertEqual(cmd["config"], None)

        self.assertEqual(1, count_records('commands', db.cursor))

        # save a command with config
        config1 = dummy_config()
        db.save_command("SOME_COMMAND3", config1)
        cmd = db.get_command()
        self.assertNotEqual(cmd, None)
        self.assertEqual(cmd["text"], "SOME_COMMAND3")

        config2 = cmd["config"]
        self.assertEqual(config2['feeding_module_activated'],
                         config1.feeding_module_activated)
        self.assertEqual(config2['watering_module_activated'],
                         config1.watering_module_activated)
        self.assertEqual(config2['feeding_module_cronstring'],
                         config1.feeding_module_cronstring)
        self.assertEqual(config2['watering_module_cronstring'],
                         config1.watering_module_cronstring)
        self.assertEqual(config2['watering_pump_1_duration'],
                         config1.watering_pump_1_duration)
        self.assertEqual(config2['watering_pump_2_duration'],
                         config1.watering_pump_2_duration)
        self.assertEqual(config2['watering_pump_3_duration'],
                         config1.watering_pump_3_duration)
        self.assertEqual(config2['watering_pump_4_duration'],
                         config1.watering_pump_4_duration)

        # saving a new command should overwrite the previous, and hence delete the config

        # save a command with config
        db.save_command("SOME_COMMAND4", None)
        cmd = db.get_command()
        self.assertNotEqual(cmd, None)
        self.assertEqual(cmd["text"], "SOME_COMMAND4")

        self.assertEqual(1, count_records('commands', db.cursor))
        self.assertEqual(0, count_records('configs', db.cursor))

        # delete should empty the table
        db.delete_all_commands()

        self.assertEqual(0, count_records('commands', db.cursor))
예제 #16
0
def insert_dummy_action_report():
    db = database.Database()
    db.recreate_database()

    for i in range(0, 14):
        db.save_action_report(dummy_action_report(i))
예제 #17
0
def start_grpc_server(override_servicer=None, verbose=False):
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=constants.GRPC_MAX_WORKERS))

    servicer = None

    if override_servicer == None:
        servicer = GaiaServiceServicer(real_database=True, verbose=verbose)
    else:
        servicer = override_servicer

    protobufs_pb2_grpc.add_GaiaServiceServicer_to_server(servicer, server)
    server.add_insecure_port('[::]:' + str(constants.GRPC_SERVER_PORT))
    print("Starting gRPC server on port", constants.GRPC_SERVER_PORT)
    server.start()
    return server


if __name__ == '__main__':
    # try recreating the DB
    db = database.Database()
    db.recreate_database()

    gprcServer = start_grpc_server(verbose=True)
    try:
        while True:
            sleep(_ONE_DAY_IN_SECONDS)
    except KeyboardInterrupt:
        print("Quitting")
        gprcServer.stop(0)