Closed
Bug 797826
Opened 14 years ago
Closed 14 years ago
Write script to scrape pandaboard data from inventory into imaging service DB
Categories
(Infrastructure & Operations :: RelOps: General, task)
Infrastructure & Operations
RelOps: General
Tracking
(Not tracked)
RESOLVED
FIXED
People
(Reporter: ted, Assigned: dustin)
References
Details
Attachments
(4 files)
|
10.72 KB,
patch
|
ted
:
review+
|
Details | Diff | Splinter Review |
|
8.76 KB,
patch
|
ted
:
review+
|
Details | Diff | Splinter Review |
|
16.05 KB,
patch
|
ted
:
review+
|
Details | Diff | Splinter Review |
|
3.32 KB,
patch
|
Details | Diff | Splinter Review |
Some of the database data for the imaging service needs to come from inventory. Specifically we'll be populating the boards table with the following fields from inventory:
name varchar(32) not null,
fqdn varchar(256) not null,
inventory_id integer not null,
mac_address varchar(10) not null,
imaging_server varchar(256) not null,
relay_info varchar(64)
Presumably we'll also need to populate the imaging_servers table from inventory, which is just:
fqdn varchar(256) not null primary key
I'm pretty sure this info isn't actually complete in inventory yet. Jake: if there's a bug on getting that data into inventory that should block this one.
Comment 1•14 years ago
|
||
That data is now in inventory for all the pandas in the production chassis.
Comment 2•14 years ago
|
||
ted: if you don't get to this by monday, dustin can work on it (and has some experience with the inventory API).
| Reporter | ||
Comment 3•14 years ago
|
||
I'm probably still going to be tied up with the REST api bits, so if he knows the inventory API then I'm happy to let him take care of it.
Updated•14 years ago
|
Assignee: server-ops-releng → dustin
| Assignee | ||
Comment 4•14 years ago
|
||
Here's the first part:
- downloading inventory results (use pattern 'hostname__startswith=panda-')
- merging inventory results between db and inventory
I need to figure out the sqlalchemy stuff to do the last bit - actually inserting into the DB. So I'll put that in a second patch.
Attachment #669272 -
Flags: review?(ted.mielczarek)
| Assignee | ||
Comment 5•14 years ago
|
||
part two: crud methods.
Attachment #669574 -
Flags: review?(ted.mielczarek)
| Assignee | ||
Comment 6•14 years ago
|
||
This should do it. I'll take care of merging these when necessary (we've diverged a good bit).
Attachment #669639 -
Flags: review?(ted.mielczarek)
| Reporter | ||
Comment 7•14 years ago
|
||
Comment on attachment 669272 [details] [diff] [review]
bug797826-part1.patch
Review of attachment 669272 [details] [diff] [review]:
-----------------------------------------------------------------
Looks good, just a couple of nits.
::: bmm/invsync.py
@@ +1,1 @@
> +#!/usr/bin/env python
I'm a sucker for more descriptive names, can we name this "inventorysync" instead?
@@ +46,5 @@
> + name=name,
> + fqdn=hostname,
> + inventory_id=o['id'],
> + mac_address=mac_address,
> + imaging_server=kv.get('system.imaging_server.0', 'UNKNOWN'),
Seems like we might want to require this, otherwise the API will refuse to actually let you boot this board.
@@ +50,5 @@
> + imaging_server=kv.get('system.imaging_server.0', 'UNKNOWN'),
> + relay_info=kv['system.relay.0'])
> +
> + if verbose: print hostname, 'done.'
> +
nit: Trailing whitespace
@@ +58,5 @@
> +def merge_hosts(from_db, from_inv):
> + """
> + Merge a list of hosts in the DB with those in inventory. This yields a
> + list of instructions of the form ('insert', dict), ('delete', id), or
> + (update, id, dict).
Nit: missing quotes: 'update'.
::: runtests.py
@@ +269,5 @@
> + inventory_id = hash(fqdn) % 100
> + kv = []
> + if mac_address:
> + mac_address = hashlib.md5(fqdn).digest()[:6]
> + mac_address = ':'.join([ '%02x' % ord(b) for b in mac_address ])
Reusing the boolean parameters as string values here confused me a little, FWIW.
Attachment #669272 -
Flags: review?(ted.mielczarek) → review+
| Reporter | ||
Comment 8•14 years ago
|
||
Comment on attachment 669574 [details] [diff] [review]
bug797826-crud.patch
Review of attachment 669574 [details] [diff] [review]:
-----------------------------------------------------------------
::: bmm/data.py
@@ +54,5 @@
> from_obj=[model.boards.join(model.imaging_servers, model.imaging_servers.c.fqdn == server)]))
> return {'boards': [row[0].encode('utf-8') for row in res]}
>
> +def dump_boards():
> + """Dump all boards for inventory sync."""
I guess my docstring formatting is inconsistent and I should be putting one-line docstrings with the quotes on the same line like this.
@@ +61,5 @@
> + res = conn.execute(j.select(use_labels=True))
> + return [ dict(id=row.boards_id, name=row.boards_name, fqdn=row.boards_fqdn,
> + inventory_id=row.boards_inventory_id, mac_address=row.boards_mac_address,
> + imaging_server=row.imaging_servers_fqdn, relay_info=row.boards_relay_info)
> + for row in res ]
You probably want to use row_to_dict here (although you might have to tweak it to handle >1 table).
@@ +76,5 @@
> + pass # probably already exists
> +
> + res = conn.execute(sqlalchemy.select([ model.imaging_servers.c.id ],
> + whereclause=(model.imaging_servers.c.fqdn==name)))
> + return res.fetchall()[0].id
I think elsewhere I just use .fetchone() when I'm expecting one result.
@@ +78,5 @@
> + res = conn.execute(sqlalchemy.select([ model.imaging_servers.c.id ],
> + whereclause=(model.imaging_servers.c.fqdn==name)))
> + return res.fetchall()[0].id
> +
> +def insert_board(values):
Can you adjust testing.py's add_server/add_board to use these methods?
@@ +88,5 @@
> + values['imaging_server_id'] = find_imaging_server_id(values.pop('imaging_server'))
> + values['status'] = 'new'
> +
> + conn = get_conn()
> + conn.execute(model.boards.insert(), [ values ])
I've just been doing get_conn().execute for when I don't need to execute multiple statements.
Attachment #669574 -
Flags: review?(ted.mielczarek) → review+
| Reporter | ||
Comment 9•14 years ago
|
||
Comment on attachment 669639 [details] [diff] [review]
bug797826-actually-sync.patch
Review of attachment 669639 [details] [diff] [review]:
-----------------------------------------------------------------
::: bmm/config.py
@@ +14,5 @@
> config_read = False
> _db_engine = None
> +_inventory_url = None
> +_inventory_username = None
> +_inventory_password = None
Sorry, this file got real ugly real fast. Should have built a better API in the first place.
::: bmm/data.py
@@ +21,5 @@
> """
> global engine
> if engine is None:
> engine = sqlalchemy.create_engine(config.db_engine())
> + model.metadata.create_all(bind=engine)
This obviates testing.create_db_schema. I didn't realize this was safe to do if the schema already existed.
::: bmm/invsync.py
@@ +68,5 @@
> from_inv = dict([ (r['inventory_id'], r) for r in from_inv ])
>
> # get the insert and deletes out of the way
> for invid in set(from_db) - set(from_inv):
> + yield ('delete', from_db[invid]['id'], from_db[invid])
You changed the format of the 'delete' results but didn't update the docstring.
@@ +84,5 @@
> +def sync(verbose=False):
> + from_db = data.dump_boards()
> + from_inv = get_boards(
> + config.inventory_url(),
> + 'hostname__startswith=panda-',
Probably put a TODO here for improving this.
@@ +105,5 @@
> +
> +def main():
> + parser = argparse.ArgumentParser(description='Sync BMM with inventory.')
> + parser.add_argument('--verbose', action='store_true',
> + default=False,
Indentation is a little wonky here.
Attachment #669639 -
Flags: review?(ted.mielczarek) → review+
| Assignee | ||
Comment 10•14 years ago
|
||
(In reply to Ted Mielczarek [:ted] from comment #7)
> Review of attachment 669272 [details] [diff] [review]:
> -----------------------------------------------------------------
>
> Looks good, just a couple of nits.
All accounted for.
(In reply to Ted Mielczarek [:ted] from comment #8)
> Review of attachment 669574 [details] [diff] [review]:
> -----------------------------------------------------------------
> I guess my docstring formatting is inconsistent and I should be putting
> one-line docstrings with the quotes on the same line like this.
I honestly wasn't paying much attention..
> You probably want to use row_to_dict here (although you might have to tweak
> it to handle >1 table).
That actually adds quite a bit of complexity to row_to_dict. But I made is suck less.
> I think elsewhere I just use .fetchone() when I'm expecting one result.
This leaves the ResultSet (and underlying cursor) open, which can cause unexpected behavior. fetchall has the advantage of automatically closing the ResultSet.
> Can you adjust testing.py's add_server/add_board to use these methods?
insert_board doesn't insert into all of the columns, so I don't think that necessarily makes sense. Also, it confuses the system under test with the test harness, IMHO.
> I've just been doing get_conn().execute for when I don't need to execute
> multiple statements.
fixed.
(In reply to Ted Mielczarek [:ted] from comment #9)
> Review of attachment 669639 [details] [diff] [review]:
> -----------------------------------------------------------------
> This obviates testing.create_db_schema. I didn't realize this was safe to do
> if the schema already existed.
Ack, that was testing code, and should have been removed!
(remainder fixed)
| Assignee | ||
Comment 11•14 years ago
|
||
All checked in, merged, and pushed to ted's user repo.
Status: NEW → RESOLVED
Closed: 14 years ago
Resolution: --- → FIXED
| Assignee | ||
Comment 12•14 years ago
|
||
Ted, I also landed the config refactor on your repo, FYI.
| Reporter | ||
Comment 13•14 years ago
|
||
(In reply to Dustin J. Mitchell [:dustin] from comment #10)
> > I think elsewhere I just use .fetchone() when I'm expecting one result.
>
> This leaves the ResultSet (and underlying cursor) open, which can cause
> unexpected behavior. fetchall has the advantage of automatically closing
> the ResultSet.
Ah, we should probably be consistent about that usage then (even if it's not a problem in practice).
| Reporter | ||
Comment 14•14 years ago
|
||
Comment on attachment 669574 [details] [diff] [review]
bug797826-crud.patch
Review of attachment 669574 [details] [diff] [review]:
-----------------------------------------------------------------
::: bmm/data.py
@@ +94,5 @@
> +def delete_board(id):
> + """Delete the board with the given ID"""
> + conn = get_conn()
> +
> + conn.execute(model.boards.delete(), whereclause=(model.boards.c.id==id))
I missed this on the first pass, but you probably want to delete the data from the logs table as well, right? (Or do we get cascading delete for free?)
| Assignee | ||
Comment 15•14 years ago
|
||
Good point. We don't get that for free because MySQL can't do foreign keys on partitioned tables.
Status: RESOLVED → REOPENED
Resolution: FIXED → ---
| Assignee | ||
Comment 16•14 years ago
|
||
In my branch at http://hg.mozilla.org/users/dmitchell_mozilla.com/reimaging-service/rev/800cfb608649
Merge it unless you see a problem?
| Reporter | ||
Comment 17•14 years ago
|
||
Status: REOPENED → RESOLVED
Closed: 14 years ago → 14 years ago
Resolution: --- → FIXED
Updated•13 years ago
|
Component: Server Operations: RelEng → RelOps
Product: mozilla.org → Infrastructure & Operations
You need to log in
before you can comment on or make changes to this bug.
Description
•