371 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			371 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| require "mongo"
 | |
| 
 | |
| require "db/exceptions/record_not_found"
 | |
| require "db/exceptions/invalid_record"
 | |
| require "exceptions/invalid_privileges"
 | |
| 
 | |
| require "db/mongo/models/project"
 | |
| require "db/mongo/models/image"
 | |
| require "db/mongo/models/project"
 | |
| require "db/mongo/models/server"
 | |
| require "db/mongo/models/user"
 | |
| 
 | |
| include Mongo
 | |
| 
 | |
| class MongoConnector
 | |
| 
 | |
|   def initialize(db, host, port=27017, user=nil, password=nil)
 | |
|     @mongo_client = MongoClient.new(host, port)
 | |
|     @db = @mongo_client.db(db)
 | |
|     @db.authenticate(user, password) unless user.nil? or password.nil?
 | |
|     @projects = @db.collection("projects")
 | |
|     @images = @db.collection("images")
 | |
|     @servers = @db.collection("servers")
 | |
|     @filters = @db.collection("filters")
 | |
|     @keys = @db.collection("keys")
 | |
|     @users = @db.collection("users")
 | |
|     @statistic = @db.collection("statistic")
 | |
|   end
 | |
| 
 | |
|   def images provider=nil
 | |
|     q = (provider.nil? ? {} : {"provider" => provider})
 | |
|     @images.find(q).to_a.map {|bi| Image.create_from_bson bi}
 | |
|   end
 | |
| 
 | |
|   def image id
 | |
|     i = @images.find(create_query("_id" => id)).to_a[0]
 | |
|     raise RecordNotFound.new("Image '#{id}' does not exist") if i.nil?
 | |
|     Image.create_from_bson i
 | |
|   end
 | |
| 
 | |
|   def image_insert image
 | |
|     image.validate!
 | |
|     @images.insert(image.to_mongo_hash)
 | |
|   rescue Mongo::OperationFailure => e
 | |
|     if e.message =~ /^11000/
 | |
|       raise InvalidRecord.new("Duplicate key error: image with id '#{image.id}'")
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def image_update image
 | |
|     image.validate!
 | |
|     @images.update(create_query({"_id" => image.id}), create_query(image.to_mongo_hash))
 | |
|   rescue Mongo::OperationFailure => e
 | |
|     if e.message =~ /^11000/
 | |
|       raise InvalidRecord.new("Duplicate key error: image with id '#{image.id}'")
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def image_delete id
 | |
|     r = @images.remove(create_query("_id" => id))
 | |
|     raise RecordNotFound.new("Image '#{id}' not found") if r["n"] == 0
 | |
|     r
 | |
|   end
 | |
| 
 | |
|   def available_images provider
 | |
|     f = @filters.find(create_query("type" => "image", "provider" => provider)).to_a[0]
 | |
|     return [] if f.nil?
 | |
|     f["images"]
 | |
|   end
 | |
| 
 | |
|   def add_available_images images, provider
 | |
|     return unless images.is_a?(Array)
 | |
|     f = @filters.find(create_query("type" => "image", "provider" => provider)).to_a[0]
 | |
|     if f.nil?
 | |
|       @filters.insert(create_query({"type" => "image", "provider" => provider, "images" => images}))
 | |
|       return images
 | |
|     else
 | |
|       f["images"] |= images
 | |
|       @filters.update({"_id" => f["_id"]}, f)
 | |
|       return f["images"]
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def delete_available_images images, provider
 | |
|     return unless images.is_a?(Array)
 | |
|     f = @filters.find(create_query("type" => "image", "provider" => provider)).to_a[0]
 | |
|     unless f.nil?
 | |
|       f["images"] -= images
 | |
|       @filters.update({"_id" => f["_id"]}, f)
 | |
|       return f["images"]
 | |
|     end
 | |
|     []
 | |
|   end
 | |
| 
 | |
|   def is_project_exists? project
 | |
|     self.project project.id
 | |
|     return true
 | |
|   rescue RecordNotFound => e
 | |
|     return false
 | |
|   end
 | |
| 
 | |
|   def project_insert project
 | |
|     project.validate!
 | |
|     @projects.insert(create_query(project.to_mongo_hash))
 | |
|   rescue Mongo::OperationFailure => e
 | |
|     if e.message =~ /^11000/
 | |
|       raise InvalidRecord.new("Duplicate key error: project with id '#{project.id}'")
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def project name
 | |
|     p = @projects.find(create_query("_id" => name)).to_a[0]
 | |
|     raise RecordNotFound.new("Project '#{name}' does not exist") if p.nil?
 | |
|     Project.create_from_bson p
 | |
|   end
 | |
| 
 | |
|   def projects_all
 | |
|     p = @projects.find()
 | |
|     p.to_a.map {|bp| Project.create_from_bson bp}
 | |
|   end
 | |
| 
 | |
|   def projects list=nil, type=nil, fields=[]
 | |
|     q = (list.nil? ? {} : {"_id" => {"$in" => list}})
 | |
|     case type
 | |
|     when :multi
 | |
|       q["type"] = "multi"
 | |
|     #else
 | |
|     #  q["type"] = {"$exists" => false}
 | |
|     end
 | |
|     res = @projects.find(create_query(q), :fields => fields)
 | |
|     a = res.to_a
 | |
|     a.map {|bp| Project.create_from_bson bp}
 | |
|   end
 | |
| 
 | |
|   # names - array of project names
 | |
|   def project_names_with_envs names=nil
 | |
|     # db.projects.aggregate({$unwind:"$deploy_envs"}, {$project:{"deploy_envs.identifier":1}}, {$group:{_id:"$_id", envs: {$addToSet: "$deploy_envs.identifier"}}})
 | |
|     q = []
 | |
|     unless names.nil?
 | |
|       q.push({
 | |
|         "$match" => {
 | |
|           "_id" => {
 | |
|             "$in" => names
 | |
|           }
 | |
|         }
 | |
|       })
 | |
|     end
 | |
|     q.push({
 | |
|       "$unwind" =>  "$deploy_envs"
 | |
|     })
 | |
|     q.push({
 | |
|       "$project" => {
 | |
|         "deploy_envs.identifier" => 1
 | |
|       }
 | |
|     })
 | |
|     q.push({
 | |
|       "$group" => {
 | |
|         "_id" => "$_id",
 | |
|         "envs" => {
 | |
|           "$addToSet" => "$deploy_envs.identifier"
 | |
|         }
 | |
|       }
 | |
|     })
 | |
|     res = @projects.aggregate(q)
 | |
|     r = {}
 | |
|     res.each do |ar|
 | |
|       r[ar["_id"]] = ar["envs"]
 | |
|     end
 | |
|     return r
 | |
|   end
 | |
| 
 | |
|   def projects_by_image image
 | |
|     @projects.find(create_query("deploy_envs.image" => image)).to_a.map {|bp| Project.create_from_bson bp}
 | |
|   end
 | |
| 
 | |
|   def projects_by_user user
 | |
|     @projects.find(create_query("deploy_envs.users" => user)).to_a.map {|bp| Project.create_from_bson bp}
 | |
|   end
 | |
| 
 | |
|   def project_delete name
 | |
|     r = @projects.remove(create_query("_id" => name))
 | |
|     raise RecordNotFound.new("Project '#{name}' not found") if r["n"] == 0
 | |
|   end
 | |
| 
 | |
|   def project_update project
 | |
|     project.validate!
 | |
|     @projects.update(create_query({"_id" => project.id}), project.to_mongo_hash)
 | |
|   rescue Mongo::OperationFailure => e
 | |
|     if e.message =~ /^11000/
 | |
|       raise InvalidRecord.new("Duplicate key error: project with id '#{project.id}'")
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def servers_find q, fields
 | |
|     @servers.find(create_query(q), :fields => fields).to_a.map{|bs| Server.create_from_bson bs}
 | |
|   end
 | |
| 
 | |
|   def servers p=nil, env=nil, names=nil, reserved=nil, fields=[]
 | |
|     q = {}
 | |
|     q["project"] = p unless p.nil? or p.empty?
 | |
|     q["deploy_env"] = env unless env.nil? or env.empty?
 | |
|     q["chef_node_name"] = {"$in" => names} unless names.nil? or names.class != Array
 | |
|     q["reserved_by"] = {"$ne" => nil} unless reserved.nil?
 | |
|     ["_id", "chef_node_name"].each do |k|
 | |
|       fields.push(k) unless fields.include?(k)
 | |
|     end
 | |
|     servers_find(q, fields)
 | |
|   end
 | |
| 
 | |
|   def servers_by_names names
 | |
|     q = {}
 | |
|     q["chef_node_name"] = {"$in" => names} unless names.nil? or names.class != Array
 | |
|     @servers.find(create_query(q)).to_a.map{|bs| Server.create_from_bson bs}
 | |
|   end
 | |
| 
 | |
|   def server_by_instance_id id
 | |
|     find_server "_id" => id
 | |
|   end
 | |
| 
 | |
|   def server_by_chef_node_name name
 | |
|     find_server "chef_node_name" => name
 | |
|   end
 | |
| 
 | |
|   def servers_by_key key_name
 | |
|     @servers.find(create_query("key" => key_name)).to_a.map {|bs| Server.create_from_bson bs}
 | |
|   end
 | |
| 
 | |
|   def server_insert s
 | |
|     #s.validate!
 | |
|     s.created_at = Time.now
 | |
|     @servers.insert(create_query(s.to_mongo_hash))
 | |
|   end
 | |
| 
 | |
|   def server_delete id
 | |
|     @servers.remove(create_query("_id" => id))
 | |
|   end
 | |
| 
 | |
|   def server_update server
 | |
|     @servers.update({"_id" => server.id}, server.to_hash_without_id)
 | |
|   end
 | |
| 
 | |
|   def keys
 | |
|     @keys.find(create_query).to_a.map {|bi| Key.create_from_bson bi}
 | |
|   end
 | |
| 
 | |
|   def key id, scope=nil
 | |
|     q = {
 | |
|       "_id" => id
 | |
|     }
 | |
|     q["scope"] = scope unless scope.nil?
 | |
|     k = @keys.find(create_query(q)).to_a[0]
 | |
|     raise RecordNotFound.new("Key '#{id}' does not exist") if k.nil?
 | |
|     Key.create_from_bson k
 | |
|   end
 | |
| 
 | |
|   def key_insert key
 | |
|     key.validate!
 | |
|     @keys.insert(create_query(key.to_mongo_hash))
 | |
|   rescue Mongo::OperationFailure => e
 | |
|     if e.message =~ /^11000/
 | |
|       raise InvalidRecord.new("Duplicate key error: key with id '#{key.id}'")
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def key_delete id
 | |
|     r = @keys.remove(create_query("_id" => id, "scope" => Key::USER))
 | |
|     raise RecordNotFound.new("Key '#{id}' not found") if r["n"] == 0
 | |
|     r
 | |
|   end
 | |
| 
 | |
|   def user_auth user, password
 | |
|     u = @users.find("_id" => user, "password" => password).to_a[0]
 | |
|     raise RecordNotFound.new("Invalid username or password") if u.nil?
 | |
|   end
 | |
| 
 | |
|   def user id
 | |
|     u = @users.find("_id" => id).to_a[0]
 | |
|     raise RecordNotFound.new("User '#{id}' does not exist") if u.nil?
 | |
|     User.create_from_bson u
 | |
|   end
 | |
| 
 | |
|   def users array=nil
 | |
|     q = {}
 | |
|     q["_id"] = {"$in" => array} if array.is_a?(Array)
 | |
|     @users.find(q).to_a.map {|bi| User.create_from_bson bi}
 | |
|   end
 | |
| 
 | |
|   def users_names array=nil
 | |
|     q = {}
 | |
|     q["_id"] = {"$in" => array} if array.is_a?(Array)
 | |
|     @users.find({}, :fields => ["_id"]).to_a.map{|u| u["_id"]}
 | |
|   end
 | |
| 
 | |
|   def user_insert user
 | |
|     user.validate!
 | |
|     @users.insert(user.to_mongo_hash)
 | |
|     rescue Mongo::OperationFailure => e
 | |
|       if e.message =~ /^11000/
 | |
|         raise InvalidRecord.new("Duplicate key error: user with id '#{user.id}'")
 | |
|       end
 | |
|   end
 | |
| 
 | |
|   def user_delete id
 | |
|     r = @users.remove("_id" => id)
 | |
|     raise RecordNotFound.new("User '#{id}' not found") if r["n"] == 0
 | |
|     r
 | |
|   end
 | |
| 
 | |
|   def user_update user
 | |
|     user.validate!
 | |
|     @users.update({"_id" => user.id}, user.to_mongo_hash)
 | |
|   rescue Mongo::OperationFailure => e
 | |
|     if e.message =~ /^11000/
 | |
|       raise InvalidRecord.new("Duplicate key error: user with id '#{user.id}'")
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def create_root_user
 | |
|     begin
 | |
|       u = user("root")
 | |
|     rescue RecordNotFound => e
 | |
|       root = User.create_root
 | |
|       @users.insert(root.to_mongo_hash)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def check_user_privileges id, cmd, priv
 | |
|     user = self.user(id)
 | |
|     case priv
 | |
|     when "r", "w", "x"
 | |
|       raise InvalidPrivileges.new("Access denied for '#{user.id}'") unless user.check_privilege cmd, priv
 | |
|     else
 | |
|       raise InvalidPrivileges.new("Access internal problem with privilege '#{priv}'")
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def check_project_auth project_id, env, user_id
 | |
|     p = @projects.find(create_query("_id" => project_id)).to_a[0]
 | |
|     raise RecordNotFound.new("Project '#{project_id}' does not exist") if p.nil?
 | |
|     project = Project.create_from_bson p
 | |
|     raise InvalidPrivileges.new("User '#{user_id}' unauthorized to work with project '#{project_id}'") unless project.check_authorization(user_id, env)
 | |
|     project
 | |
|   end
 | |
| 
 | |
|   def statistic user, path, method, body, response_code
 | |
|     @statistic.insert({:user => user, :path => path, :method => method, :body => body, :response_code => response_code, :date => Time.now})
 | |
|   end
 | |
| 
 | |
| private
 | |
|   def find_server params
 | |
|     s = @servers.find(create_query(params)).to_a[0]
 | |
|     if s.nil?
 | |
|       if params.has_key? "_id"
 | |
|         raise RecordNotFound.new("No server by instance id '#{params["_id"]}' found")
 | |
|       elsif params.has_key? "chef_node_name"
 | |
|         raise RecordNotFound.new("No server by node name '#{params["chef_node_name"]}' found")
 | |
|       end
 | |
|     end
 | |
|     Server.create_from_bson s
 | |
|   end
 | |
| 
 | |
|   def create_query q={}
 | |
|     q
 | |
|   end
 | |
| 
 | |
|   def create_query_with_provider provider, q={}
 | |
|     q["provider"] = provider
 | |
|     q
 | |
|   end
 | |
| end
 | 
