incubator-blur-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cr...@apache.org
Subject [47/53] [partial] Initial commit of console v2. Sorry for the large commit
Date Mon, 17 Feb 2014 16:07:23 GMT
http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/controllers/blur_queries_controller.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/controllers/blur_queries_controller.rb b/contrib/blur-console-v1/blur-admin/app/controllers/blur_queries_controller.rb
new file mode 100644
index 0000000..08d237f
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/controllers/blur_queries_controller.rb
@@ -0,0 +1,58 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+class BlurQueriesController < ApplicationController
+  load_and_authorize_resource :through => :current_zookeeper,
+                              :shallow => true, :except => :refresh
+
+  before_filter :zookeepers, :only => :index
+
+  respond_to :html, :only => [:index, :show, :cancel]
+  respond_to :json, :only => [:refresh, :show]
+
+  def index
+    respond_with(@blur_queries)
+  end
+
+  def refresh
+    lower_range = params[:time_length].to_i.minute.ago
+    query_summaries = current_zookeeper.refresh_queries(lower_range).collect do |query| 
+      summary = query.summary(current_user)
+      summary[:action] = ''
+      summary
+    end
+
+    respond_with(query_summaries) do |format|
+      # Root node aaData is for the datatable library
+      format.json { render :json => { :aaData => query_summaries } }
+    end
+  end
+
+  def show
+    respond_with(@blur_query) do |format|
+      format.html { render :partial => 'show' }
+      format.json { render :json => @blur_query.summary(current_user) }
+    end
+  end
+
+  def cancel
+    @blur_query.cancel
+    Audit.log_event(current_user, "BlurQuery with UUID #{@blur_query.uuid}) was canceled",
+                    "blur_query", "update", current_zookeeper)
+
+    respond_with(@blur_query) do |format|
+      format.html { render :partial => 'blur_query' }
+    end
+  end
+end

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/controllers/blur_shards_controller.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/controllers/blur_shards_controller.rb b/contrib/blur-console-v1/blur-admin/app/controllers/blur_shards_controller.rb
new file mode 100644
index 0000000..251f18a
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/controllers/blur_shards_controller.rb
@@ -0,0 +1,35 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+class BlurShardsController < ApplicationController
+  load_and_authorize_resource :cluster
+  load_and_authorize_resource :through => :cluster, :shallow => true
+
+  respond_to :json
+
+  def index
+    respond_with(@blur_shards) do |format|
+      format.json { render :json => @blur_shards, :except => :cluster_id }
+    end
+  end
+
+  def destroy
+    raise "Cannot Remove A Shard that is online!" if @blur_shard.shard_status == 1
+    @blur_shard.destroy
+    Audit.log_event(current_user, "Shard (#{@blur_shard.node_name}) was forgotten",
+                    "shard", "delete", @blur_shard.zookeeper) if @blur_shard.destroyed?
+
+    respond_with(@blur_shard)
+  end
+end
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/controllers/blur_tables_controller.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/controllers/blur_tables_controller.rb b/contrib/blur-console-v1/blur-admin/app/controllers/blur_tables_controller.rb
new file mode 100644
index 0000000..4c0a7fc
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/controllers/blur_tables_controller.rb
@@ -0,0 +1,108 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+class BlurTablesController < ApplicationController
+  load_and_authorize_resource :shallow => true, :only => [:comment, :terms, :hosts, :schema]
+
+  before_filter :zookeepers, :only => :index
+
+  respond_to :html, :only => [:index]
+  respond_to :json
+
+  def index
+    @clusters = current_zookeeper.clusters_with_query_status(current_user)
+    respond_with(@clusters) do |format|
+      format.json { render :json => @clusters, :methods => [:blur_tables], :blur_tables => true }
+    end
+  end
+
+  def enable
+    table_update_action do |table|
+      table.table_status = STATUS[:enabling]
+      table.enable current_zookeeper.blur_urls
+      table.save
+      Audit.log_event(current_user, "Table, #{table.table_name}, was enabled",
+                      "blur_table", "update", current_zookeeper)
+    end
+  end
+
+  def disable
+    table_update_action do |table|
+      table.table_status = STATUS[:disabling]
+      table.disable current_zookeeper.blur_urls
+      table.save
+      Audit.log_event(current_user, "Table, #{table.table_name}, was disabled",
+                      "blur_table", "update", current_zookeeper)
+    end
+  end
+
+  def destroy
+    destroy_index = params[:delete_index] == 'true' # Destroy underlying index boolean
+    tables = params[:tables]                        # Tables being destroyed
+    blur_urls = current_zookeeper.blur_urls         # Cached blur_urls
+
+    BlurTable.find(tables).each do |table|
+      table.blur_destroy destroy_index, blur_urls
+      index_message = "and underlying index " if destroy_index
+      Audit.log_event(current_user, "Table, #{table.table_name}, #{index_message}was deleted",
+                      "blur_table", "update", current_zookeeper)
+    end
+    BlurTable.destroy tables
+
+    respond_to do |format|
+      format.json { render :json => {} }
+    end
+  end
+
+  def terms
+    terms = @blur_table.terms current_zookeeper.blur_urls, params[:family], params[:column], params[:startwith], params[:size].to_i
+
+    respond_with(terms)
+  end
+
+  def hosts
+    respond_with(@blur_table) do |format|
+      format.json { render :json => @blur_table.hosts }
+    end
+  end
+
+  def schema
+    respond_with(@blur_table) do |format|
+      format.json { render :json => @blur_table.schema }
+    end
+  end
+
+  def comment
+    raise "No comment provided!" if params[:comment].nil?
+    @blur_table.comments = params[:comment]
+    @blur_table.save
+
+    respond_with(@table)
+  end
+
+  private
+
+  STATUS = {:enabling => 5, :active => 4, :disabling => 3, :disabled => 2, :deleting => 1, :deleted => 0}
+  STATUS_SELECTOR = {:active => [4, 3], :disabled => [2, 5, 1], :deleted => [0]}
+
+  def table_update_action
+    BlurTable.find(params[:tables]).each do |table|
+      yield table
+    end
+
+    respond_to do |format|
+      format.json { render :json => {} }
+    end
+  end
+end

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/controllers/clusters_controller.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/controllers/clusters_controller.rb b/contrib/blur-console-v1/blur-admin/app/controllers/clusters_controller.rb
new file mode 100644
index 0000000..a4b9332
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/controllers/clusters_controller.rb
@@ -0,0 +1,27 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+class ClustersController < ApplicationController
+  load_and_authorize_resource
+
+  respond_to :json
+
+  def destroy
+    raise "Cannot Remove A Cluster that is online!" if @cluster.cluster_status == 1
+    @cluster.destroy
+    Audit.log_event(current_user, "Cluster (#{@cluster.name}) was forgotten",
+                    "cluster", "delete", @cluster.zookeeper) if @cluster.destroyed?
+    respond_with(@cluster)
+  end
+end
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/controllers/errors_controller.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/controllers/errors_controller.rb b/contrib/blur-console-v1/blur-admin/app/controllers/errors_controller.rb
new file mode 100644
index 0000000..4c2cd40
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/controllers/errors_controller.rb
@@ -0,0 +1,31 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+class ErrorsController < ApplicationController
+  respond_to :json, :html
+
+  def error_404
+    render :error_404, :status => :not_found
+  end
+
+  def error_500
+    @error = env["action_dispatch.exception"]
+    @status_code = ActionDispatch::ExceptionWrapper.new(env, @exception).status_code
+    render :error_500, :status => 500
+  end
+
+  def error_422
+    render :error_422, :status => 422
+  end
+end

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/controllers/hdfs_controller.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/controllers/hdfs_controller.rb b/contrib/blur-console-v1/blur-admin/app/controllers/hdfs_controller.rb
new file mode 100644
index 0000000..1f0c5a1
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/controllers/hdfs_controller.rb
@@ -0,0 +1,176 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+class HdfsController < ApplicationController
+  require 'hdfs_thrift_client'
+  load_and_authorize_resource :shallow => true
+
+  HTML_REPONSES = [:info, :folder_info, :expand, :file_info, :upload_form, :upload]
+  respond_to :html, :only => (HTML_REPONSES + [:index])
+  respond_to :json, :except => HTML_REPONSES
+
+  include ActionView::Helpers::NumberHelper
+
+  def index
+    respond_with do |format|
+      format.json { render :json => @hdfs, :methods => [:most_recent_stats, :recent_stats] }
+    end
+  end
+
+  def info
+    @hdfs_stat = @hdfs.hdfs_stats.last
+    respond_with(@hdfs_stat) do |format|
+      format.html do
+        if @hdfs_stat
+          render :partial => 'info'
+        else
+          render :text => "<div>Stats for hdfs ##{params[:id]} were not found, is the blur tools agent running?</div>"
+        end
+      end
+    end
+  end
+
+  def folder_info
+    client = build_client_from_id
+    path = params[:fs_path]
+
+    @stat = client.stat path
+    respond_with(@stat) do |format|
+      format.html{ render :partial => 'folder_info' }
+    end
+  end
+
+  def slow_folder_info
+    client = build_client_from_id
+    path = params[:fs_path]
+    file_stats = client.ls(path, true)
+    file_size = 0
+    stats_hash = {:file_size => 0, :file_count => 0, :folder_count => 0}
+
+    file_stats.each do |stat|
+      file_size += stat.length
+      stats_hash[:file_count] += 1 unless stat.isdir
+      stats_hash[:folder_count] += 1 if stat.isdir
+    end
+    stats_hash[:file_size] = number_to_human_size file_size
+
+    respond_with(stats_hash)
+  end
+
+  def expand
+    @hdfs_id = params[:id]
+    @path = params[:fs_path] || '/'
+    @path += '/' unless @path.last=='/'
+    client = build_client_from_id
+    fileStats = client.ls(@path)
+
+    @children = fileStats.collect do |stat|
+      file_ending = stat.path.split('/').last
+      {:name=> file_ending, :is_dir=>stat.isdir}
+    end
+    @children.sort_by! {|c| [c[:is_dir] ? 1:0, c[:name].downcase]}
+
+    respond_with do |format|
+      format.html { render :partial => 'expand' }
+    end
+  end
+
+  def mkdir
+    client = build_client_from_id
+    path = "#{params[:fs_path]}/#{params[:folder]}/"
+    path.gsub!(/\/\//, "/")
+    client.mkdirs(path)
+    Audit.log_event(current_user, "A folder, #{params[:folder]}, was created",
+      "hdfs", "create", @hdfs)
+
+    respond_with do |format|
+      format.json { render :json => {} }
+    end
+  end
+
+  def file_info
+    client = build_client_from_id
+    @stat = client.stat params[:fs_path]
+    respond_with do |format|
+      format.html { render :partial => 'file_info' }
+    end
+  end
+
+  def move_file
+    file_name = params[:from].strip.split("/").last
+    client = build_client_from_id
+    client.rename(params[:from], params[:to].gsub(/(\/$)/, '') + '/' + file_name)
+    Audit.log_event(current_user, "File/Folder, #{file_name}, was moved or renamed to #{params[:to]}",
+      "hdfs", "update", @hdfs)
+
+    respond_with do |format|
+      format.json { render :json => {} }
+    end
+  end
+
+  def delete_file
+    client = build_client_from_id
+    path = params[:path]
+    client.delete path, true
+    file_name = params[:path].strip.split("/").last
+    Audit.log_event(current_user, "File/Folder, #{file_name}, was deleted",
+      "hdfs", "delete", @hdfs)
+
+    respond_with do |format|
+      format.json { render :json => {} }
+    end
+  end
+
+  def upload_form
+    respond_with do |format|
+      format.html { render :partial => 'upload_form' }
+    end
+  end
+
+  def upload
+    begin
+      if !(params[:upload].nil? or params[:path].nil? or params[:id].nil?)
+        f = params[:upload]
+        @path = params[:path].gsub(/(\/$)/, '')
+        if f.tempfile.size > 26214400
+          @error = 'Upload is Too Large.  Files must be less than 25Mb.'
+        else
+          client = build_client_from_id
+          client.put(f.tempfile.path, @path + '/' + f.original_filename)
+          Audit.log_event(current_user, "File, #{f.original_filename}, was uploaded",
+            "hdfs", "create", @hdfs)
+        end
+      else
+        @error = 'Problem with File Upload'
+      end
+    rescue Exception => e
+      @error = e.to_s
+    end
+    respond_with do |format|
+      format.html { render :partial => 'upload' }
+    end
+  end
+
+  def file_tree
+    client = build_client_from_id
+    file_structure = client.folder_tree params[:fs_path], 4
+    respond_with(file_structure)
+  end
+
+  private
+  def build_client_from_id
+    HdfsThriftClient.client("#{@hdfs.host}:#{@hdfs.port}")
+  end
+end
+

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/controllers/hdfs_metrics_controller.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/controllers/hdfs_metrics_controller.rb b/contrib/blur-console-v1/blur-admin/app/controllers/hdfs_metrics_controller.rb
new file mode 100644
index 0000000..541acbb
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/controllers/hdfs_metrics_controller.rb
@@ -0,0 +1,51 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+class HdfsMetricsController < ApplicationController
+  respond_to :html, :only => [:index]
+  respond_to :json, :only => [:stats]
+
+  def index
+    @hdfs_index = Hdfs.all
+    respond_with(@hdfs_index)
+  end
+
+  def stats
+    @results = hdfs_stat_select [:present_capacity, :dfs_used_real, :live_nodes, :dead_nodes, :under_replicated, :corrupt_blocks, :missing_blocks]
+    respond_with(@results) do |format|
+      format.json { render :json => @results, :methods => [:capacity, :used], :except => [:present_capacity, :dfs_used] }
+    end
+  end
+
+  private
+  def hdfs_stat_select(properties)
+    hdfs = Hdfs.find params[:id]
+    properties = [:id, :created_at] + properties
+
+    if params[:stat_id]
+      where_clause = "id > #{params[:stat_id]}"
+    else
+      where_clause = "created_at >= '#{params[:stat_min].to_i.minute.ago}'"
+      where_clause += " and created_at < '#{params[:stat_max].to_i.minute.ago}'" if params[:stat_max]
+    end
+
+    stat_number = hdfs.hdfs_stats.where(where_clause).select("count(*) as count")
+    if stat_number.count >= 700
+      remove_number = (stat_number.count / 700).floor
+      where_clause += " and hdfs_stats.id % #{remove_number} = 0"
+    end
+
+    return hdfs.hdfs_stats.where(where_clause).select(properties)
+  end
+end

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/controllers/preferences_controller.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/controllers/preferences_controller.rb b/contrib/blur-console-v1/blur-admin/app/controllers/preferences_controller.rb
new file mode 100644
index 0000000..a0e1dfb
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/controllers/preferences_controller.rb
@@ -0,0 +1,35 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+class PreferencesController < ApplicationController
+  load_and_authorize_resource
+
+  respond_to :json
+
+  def update
+    @preference = Preference.find_by_pref_type_and_user_id params[:pref_type], params[:user_id]
+    updated_attr = {:value => params['value']}
+    
+    # Zookeeper pref uses the name as a data store
+    if params[:pref_type] == 'zookeeper'
+      updated_attr[:name] = params['name']
+      puts params['value']
+      set_zookeeper params['value']
+    end
+    @preference.try(:update_attributes, updated_attr)
+    respond_with(@preference) do |format|
+      format.json { render :json => {} }
+    end
+  end
+end

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/controllers/searches_controller.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/controllers/searches_controller.rb b/contrib/blur-console-v1/blur-admin/app/controllers/searches_controller.rb
new file mode 100644
index 0000000..00495bc
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/controllers/searches_controller.rb
@@ -0,0 +1,219 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+class SearchesController < ApplicationController
+  load_and_authorize_resource :only => [:show, :destroy]
+
+  before_filter :zookeepers, :only => :index
+  before_filter :clean_column_data, :only => [:save, :update]
+
+  JSON_RESPONSES = [:filters, :show, :update]
+  respond_to :html, :except => JSON_RESPONSES
+  respond_to :json, :only => JSON_RESPONSES
+
+  #Show action that sets instance variables used to build the filter column
+  def index
+    # the .all call executes the SQL fetch, otherwise there are many more SQL fetches
+    # required because of the lazy loading (in this case where a few more variables
+    # depend on the result)
+    @search_filter = AdminSetting.search_filter
+    @blur_tables = current_zookeeper.blur_tables.where('table_status = 4').order("table_name").includes(:cluster).all
+    @blur_table = BlurTable.find_by_id(params[:table_id])
+    if @blur_table.nil?
+      @blur_table = @blur_tables[0]
+      @query = ''
+    else
+      @query = params[:query].nil? ? '' : params[:query]
+    end
+    @columns = @blur_table.schema &preference_sort(current_user.column_preference.value || []) if @blur_table
+    @searches = current_user.searches.order("name")
+    @filter_table_collection = {}
+    @blur_tables.each do |table|
+        @filter_table_collection[table.cluster.name] ||= []
+        @filter_table_collection[table.cluster.name] << [table.table_name, table.id]
+    end
+    respond_with
+  end
+
+  #Filter action to help build the tree for column families
+  def filters
+    blur_table = BlurTable.find params[:blur_table]
+    preference = current_user.column_preference
+    columns = blur_table ? (blur_table.schema &preference_sort(preference.value || [])) : []
+    selected_count = 0
+    first_selected = preference.value.nil?
+    filter_children = columns.collect do |family|
+      if preference.value && !preference.value.index(family['name']).nil?
+        selected = true
+        selected_count += 1
+      end
+      col_fam = {:title => family['name'], :key => "family_-sep-_#{family['name']}", :addClass => 'check_filter', :select => (first_selected || selected)}
+      col_fam[:children] = family['columns'].collect do |column|
+        {:title => column['name'], :key => "column_-sep-_#{family['name']}_-sep-_#{column['name']}", :addClass=>'check_filter', :select => (first_selected || selected)}
+      end
+      first_selected = false
+      col_fam
+    end
+    all_selected = selected_count == filter_children.length
+    filter_list = { :title => 'All Families', :key => "neighborhood", :addClass => 'check_filter', :select => all_selected, :children => filter_children}
+    respond_with(filter_list)
+  end
+
+  #Create action is a large action that handles all of the filter data
+  #and either saves the data or performs a search
+  def create
+    search_filter = AdminSetting.search_filter
+    blur_table = BlurTable.find params[:blur_table]
+    if blur_table.table_name.match(search_filter.value).nil? && params[:query_string].match(/:\*$|^\*$/)
+      raise "The table #{blur_table.table_name} is Star Protected, Contact your admin!"
+    end
+
+    params[:column_data].delete( "neighborhood") if params[:column_data]
+    search = Search.new(  :super_query      => params[:search] == '0',
+                          :record_only      => params[:search] == '1' && params[:return] == '1',
+                          :fetch            => params[:result_count].to_i,
+                          :offset           => params[:offset].to_i,
+                          :user_id          => current_user.id,
+                          :query            => params[:query_string],
+                          :blur_table_id    => params[:blur_table],
+                          :pre_filter       => params[:pre_filter],
+                          :post_filter      => params[:post_filter]
+                         )
+    search.column_object = params[:column_data]
+
+    blur_results = search.fetch_results(blur_table.table_name, current_zookeeper.blur_urls)
+
+    # parse up the response object and reformat it to be @results.  @results holds the data
+    # that will be passed to the view. @results is an array of results. Each result is a series
+    # of nested hashes/arrays:
+    #   result = {:id, :max_record_count, :column_families => column_families}
+    #   column_families = {:column_family_name => [record]}
+    #   record = {:recordId => recordId, :column_name => value}
+
+    @result_count = blur_results.totalResults
+    @result_time = -1 #blur_results.realTime
+    @results = []
+    blur_results.results.each do |blur_result_container|
+
+      # drill down through the result object cruft to get the real result
+      if !search.record_only
+        blur_result = blur_result_container.fetchResult.rowResult.row
+        records = blur_result.records
+        id = blur_result.id
+      else
+        blur_result = blur_result_container.fetchResult.recordResult
+        records = [blur_result.record]
+        id = blur_result.rowid
+      end
+
+      # continue to next result if there is no returned data
+      next if records.empty?
+
+      max_record_count = records.
+        collect {|record| record.family}.
+        reduce(Hash.new(0)) {|count, family| count[family] += 1; count}.
+        values.max
+
+      result = {:max_record_count => max_record_count, :id => id}
+
+      records.each do |blur_record|
+        column_family = blur_record.family
+        unless column_family.nil? # to compensate for a bug in blur that returns empty records if a column family is not selected
+          record = {'recordId' => blur_record.recordId}
+          blur_record.columns.each do |blur_column|
+            record[blur_column.name] = blur_column.value
+          end
+          result[column_family] = [] unless result[column_family]
+          result[column_family] << record
+        end
+      end
+      @results << result
+    end
+    pref_sort = preference_sort(current_user.column_preference.value || [])
+    @schema = Hash[search.schema(blur_table).sort &pref_sort]
+    respond_with do |format|
+      format.html { render 'create', :layout => false }
+    end
+  end
+
+  #save action that loads the state of a saved action and returns a json to be used to populate the form
+  def show
+    respond_with(@search) do |format|
+      format.json { render :json => @search, :methods => :column_object }
+    end
+  end
+
+  #Delete action used for deleting a saved search from a user's saved searches
+  def destroy
+    @search.destroy
+    @searches = current_user.searches.reverse
+    respond_with(@searches) do |format|
+      format.html { render :partial => "saved" }
+    end
+  end
+
+  def save
+    search = Search.new(:name             => params[:save_name],
+                        :super_query      => params[:search] == '0',
+                        :record_only      => params[:search] == '1' && params[:return] == '1',
+                        :fetch            => params[:result_count].to_i,
+                        :offset           => params[:offset].to_i,
+                        :user_id          => current_user.id,
+                        :query            => params[:query_string],
+                        :blur_table_id    => params[:blur_table],
+                        :pre_filter       => params[:pre_filter],
+                        :post_filter      => params[:post_filter])
+    search.column_object = params[:column_data]
+    search.save
+    @searches = current_user.searches.reverse
+
+    respond_with(@searches) do |format|
+      format.html { render :partial =>"saved" }
+    end
+  end
+
+  def update
+    Search.update(params[:id],
+                        :name               => params[:save_name],
+                        :super_query        => params[:search] == '0',
+                        :record_only        => params[:search] == '1' && params[:return] == '1',
+                        :fetch              => params[:result_count].to_i,
+                        :offset             => params[:offset].to_i,
+                        :user_id            => current_user.id,
+                        :query              => params[:query_string],
+                        :column_object      => params[:column_data],
+                        :blur_table_id      => params[:blur_table],
+                        :pre_filter       => params[:pre_filter],
+                        :post_filter      => params[:post_filter])
+    respond_with do |format|
+      format.json { render :json => {} }
+    end
+  end
+  private
+    def preference_sort(preferred_columns)
+      lambda do |a, b|
+        if preferred_columns.include? a[0] and !preferred_columns.include? b[0]
+          -1
+        elsif preferred_columns.include? b[0] and !preferred_columns.include? a[0]
+          1
+        else
+          preferred_columns.index(a[0]) <=> preferred_columns.index(b[0])
+        end
+      end
+    end
+
+    def clean_column_data
+      params[:column_data].delete 'neighborhood'
+    end
+end

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/controllers/user_sessions_controller.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/controllers/user_sessions_controller.rb b/contrib/blur-console-v1/blur-admin/app/controllers/user_sessions_controller.rb
new file mode 100644
index 0000000..24d751d
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/controllers/user_sessions_controller.rb
@@ -0,0 +1,39 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+class UserSessionsController < ApplicationController
+  respond_to :html
+
+  def new
+    respond_with(@user_session = UserSession.new)
+  end
+
+  def create
+    @user_session = UserSession.new params[:user_session]
+    saved = @user_session.save
+    flash[:notice] = "Successfully Logged In" if saved
+    # Redirects to path on save otherwise it goes to login
+    respond_with(@user_session, :location => login_path) do |format|
+      # Hack to fork the location on error and success
+      format.html { redirect_to root_path } if saved
+    end
+  end
+
+  def destroy
+    current_user_session.destroy
+    reset_session
+    redirect_to login_path, :notice => "Successfully Logged Out"
+  end
+
+end

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/controllers/users_controller.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/controllers/users_controller.rb b/contrib/blur-console-v1/blur-admin/app/controllers/users_controller.rb
new file mode 100644
index 0000000..7f1e9f4
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/controllers/users_controller.rb
@@ -0,0 +1,71 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+class UsersController < ApplicationController
+  load_and_authorize_resource
+
+  before_filter :zookeepers, :only => :show
+
+  respond_to :html
+
+  def index
+    @search_filter = AdminSetting.search_filter
+    respond_with(@users)
+  end
+
+  def show
+    @column_preference = @user.column_preference
+    @zookeeper_preference = @user.zookeeper_preference
+    @choices = BlurTable.select('table_schema').collect {|table| schema = table.schema; schema.collect{|familes| familes['name']} if schema}.flatten.uniq
+    respond_with(@user)
+  end
+
+  def new
+    @user = User.new
+  end
+
+  def create
+    if @user.save
+      if can? :index, :users
+        redirect_to users_path, :notice => "User Created"
+      else
+        redirect_to @user, :notice => "User Created"
+      end
+    else
+      render 'new'
+    end
+  end
+
+  def update
+    if @user.update_attributes(params[:user])
+      Audit.log_event(current_user, "User, #{@user.username}, had their roles updated",
+        "users", "update", current_zookeeper)
+      if can? :index, :users
+        redirect_to users_path, :notice => "User Updated"
+      else
+        redirect_to @user, :notice => "User Updated"
+      end
+    else
+      render 'edit'
+    end
+  end
+
+  def destroy
+    @user.destroy
+    Audit.log_event(current_user, "User, #{@user.username}, was removed",
+      "users", "delete", current_zookeeper)
+    flash[:notice] = "User Removed"
+    respond_with(@user)
+  end
+end

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/controllers/zookeepers_controller.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/controllers/zookeepers_controller.rb b/contrib/blur-console-v1/blur-admin/app/controllers/zookeepers_controller.rb
new file mode 100644
index 0000000..91aa58b
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/controllers/zookeepers_controller.rb
@@ -0,0 +1,50 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+class ZookeepersController < ApplicationController
+  load_and_authorize_resource :only => [:index, :destroy, :long_running_queries, :show], :shallow => true
+
+  before_filter :set_zookeeper_with_preference, :only => :index
+
+  respond_to :html, :only => [:index, :show]
+  respond_to :json
+
+  def index
+    set_zookeeper Zookeeper.first.id if Zookeeper.count == 1
+    respond_with do |format|
+      format.json { render :json => Zookeeper.dashboard_stats }
+    end
+  end
+
+  def show
+    @zookeepers = Zookeeper.all
+    set_zookeeper params[:id]
+    respond_with(@zookeeper) do |format|
+      format.json { render :json => @zookeeper, :methods => [:clusters, :blur_controllers] }
+    end
+  end
+
+  def destroy
+    raise "Cannot Remove A Zookeeper that is online!" if @zookeeper.zookeeper_status == 1
+    @zookeeper.destroy
+    Audit.log_event(current_user, "Zookeeper (#{@zookeeper.name}) was forgotten", "zookeeper", "delete", @zookeeper) if @zookeeper.destroyed?
+    respond_with(@zookeeper)
+  end
+
+  def long_running_queries
+    respond_with(@zookeeper) do |format|
+      format.json { render :json => @zookeeper.long_running_queries(current_user) }
+    end
+  end
+end

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/helpers/application_helper.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/helpers/application_helper.rb b/contrib/blur-console-v1/blur-admin/app/helpers/application_helper.rb
new file mode 100644
index 0000000..d97f8b2
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/helpers/application_helper.rb
@@ -0,0 +1,35 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+module ApplicationHelper
+  def pluralize_no_count(count, singular, plural = nil)
+    ((count == 1 || count == '1') ? singular : (plural || singular.pluralize))
+  end
+
+  def stateful_nav_url(page)
+    return '' if session[:current_zookeeper_id].nil?
+    case page
+    when 'environment'
+      return zookeeper_path(session[:current_zookeeper_id])
+    when 'blur_table'
+      return zookeeper_blur_tables_path(session[:current_zookeeper_id])
+    when 'blur_query'
+      return zookeeper_blur_queries_path(session[:current_zookeeper_id])
+    when 'search'
+      return zookeeper_searches_path(session[:current_zookeeper_id])
+    else
+      return ''
+    end
+  end
+end
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/helpers/blur_query_helper.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/helpers/blur_query_helper.rb b/contrib/blur-console-v1/blur-admin/app/helpers/blur_query_helper.rb
new file mode 100644
index 0000000..2b015a1
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/helpers/blur_query_helper.rb
@@ -0,0 +1,25 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+module BlurQueryHelper
+  def format_title(query_string)
+    query_string.length() > 20 ? query_string.gsub(/ \+/) {'<br />+'} : ''
+  end
+
+  def print_value(conditional, default_message = "Not Available")
+    return default_message unless conditional
+    return conditional unless block_given?
+    yield
+  end
+end

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/models/ability.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/models/ability.rb b/contrib/blur-console-v1/blur-admin/app/models/ability.rb
new file mode 100644
index 0000000..e69c3e5
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/models/ability.rb
@@ -0,0 +1,83 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+class Ability
+  include CanCan::Ability
+
+  def initialize(user)
+    #Anybody
+    can [:error_404, :error_422, :error_500], :errors
+
+    if user # logged in
+      # view, edit, and destroy own account
+      can [:show, :edit, :destroy], :users, :id => user.id
+
+      # edit own username, email, password
+      can :update, :users, [:username, :name, :email, :password, :password_confirmation], :id => user.id
+
+      # logout
+      can :destroy, :user_sessions
+
+      if user.reader?
+        # view pages
+        can :index, [:zookeepers, :blur_tables, :hdfs, :hdfs_metrics]
+        can :show, [:zookeepers, :clusters]
+        can :long_running_queries, :zookeepers
+        can [:expand, :file_info, :info, :folder_info, :slow_folder_info, :file_tree], :hdfs
+        can :stats, :hdfs_metrics
+        can :help, :application
+
+        # can view everything but query_string on blur_tables:
+        attributes = BlurQuery.new.attribute_names.collect{|att| att.to_sym}
+        attributes.delete :query_string
+        can [:index, :show], :blur_queries, attributes
+
+        can :refresh, :blur_queries
+        can [:terms, :hosts, :schema], :blur_tables
+      end
+
+      if user.editor?
+        can [:enable, :disable, :destroy, :comment], :blur_tables
+        can :cancel, :blur_queries
+        can :index, :blur_shards
+        can [:destroy], [:zookeepers, :clusters, :blur_shards, :blur_controllers]
+        can [:move_file, :delete_file, :mkdir, :upload_form, :upload], :hdfs
+      end
+
+      if user.auditor?
+        can [:index, :show], :blur_queries, :query_string
+        can :index, :audits
+      end
+
+      if user.admin?
+        can [:index, :edit, :destroy, :create, :new], :users
+        can :update, :users, [:email, :roles]
+        can :update, :admin_settings
+      end
+
+      if user.searcher?
+        # searches
+        can :access, :searches
+
+        # Can modify own column preferences
+        can :update, :preferences, :user_id => user.id
+      end
+
+    else  # not logged in
+      can :new, [:users, :user_sessions]
+      can :create, :user_sessions
+      can :create, :users, [:username, :name, :email, :password, :password_confirmation]
+    end
+  end
+end

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/models/admin_setting.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/models/admin_setting.rb b/contrib/blur-console-v1/blur-admin/app/models/admin_setting.rb
new file mode 100644
index 0000000..7081dc8
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/models/admin_setting.rb
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+class AdminSetting < ActiveRecord::Base
+  validates :setting, :uniqueness => true
+
+  def self.search_filter
+    AdminSetting.where(:setting => 'regex_filter').first_or_create(:value => '.*')
+  end
+end

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/models/audit.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/models/audit.rb b/contrib/blur-console-v1/blur-admin/app/models/audit.rb
new file mode 100644
index 0000000..972523b
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/models/audit.rb
@@ -0,0 +1,44 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+class Audit < ActiveRecord::Base
+  belongs_to :user
+
+  scope :recent, lambda { |from, to|
+    where(:created_at => from.hours.ago..to.hours.ago).
+    includes(:user)
+  }
+
+	def self.log_event(user, message, model, mutation, parent_affected)
+    Audit.create(
+      :user_id => user.id,
+      :mutation => mutation.downcase,
+      :model_affected => model.downcase,
+      :action => "#{message}",
+      :zookeeper_affected => parent_affected.name
+    )
+	end
+
+  def summary
+    {
+      :action => action,
+      :date_audited => created_at.getutc.to_s,
+      :model => model_affected,
+      :mutation => mutation,
+      :username => user.username,
+      :user => user.name,
+      :zookeeper_affected => zookeeper_affected
+    }
+  end
+end

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/models/blur_controller.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/models/blur_controller.rb b/contrib/blur-console-v1/blur-admin/app/models/blur_controller.rb
new file mode 100644
index 0000000..81307b2
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/models/blur_controller.rb
@@ -0,0 +1,24 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+class BlurController < ActiveRecord::Base
+  belongs_to :zookeeper
+
+  def as_json(options={})
+    serial_properties = super(options)
+    serial_properties.delete('updated_at')
+    serial_properties.delete('created_at')
+    serial_properties
+  end
+end

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/models/blur_query.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/models/blur_query.rb b/contrib/blur-console-v1/blur-admin/app/models/blur_query.rb
new file mode 100644
index 0000000..8262036
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/models/blur_query.rb
@@ -0,0 +1,91 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+require 'blur_thrift_client'
+
+class BlurQuery < ActiveRecord::Base
+  include ActionView::Helpers::NumberHelper
+  belongs_to :blur_table
+  has_one :cluster, :through => :blur_table
+  has_one :zookeeper, :through => :cluster
+
+  def cancel
+    begin
+      ActiveSupport::Notifications.instrument "cancel.blur", :urls => blur_table.zookeeper.blur_urls, :table => self.blur_table.table_name, :uuid => self.uuid do
+        BlurThriftClient.client(blur_table.zookeeper.blur_urls).cancelQuery self.blur_table.table_name, self.uuid
+      end
+      return true
+    rescue Exception => e
+      logger.error "Exception in BlurQueries.cancel:"
+      logger.error e
+      return false
+    end
+  end
+
+  def state_str
+    case read_attribute(:state)
+      when 0 then "Running"
+      when 1 then "Interrupted"
+      when 2 then "Complete"
+      when 3 then "Marked Complete by Agent"
+      else nil
+    end
+  end
+
+  def complete
+    if self.total_shards == 0
+      0
+    else
+      self.complete_shards / self.total_shards.to_f
+    end
+  end
+
+  def summary(user)
+    summary_hash =
+    {
+      :id => id,
+      :can_update => user.can?(:cancel, :blur_queries),
+      :userid => print_value(userid),
+      :query => print_value(query_string),
+      :tablename => print_value(blur_table.table_name),
+      :start => print_value(start, 0),
+      :time => created_at.getlocal.strftime('%r'),
+      :status => summary_state,
+      :state => state_str
+    }
+    summary_hash.delete(:query) if user.cannot?(:index, :blur_queries, :query_string)
+    summary_hash
+  end
+
+  private
+
+  def summary_state
+    if state == 0
+      formattedNumber = "%01d" % (100 * complete)
+      formattedNumber + '%'
+    elsif state == 1
+      "(Interrupted) - #{number_to_percentage(100 * complete, :precision => 0)}"
+    elsif state == 3
+      "Marked Complete by Agent"
+    else
+      "Complete"
+    end
+  end
+
+  def print_value(conditional, default_message = "Not Available")
+    return default_message unless conditional
+    return conditional unless block_given?
+    yield
+  end
+end

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/models/blur_shard.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/models/blur_shard.rb b/contrib/blur-console-v1/blur-admin/app/models/blur_shard.rb
new file mode 100644
index 0000000..299dd20
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/models/blur_shard.rb
@@ -0,0 +1,26 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+class BlurShard < ActiveRecord::Base
+  after_destroy :destroy_parent_cluster
+
+  belongs_to :cluster
+
+  has_one :zookeeper, :through => :cluster
+
+  private
+  def destroy_parent_cluster
+    self.cluster.destroy if self.cluster.blur_shards.count <= 0
+  end
+end

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/models/blur_table.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/models/blur_table.rb b/contrib/blur-console-v1/blur-admin/app/models/blur_table.rb
new file mode 100644
index 0000000..37e1832
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/models/blur_table.rb
@@ -0,0 +1,118 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+class BlurTable < ActiveRecord::Base
+  require 'blur_thrift_client'
+
+  belongs_to :cluster
+  has_many :blur_queries, :dependent => :destroy
+  has_many :searches, :dependent => :destroy
+  has_one :zookeeper, :through => :cluster
+
+  scope :deleted, where("table_status=?", 0)
+  scope :disabled, where("table_status=?", 2)
+  scope :active, where("table_status=?", 4)
+
+  attr_accessor :query_count
+
+  def as_json(options={})
+    serial_properties = super(options)
+    serial_properties.delete('server')
+    serial_properties.delete('table_schema')
+    serial_properties.delete('updated_at')
+    serial_properties['queried_recently'] = self.query_count > 0
+
+    host_count = self.hosts.keys.length
+    shard_count = 0
+    self.hosts.values.each{ |shards| shard_count += shards.length }
+
+    serial_properties['server_info'] = host_count.to_s + ' | ' + shard_count.to_s
+    serial_properties['comments'] = self.comments
+    serial_properties
+  end
+
+  # Returns a map of host => [shards] of all hosts/shards associated with the table
+  def hosts
+    read_attribute(:server).blank? ? {} : (JSON.parse read_attribute(:server))
+  end
+
+  def schema
+    return nil if self.table_schema.blank?
+    # sort columns inline
+    sorted_schema = (JSON.parse self.table_schema).each{|n| n['columns'].sort_by!{|k| k['name']}}
+    if block_given?
+      sorted_schema.sort &Proc.new
+    else
+      # sort column families
+      sorted_schema.sort_by{|k| k['name']}
+    end
+  end
+
+  def record_count
+    read_attribute(:record_count).to_s.reverse.gsub(%r{([0-9]{3}(?=([0-9])))}, "\\1#{','}").reverse
+  end
+
+  def row_count
+    read_attribute(:row_count).to_s.reverse.gsub(%r{([0-9]{3}(?=([0-9])))}, "\\1#{','}").reverse
+  end
+
+  def is_enabled?
+    self.table_status == 4
+  end
+
+  def is_disabled?
+    self.table_status == 2
+  end
+
+  def is_deleted?
+    self.table_status == 0
+  end
+
+  def terms(blur_urls,family,column,startWith,size)
+    ActiveSupport::Notifications.instrument "terms.blur", :urls => blur_urls, :family => family, :column => column, :starter => startWith, :size => size do
+      BlurThriftClient.client(blur_urls).terms(self.table_name, family, column, startWith, size)
+    end
+  end
+
+  def enable(blur_urls)
+    begin
+      ActiveSupport::Notifications.instrument "enable.blur", :urls => blur_urls, :table => self.table_name do
+        BlurThriftClient.client(blur_urls).enableTable self.table_name
+      end
+    ensure
+      return self.is_enabled?
+    end
+  end
+
+  def disable(blur_urls)
+    begin
+      ActiveSupport::Notifications.instrument "disable.blur", :urls => blur_urls, :table => self.table_name do
+        BlurThriftClient.client(blur_urls).disableTable self.table_name
+      end
+    ensure
+      return self.is_disabled?
+    end
+  end
+
+  def blur_destroy(underlying=false, blur_urls)
+    begin
+      ActiveSupport::Notifications.instrument "destroy.blur", :urls => blur_urls, :table => self.table_name, :underlying => underlying do
+        BlurThriftClient.client(blur_urls).removeTable self.table_name, underlying
+      end
+      return true
+    rescue
+      return false
+    end
+  end
+end

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/models/cluster.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/models/cluster.rb b/contrib/blur-console-v1/blur-admin/app/models/cluster.rb
new file mode 100644
index 0000000..a815157
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/models/cluster.rb
@@ -0,0 +1,55 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+  class Cluster < ActiveRecord::Base
+  belongs_to :zookeeper
+  has_many :blur_shards, :dependent => :destroy
+  has_many :blur_tables, :dependent => :destroy, :order => 'table_name'
+  has_many :blur_queries, :through => :blur_tables, :dependent => :destroy
+
+  attr_accessor :can_update
+
+  def as_json(options={})
+    serial_properties = super(options)
+
+    if options[:blur_tables]
+      serial_properties["cluster_queried"] = self.query_status
+      serial_properties["can_update"] = self.can_update
+    else
+      serial_properties["shard_blur_version"] = self.shard_version
+      serial_properties["shard_status"] = self.shard_status
+    end
+
+    serial_properties
+  end
+
+  def shard_version
+    versions = self.blur_shards.collect{ |shard| shard.blur_version }.uniq
+    if versions.length < 1
+      "No shards in this Cluster!"
+    else
+      versions.length == 1 ? versions.first : "Inconsistent Blur Versions"
+    end
+  end
+
+  def shard_status
+    shard_total = self.blur_shards.length
+    shards_online = self.blur_shards.select{ |shard| shard.shard_status == 1 }.length
+    "#{shards_online} | #{shard_total}"
+  end
+
+  def query_status
+    self.blur_tables.select{ |table| table.query_count > 0 }.length > 0
+  end
+end

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/models/hdfs.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/models/hdfs.rb b/contrib/blur-console-v1/blur-admin/app/models/hdfs.rb
new file mode 100644
index 0000000..2a18788
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/models/hdfs.rb
@@ -0,0 +1,26 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+class Hdfs < ActiveRecord::Base
+  has_many :hdfs_stats
+
+  def most_recent_stats
+    self.hdfs_stats.last
+  end
+
+  def recent_stats
+    return false unless self.hdfs_stats.last
+    self.hdfs_stats.last.created_at > 1.minute.ago
+  end
+end

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/models/hdfs_stat.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/models/hdfs_stat.rb b/contrib/blur-console-v1/blur-admin/app/models/hdfs_stat.rb
new file mode 100644
index 0000000..4812eb0
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/models/hdfs_stat.rb
@@ -0,0 +1,25 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+class HdfsStat < ActiveRecord::Base
+  belongs_to :hdfs
+
+  def capacity
+  	self.present_capacity.to_f / 1024**3
+  end
+
+  def used
+	  self.dfs_used_real.to_f / 1024**3
+  end
+end

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/models/license.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/models/license.rb b/contrib/blur-console-v1/blur-admin/app/models/license.rb
new file mode 100644
index 0000000..de15cf6
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/models/license.rb
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+class License < ActiveRecord::Base
+end

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/models/preference.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/models/preference.rb b/contrib/blur-console-v1/blur-admin/app/models/preference.rb
new file mode 100644
index 0000000..376e14d
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/models/preference.rb
@@ -0,0 +1,23 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+class Preference < ActiveRecord::Base
+  belongs_to :user
+  validates :pref_type, :uniqueness => {:scope => :user_id}, :presence => true
+  serialize :value
+
+  # Scopes allow you to call user.preferences.column
+  # or user.preferences.filter
+  scope :column, where(:pref_type => 'column')
+end

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/models/search.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/models/search.rb b/contrib/blur-console-v1/blur-admin/app/models/search.rb
new file mode 100644
index 0000000..1fb04f4
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/models/search.rb
@@ -0,0 +1,88 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+class Search < ActiveRecord::Base
+  belongs_to :blur_table
+  belongs_to :user
+
+  before_save :marshal_columns
+
+  attr_accessor :column_object
+
+  def blur_query
+    b = Blur::BlurQuery.new( :query  => Blur::Query.new(:query => query,
+                      :rowQuery => super_query?),
+                      :fetch        => fetch,
+                      :start        => offset,
+                      #:uuid         => Time.now.to_i*1000 + rand(1000),
+                      :selector     => selector,
+                      :userContext  => User.find(user_id).username)
+    b.query.rowFilter = post_filter if !post_filter.blank?
+    b.query.recordFilter = pre_filter if !pre_filter.blank?
+    b
+  end
+
+  def column_object
+    @column_object = @column_object || (columns ? JSON.parse(columns) : [])
+  end
+
+  def column_families
+    column_object.collect{|value| value.split('_-sep-_')[1] if value.starts_with?('family')}.compact
+  end
+
+  def columns_hash
+    # hash with key = column_family and value = array of columns
+    # just columns without column families, and with 'recordId' added in
+    families = column_families
+    cols = {}
+    column_object.each do |raw_column|
+      parts = raw_column.split('_-sep-_')
+      if parts[0] == 'column' and !families.include?(parts[1])
+        cols[parts[1]] ||= ['recordId']
+        cols[parts[1]] << parts[2]
+      end
+    end
+    cols
+  end
+
+  def selector
+    Blur::Selector.new  :columnFamiliesToFetch => column_families,
+                        :columnsToFetch        => columns_hash,
+                        :recordOnly            => record_only?
+  end
+  def fetch_results(table_name, blur_urls)
+    ActiveSupport::Notifications.instrument "search.blur", :urls => blur_urls, :table => table_name, :query => blur_query.query.query do
+      BlurThriftClient.client(blur_urls).query(table_name, blur_query)
+    end
+  end
+
+  def schema(blur_table)
+    tmp_schema = columns_hash
+    tmp_schema.clone.each do |family,cols|
+      cols.collect!{|v| {"name" => v}}
+      tmp_schema[family] = {"name" => family, "columns" => cols}
+    end
+    column_families.each do |family|
+      col_fam = blur_table.schema.select{|v| v['name'] == family}.first
+      col_fam['columns'].insert(0,{"name" => 'recordId'})
+      tmp_schema[family] = col_fam
+    end
+    tmp_schema.sort
+  end
+
+  private
+  def marshal_columns
+    write_attribute(:columns, column_object.to_json) if column_object
+  end
+end

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/models/user.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/models/user.rb b/contrib/blur-console-v1/blur-admin/app/models/user.rb
new file mode 100644
index 0000000..dd16039
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/models/user.rb
@@ -0,0 +1,80 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+class User < ActiveRecord::Base
+  attr_accessible :email, :username, :name, :password, :password_confirmation, :roles
+
+  has_many :searches
+  has_many :preferences
+  has_many :audits
+
+  email_regex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+/
+
+  acts_as_authentic do |c|
+    c.merge_validates_format_of_email_field_options({:with => email_regex} )
+  end
+
+  # declare the valid roles -- do not change the order if you add more
+  # roles later, always append them at the end!
+  ROLES = %w[editor admin reader auditor searcher]
+
+  def ability
+    @ability ||= Ability.new(self)
+  end
+
+  delegate :can?, :cannot?, :to => :ability
+
+  #returns the array of saved cols
+  def column_preference
+    Preference.find_or_create_by_user_id_and_pref_type(self.id, 'column') do |preference|
+      preference.name = 'column'
+      preference.value = []
+    end
+  end
+  #returns the zookeeper preference set by the user
+  def zookeeper_preference
+    Preference.find_or_create_by_user_id_and_pref_type(self.id, 'zookeeper') do |preference|
+      preference.name = '0'
+      preference.value = nil
+    end
+  end
+
+  ### ROLE AUTHENTICATION ###
+
+  def roles=(roles)
+    self.roles_mask = (roles & ROLES).map { |r| 2**ROLES.index(r) }.sum
+  end
+
+  def roles
+    ROLES.reject do |r|
+      ((roles_mask || 0) & 2**ROLES.index(r)).zero?
+    end
+  end
+
+  def is?(role)
+    roles.include?(role.to_s)
+  end
+
+  # the roles are virtual attributes needed to use form helpers
+  ROLES.each do |role|
+    #truthy style methods role?
+    define_method role + '?' do
+      return roles.include?(role)
+    end
+    #form helper methods (same as above)
+    define_method role do
+      return roles.include?(role)
+    end
+  end
+end

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/models/user_session.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/models/user_session.rb b/contrib/blur-console-v1/blur-admin/app/models/user_session.rb
new file mode 100644
index 0000000..8b0b57b
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/models/user_session.rb
@@ -0,0 +1,23 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+class UserSession < Authlogic::Session::Base
+  def to_key
+    new_record? ? nil : [ self.send(self.class.primary_key) ]
+  end
+
+  def persisted?
+    false
+  end
+end

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/models/zookeeper.rb
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/models/zookeeper.rb b/contrib/blur-console-v1/blur-admin/app/models/zookeeper.rb
new file mode 100644
index 0000000..76fddec
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/models/zookeeper.rb
@@ -0,0 +1,80 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+class Zookeeper < ActiveRecord::Base
+  has_many :blur_controllers, :dependent => :destroy
+  has_many :clusters, :dependent => :destroy, :order => 'name'
+  has_many :blur_shards, :through => :clusters
+  has_many :blur_tables, :through => :clusters
+  has_many :blur_queries, :through => :blur_tables
+
+  QUERY = "
+    select
+      z.name,
+      z.zookeeper_status,
+      z.id,
+      v.controller_version,
+      c.controller_offline_node,
+      c.controller_total,
+      v.shard_version,
+      s.shard_offline_node,
+      s.shard_total,
+      q.long_running_queries
+    from
+      zookeepers z,
+      (select z1.id, count(distinct c1.blur_version) as controller_version, count(distinct s1.blur_version) as shard_version from zookeepers z1 left join blur_controllers c1 on (z1.id = c1.zookeeper_id), zookeepers z2 left join clusters c2 on (z2.id = c2.zookeeper_id) left join blur_shards s1 on (c2.id = s1.cluster_id) where z1.id = z2.id group by z1.id) v,
+      (select z2.id, CAST(sum(if((c3.controller_status = 0 or c3.controller_status = 2), 1, 0)) AS SIGNED) as controller_offline_node, count(c3.id) as controller_total from zookeepers z2 left join blur_controllers c3 on (z2.id = c3.zookeeper_id) group by z2.id) c,
+      (select z3.id, CAST(sum(if((s2.shard_status = 0 or s2.shard_status = 2), 1, 0)) AS SIGNED) as shard_offline_node, count(s2.id) as shard_total from zookeepers z3 left join clusters c4 on (z3.id = c4.zookeeper_id) left join blur_shards s2 on (c4.id = s2.cluster_id) group by z3.id) s,
+      (select z4.id, CAST(sum(if(q1.state = 0 and q1.created_at < date_sub(utc_timestamp(), interval 1 minute), 1, 0)) AS SIGNED) as long_running_queries from zookeepers z4 left join clusters c5 on (z4.id = c5.zookeeper_id) left join blur_tables t1 on (c5.id = t1.cluster_id) left join blur_queries q1 on (t1.id = q1.blur_table_id) group by z4.id) q
+    where
+      z.id = v.id and
+      z.id = c.id and
+      z.id = s.id and
+      z.id = q.id
+    order by
+      z.id
+  "
+
+  def as_json(options={})
+    serial_properties = super(options)
+    serial_properties.delete('online_ensemble_nodes')
+    serial_properties['ensemble'] = JSON.parse self.online_ensemble_nodes
+    serial_properties
+  end
+
+  def self.dashboard_stats
+    zookeeper_results = []
+    connection = ActiveRecord::Base.connection()
+    connection.execute(QUERY).each(:as => :hash) { |row| zookeeper_results << row }
+    zookeeper_results
+  end
+
+  def refresh_queries(lower_range)
+    self.blur_queries.where("blur_queries.updated_at > ? and blur_tables.table_status = ?", lower_range, 4)
+  end
+
+  def long_running_queries(current_user)
+    self.blur_queries.where('created_at < ? and state = ?', 1.minute.ago, 0).collect{|query| query.summary(current_user)}
+  end
+
+  def clusters_with_query_status(current_user)
+    query_counts = BlurQuery.where("updated_at > '#{5.minutes.ago}'").group('blur_table_id').count
+    self.clusters.each do |cluster|
+      cluster.blur_tables.each do |table|
+        table.query_count = query_counts[table.id] || 0
+      end
+      cluster.can_update = current_user.editor?
+    end
+  end
+end

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/views/audits/index.html.haml
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/views/audits/index.html.haml b/contrib/blur-console-v1/blur-admin/app/views/audits/index.html.haml
new file mode 100644
index 0000000..96882f5
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/views/audits/index.html.haml
@@ -0,0 +1,44 @@
+-#
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+
+- content_for :title, 'Audits'
+- content_for :javascript do
+  =javascript_include_tag 'audits.js'
+
+#audits_wrapper
+  %h2 Audits
+  #audits_table
+    %table.table.table-bordered.table-striped
+      %thead
+        %tr
+        - headers = ['Action Taken', 'Username', 'User','Zookeeper/Root Path', 'Model Affected', 'Mutation Type', 'Date']
+        - headers.each do |header|
+          %th
+            .header_content
+              %div=header
+              =render :partial => 'shared/icons'
+      %tbody
+        - for audit in @audits
+          %tr
+            %td= audit.action
+            %td= audit.user.username
+            %td= audit.user.name
+            %td= audit.zookeeper_affected
+            %td= audit.model_affected
+            %td= audit.mutation
+            %td= audit.created_at
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/11a2529a/contrib/blur-console-v1/blur-admin/app/views/blur_queries/_blur_query.html.haml
----------------------------------------------------------------------
diff --git a/contrib/blur-console-v1/blur-admin/app/views/blur_queries/_blur_query.html.haml b/contrib/blur-console-v1/blur-admin/app/views/blur_queries/_blur_query.html.haml
new file mode 100644
index 0000000..b9a0a25
--- /dev/null
+++ b/contrib/blur-console-v1/blur-admin/app/views/blur_queries/_blur_query.html.haml
@@ -0,0 +1,45 @@
+-#
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+
+%tr[@blur_query]{'data-age' => Time.now - @blur_query.created_at }>
+  %td.userid= print_value(@blur_query.userid)
+  - if can? :index, :blur_queries, :query_string
+    - if @blur_query.query_string
+      %td.query_string{:title => format_title(@blur_query.query_string)}
+        = truncate(@blur_query.query_string, :length => 75, :ommision => "...")
+    - else
+      %td.query_string
+        = 'Not Available'
+  %td= print_value(@blur_query.blur_table.table_name)
+  %td.start= print_value(@blur_query.start)
+  %td.fetch_num= print_value(@blur_query.fetch_num)
+  %td
+    - if @blur_query.state == 0
+      = print_value(@blur_query.complete) {number_to_percentage(100 * @blur_query.complete, :precision => 0)}
+    - elsif @blur_query.state == 1
+      = print_value(@blur_query.complete) {number_to_percentage(100 * @blur_query.complete, :precision => 0)}
+      (Interrupted)
+    - else
+      Complete
+  %td.query-actions
+    - if can? :update, :blur_queries
+      - if @blur_query.state == 0
+        = form_tag zookeeper_blur_query_path(@blur_query), :method => :put, :remote => true, :class => :cancel do
+          = hidden_field_tag :cancel, true
+          = tag :input, :type => :button, :value => 'Cancel', :class => "cancel_query_button btn"
+    = link_to "More Info", show_blur_query_path(@blur_query), :class => 'more_info', :remote => true, :style => 'margin-right: 3px'


Mime
View raw message