Slide 1

Slide 1 text

Rick  Copeland  @rick446   Arborian  Consulting,  LLC  

Slide 2

Slide 2 text

  Infrastructure  as  Code     Resources  &  Providers     Cookbooks,  Recipes,  Clients,  and  Nodes  

Slide 3

Slide 3 text

Chef  Server     (API)   RabbitMQ   RabbitMQ   RabbitMQ   CouchDB   Solr   Solr  Indexer   chef-­‐client   knife   Chef  Server   (Web  UI)   HTTP  REST  API  

Slide 4

Slide 4 text

Build,  register,  and  authenticate  the  node   Synchronize  cookbooks   Build  resource  collection  (run  the  recipes  in  order)   Configure  node  (“converge”)   Run  notification  handlers  

Slide 5

Slide 5 text

Chef  Server     (API)   RabbitMQ   RabbitMQ   RabbitMQ   CouchDB   Solr   Solr  Indexer   chef-­‐client   knife   Chef  Server   (Web  UI)   HTTP  REST  API   Ruby   Ruby   Ruby  

Slide 6

Slide 6 text

  Chef  assumes  a  bootstrapped  node  exists     Chef  doesn’t  keep  release  notes     Code  and  infrastructure  are  versioned   differently     Solution:  Web  app  to  manage  deployments  &   generate  release  notes  

Slide 7

Slide 7 text

MongoDB   Solr   Solr  Indexer   chef-­‐client   knife   HTTP  REST  API   MonQ   Chef  Server     (API  +  web)   Ruby   Python  

Slide 8

Slide 8 text

  Reduce  #  of  processes  &  technologies     Don’t  know  Ruby  well     Keep  private  keys  out  of  the  system     Integrate  with  existing  authentication     Performance  

Slide 9

Slide 9 text

/clients   /data   /roles   /nodes   /cookbooks   /environments   /sandboxes   /search  

Slide 10

Slide 10 text

  Mostly  JSON    almost  BSON     References  to  Ruby  files  stored  separately   {      "name":  "allura-­‐0.0.1”,…      "json_class":  "Chef::CookbookVersion",      "attributes":  [          {              "name":  "default.rb",              "url":  "https://s3.amazonaws.com/opscode-­‐platform-­‐production-­‐data/…                                  "checksum":  "749a3a328d6c47a32d134b336183981f",              "path":  "attributes/default.rb",              "specificity":  "default”…   Ruby  files  stored  on  S3  

Slide 11

Slide 11 text

role = collection( 'chef.role', doc_session, Field('_id', S.ObjectId()), Field('account_id', S.ObjectId(if_missing=None)), Field('name', str), Field('description', str), Field('default_attributes', str), Field('override_attributes', str), Field('run_list', [ str ] ), Field('env_run_lists', { str: [ str ]}), Index('account_id', 'name', unique=True)) MongoDB  Validator   Shorthand  with   Python  Types   Embedded   Documents   Index  Definitions  

Slide 12

Slide 12 text

class Role(object): def url(self): return request.relative_url( config.chef_api_root + '/roles/' + self.name) def __json__(self): return dict( chef_type='role', json_class='Chef::Role',! … default_attributes=loads(self.default_attributes),! …) def update(self, d): self.name = d['name'] … self.default_attributes = dumps(d['default_attributes']) self.override_attributes = dumps(d['override_attributes'])! … Models  know   where  they  live   Models  can  be   turned  into  dict  (to   be  JSONified)   Models  can  be   updated  from  dict  

Slide 13

Slide 13 text

class RoleSchema(JSONModelSchema):! model_class=CM.role! chef_type='role’! json_class='Chef::Role’! exclude_fields=['_id', 'account_id']

Slide 14

Slide 14 text

  /foo/bar/baz    root.foo.bar.baz     Lots  of  decorators     Validation  (params/body    **kwargs)     Authorization     Rendering     HTTP  method  lookup     GET  /foo/bar    root.foo.bar._get()  

Slide 15

Slide 15 text

class RolesController(RESTController): @expose(template_engine='json') def _get(self):… @expose(template_engine='json', acl=[CACE.admin(True), ACE.any(False)], schema=cv.RoleSchema) def _post(self, **kwargs):… def __getattr__(self, name): return RoleController(name) Returns  JSON   Only  admins  can   access   Convert  and   Validate  POST   Continue  dotted   lookup  

Slide 16

Slide 16 text

class RoleController(RESTController): @expose(template_engine='json') def _get(self): … @expose(template_engine='json', acl=[CACE.admin(True), ACE.any(False)], schema=cv.RoleSchema) def _put(self, name, **kwargs): … @expose(template_engine='json', acl=[CACE.admin(True), ACE.any(False)]) def _delete(self): … PUT  looks  just  like  a  POST  

Slide 17

Slide 17 text

class RoleController(RESTController):! def __init__(self, name): self._role = CM.Role.query.get( account_id=c.account._id, name=name) if self._role is None: raise AttributeError, name! @expose(template_engine='json') def _get(self): return self._role! AttributeError       HTTP  404  Not  Found   Auto-­‐JSONify  

Slide 18

Slide 18 text

class RoleController(RESTController):! … @expose(template_engine='json', acl=[CACE.admin(True), ACE.any(False)], schema=cv.RoleSchema) def _put(self, name, **kwargs): assert name == self._role.name self._role.update(kwargs) return self._role! @expose(template_engine='json', acl=[CACE.admin(True), ACE.any(False)]) def _delete(self): self._role.delete() return self._role Update  model   from  kwargs  

Slide 19

Slide 19 text

  Don’t  trust  the  docs     Don’t  trust  the  docs   ▪  Don’t  trust  the  docs     Use  fat  models     Framework  support  for  REST  &  JSON     You’re  gonna  have  to  learn  some  Ruby  anyway     JSON  !=  BSON  

Slide 20

Slide 20 text

  Better  test  coverage     Search  support  (SOLR  /  ElasticSearch)     More  testing  with  real-­‐world  deployments     Finalize  integration  with  deployment   manager  

Slide 21

Slide 21 text

Rick  Copeland  @rick446   Arborian  Consulting,  LLC  

Slide 22

Slide 22 text

  http://openmymind.net/2011/10/28/ CouchDB-­‐And-­‐MongoDB-­‐Performance/     MongoDB  is  14x  faster     http://www.snailinaturtleneck.com/blog/ 2009/06/29/couchdb-­‐vs-­‐mongodb-­‐ benchmark/