summaryrefslogtreecommitdiff
path: root/chef-server-api/lib/chef-server-api.rb
blob: 7d5dac559c3817f4fb545e7c7ee1936862128012 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
if defined?(Merb::Plugins)
  $:.unshift File.dirname(__FILE__)
  $:.unshift File.join(File.dirname(__FILE__), "..", "..", "chef-solr", "lib")
  $:.unshift File.join(File.dirname(__FILE__), "..", "..", "chef", "lib")

  dependency 'merb-slices', :immediate => true
  dependency 'chef', :immediate=>true unless defined?(Chef)
  dependency 'bunny', :immediate=>true 
  dependency 'uuidtools', :immediate=>true 

  require 'chef/role'
  require 'chef/data_bag'
  require 'chef/data_bag_item'
  require 'chef/api_client'
  require 'chef/webui_user'
  require 'chef/certificate'

  require 'mixlib/authentication'

  require 'chef/data_bag'
  require 'chef/data_bag_item'
  require 'ohai'
  require 'openssl'

  Merb::Plugins.add_rakefiles "chef-server-api/merbtasks", "chef-server-api/slicetasks", "chef-server-api/spectasks"

  # Register the Slice for the current host application
  Merb::Slices::register(__FILE__)

  Merb.disable :json

  # Slice configuration - set this in a before_app_loads callback.
  # By default a Slice uses its own layout, so you can switch to
  # the main application layout or no layout at all if needed.
  #
  # Configuration options:
  # :layout - the layout to use; defaults to :chefserverslice
  # :mirror - which path component types to use on copy operations; defaults to all
  Merb::Slices::config[:chef_server_api][:layout] ||= :chef_server_api
  
  # All Slice code is expected to be namespaced inside a module
  module ChefServerApi
    # Slice metadata
    self.description = "ChefServerApi.. serving up some piping hot infrastructure!"
    self.version = Chef::VERSION
    self.author = "Opscode"

    # Stub classes loaded hook - runs before LoadClasses BootLoader
    # right after a slice's classes have been loaded internally.
    def self.loaded
      Chef::Log.info("Compiling routes... (totally normal to see 'Cannot find resource model')")
    end

    # Initialization hook - runs before AfterAppLoads BootLoader
    def self.init
    end

    # Activation hook - runs after AfterAppLoads BootLoader
    def self.activate
      Mixlib::Authentication::Log.logger = Ohai::Log.logger = Chef::Log.logger 

      unless Merb::Config.environment == "test"
        # create the couch design docs for nodes, roles, and databags
        Chef::CouchDB.new.create_id_map
        Chef::Node.create_design_document
        Chef::Role.create_design_document
        Chef::DataBag.create_design_document
        Chef::ApiClient.create_design_document
        Chef::WebUIUser.create_design_document
        
        # Create the signing key and certificate 
        Chef::Certificate.generate_signing_ca

        # Generate the validation key
        Chef::Certificate.gen_validation_key

        # Generate the Web UI Key 
        Chef::Certificate.gen_validation_key(Chef::Config[:web_ui_client_name], Chef::Config[:web_ui_key], true)
        
        Chef::Log.info('Loading roles')
        Chef::Role.sync_from_disk_to_couchdb
      end
    end

    # Deactivation hook - triggered by Merb::Slices.deactivate(Chefserver)
    def self.deactivate
    end

    # Setup routes inside the host application
    #
    # @param scope<Merb::Router::Behaviour>
    #  Routes will be added within this scope (namespace). In fact, any
    #  router behaviour is a valid namespace, so you can attach
    #  routes at any level of your router setup.
    #
    # @note prefix your named routes with :chefserverslice_
    #   to avoid potential conflicts with global named routes.
    def self.setup_router(scope)
      # Users
      scope.resources :users
      
      # Nodes
      scope.resources :nodes, :id => /[^\/]+/
      scope.match('/nodes/:id/cookbooks',
                  :id => /[^\/]+/,
                  :method => 'get').
                  to(:controller => "nodes", :action => "cookbooks")
      # Roles
      scope.resources :roles

      # Status
      scope.match("/status").to(:controller => "status", :action => "index").name(:status)

      # Clients
      scope.match("/clients", :method=>"post").to(:controller=>'clients', :action=>'create')
      scope.match("/clients", :method=>"get").to(:controller=>'clients', :action=>'index').name(:clients)
      scope.match("/clients/:id", :id => /[\w\.-]+/, :method=>"get").to(:controller=>'clients', :action=>'show').name(:client)
      scope.match("/clients/:id", :id => /[\w\.-]+/, :method=>"put").to(:controller=>'clients', :action=>'update')
      scope.match("/clients/:id", :id => /[\w\.-]+/, :method=>"delete").to(:controller=>'clients', :action=>'destroy')

      # Search
      scope.resources :search
      scope.match('/search/reindex', :method => 'post').to(:controller => "search", :action => "reindex")

      # Cookbooks        
      scope.match('/nodes/:id/cookbooks', :method => 'get').to(:controller => "nodes", :action => "cookbooks")

      scope.resources :cookbooks
      scope.match("/cookbooks/:cookbook_id/_content", :method => 'get', :cookbook_id => /[\w\.]+/).to(:controller => "cookbooks", :action => "get_tarball")
      scope.match("/cookbooks/:cookbook_id/_content", :method => 'put', :cookbook_id => /[\w\.]+/).to(:controller => "cookbooks", :action => "update")
      scope.match("/cookbooks/:cookbook_id/:segment", :cookbook_id => /[\w\.]+/).to(:controller => "cookbooks", :action => "show_segment").name(:cookbook_segment)

      # Data
      scope.match("/data/:data_bag_id/:id", :method => 'get').to(:controller => "data_item", :action => "show").name("data_bag_item")
      scope.match("/data/:data_bag_id", :method => 'post').to(:controller => "data_item", :action => "create").name("create_data_bag_item")
      scope.match("/data/:data_bag_id/:id", :method => 'put').to(:controller => "data_item", :action => "update").name("update_data_bag_item")
      scope.match("/data/:data_bag_id/:id", :method => 'delete').to(:controller => "data_item", :action => "destroy").name("destroy_data_bag_item")
      scope.resources :data

      scope.match('/').to(:controller => 'main', :action =>'index').name(:top)
    end
  end
  

  # Setup the slice layout for ChefServerApi
  #
  # Use ChefServerApi.push_path and ChefServerApi.push_app_path
  # to set paths to chefserver-level and app-level paths. Example:
  #
  # ChefServerApi.push_path(:application, ChefServerApi.root)
  # ChefServerApi.push_app_path(:application, Merb.root / 'slices' / 'chefserverslice')
  # ...
  #
  # Any component path that hasn't been set will default to ChefServerApi.root
  #
  # Or just call setup_default_structure! to setup a basic Merb MVC structure.
  ChefServerApi.setup_default_structure!
end