def update_rpi_sense_hat_data(self, device_num_id, ts, sensor_data, memory=None, ip=None, storage=None): """ Performs a database upsert for the given device_num_id. It will delete the current row for device_num_id, and insert a row with the given data. @param device_num_id: Primary key for the database @type device_num_id: String @param ts: Timestamp from the IoT device @type ts: String @param sensor_data: json data from the IoT device @type sensor_data: String @param memory: The amount of memory in the IoT device @type memory: String @param ip: Current IP address of the IoT device @type ip: String @param storage: Remaining storage in the IoT device @type storage: String @return: None """ dbcur = self.dbcon.cursor() iot_upsert = f""" REPLACE INTO {self.RPI_SENSE_HAT} (device_num_id, ts, sensor_data, memory, ip, storage) VALUES (%s, %s, %s, %s, %s, %s) """ iot_args = (device_num_id, ts, sensor_data, memory, ip, storage) try: return_value = dbcur.execute(iot_upsert, iot_args) except pymysql.err.ProgrammingError as ex: # If the table does not exist, then create it first. if self._create_rpi_sense_hat_database(): dbcur.execute(iot_upsert, iot_args) else: cloud_log(LogIDs.IOT, "Unknown error: Could not create table for IoT.", LOG_LEVELS.ERROR) finally: self.dbcon.commit() self.dbcon.close() return return_value
def build(self): key = ds_client.key('cybergym-unit', self.unit_id) unit = ds_client.get(key) # This can sometimes happen when debugging a Unit ID and the Datastore record no longer exists. arena = unit['arena'] if not arena: cloud_log( self.unit_id, f"Build operation failed. No unit {self.unit_id} exists in the data store", LOG_LEVELS.ERROR) raise LookupError if 'state' not in unit or not unit['state']: state_transition(entity=unit, new_state=BUILD_STATES.START) # STATE: BUILDING_STUDENT_NETWORKS if check_ordered_arenas_state( unit, BUILD_STATES.BUILDING_ARENA_STUDENT_NETWORKS): cloud_log(self.unit_id, f"Creating student networks for arena {self.unit_id}", LOG_LEVELS.INFO) student_network = [{ 'name': self.STUDENT_NETWORK_NAME, 'subnets': [{ 'name': f'{self.unit_id}-{self.STUDENT_NETWORK_NAME}-default', 'ip_subnet': self.STUDENT_NETWORK_SUBNET }] }] try: create_network(networks=student_network, build_id=self.unit_id) except HttpError as err: if err.resp.status not in [409]: cloud_log( self.unit_id, f"Error when trying to create the student network for " f"the arena {self.unit_id}", LOG_LEVELS.ERROR) raise # STATE: BUILDING_ARENA_NETWORKS if check_ordered_arenas_state(unit, BUILD_STATES.BUILDING_ARENA_NETWORKS): state_transition(entity=unit, new_state=BUILD_STATES.BUILDING_ARENA_NETWORKS) if arena['networks']: cloud_log( self.unit_id, f"Creating additional arena networks for arena {self.unit_id}", LOG_LEVELS.INFO) create_network(networks=arena['networks'], build_id=self.unit_id) state_transition(entity=unit, new_state=BUILD_STATES.COMPLETED_ARENA_NETWORKS) # STATE: BUILDING_ARENA_SERVERS if check_ordered_arenas_state(unit, BUILD_STATES.BUILDING_ARENA_SERVERS): state_transition(entity=unit, new_state=BUILD_STATES.BUILDING_ARENA_SERVERS) cloud_log(self.unit_id, f"Creating additional servers for arena {self.unit_id}", LOG_LEVELS.INFO) server_list = list( ds_client.query(kind='cybergym-server').add_filter( 'workout', '=', self.unit_id).fetch()) for server in server_list: server_name = server['name'] cloud_log(self.unit_id, f"Sending pubsub message to build {server_name}", LOG_LEVELS.INFO) pubsub_topic = PUBSUB_TOPICS.MANAGE_SERVER publisher = pubsub_v1.PublisherClient() topic_path = publisher.topic_path(project, pubsub_topic) publisher.publish(topic_path, data=b'Server Build', server_name=server_name, action=SERVER_ACTIONS.BUILD) state_transition(entity=unit, new_state=BUILD_STATES.COMPLETED_ARENA_SERVERS) # STATE: BUILDING_ROUTES if check_ordered_arenas_state(unit, BUILD_STATES.BUILDING_ROUTES): state_transition(entity=unit, new_state=BUILD_STATES.BUILDING_ROUTES) cloud_log( self.unit_id, f"Creating network routes and firewall rules for arena {self.unit_id}", LOG_LEVELS.INFO) if 'routes' in arena and arena['routes']: for route in arena['routes']: r = { "name": f"{self.unit_id}-{route['name']}", "network": f"{self.unit_id}-{route['network']}", "destRange": route['dest_range'], "nextHopInstance": f"{self.unit_id}-{route['next_hop_instance']}" } create_route(route) state_transition(entity=unit, new_state=BUILD_STATES.COMPLETED_ROUTES) # STATE: BUILDING_FIREWALL if check_ordered_arenas_state(unit, BUILD_STATES.BUILDING_FIREWALL): state_transition(entity=unit, new_state=BUILD_STATES.BUILDING_FIREWALL) firewall_rules = [] for rule in arena['firewall_rules']: if 'network' not in rule: rule['network'] = self.STUDENT_NETWORK_NAME firewall_rules.append({ "name": f"{self.unit_id}-{rule['name']}", "network": f"{self.unit_id}-{rule['network']}", "targetTags": rule['target_tags'], "protocol": rule['protocol'], "ports": rule['ports'], "sourceRanges": rule['source_ranges'] }) # Create the default rules to allow traffic between student networks. firewall_rules.append({ "name": f"{self.unit_id}-allow-all-internal", "network": f"{self.unit_id}-{self.STUDENT_NETWORK_NAME}", "targetTags": [], "protocol": 'tcp', "ports": ['tcp/any', 'udp/any', 'icmp/any'], "sourceRanges": [self.STUDENT_NETWORK_SUBNET] }) create_firewall_rules(firewall_rules) state_transition(entity=unit, new_state=BUILD_STATES.COMPLETED_FIREWALL)