blob: 8f339b7e148bee1d5906864395e07f9b906873fd [file] [log] [blame]
;; 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.
(ns backtype.storm.ui.helpers
(:use compojure.core)
(:use [hiccup core page-helpers])
(:use [clojure
[string :only [blank? join]]
[walk :only [keywordize-keys]]])
(:use [backtype.storm config log])
(:use [backtype.storm.util :only [clojurify-structure uuid defnk url-encode]])
(:use [clj-time coerce format])
(:import [backtype.storm.generated ExecutorInfo ExecutorSummary])
(:import [org.mortbay.jetty.security SslSocketConnector])
(:require [ring.util servlet])
(:require [compojure.route :as route]
[compojure.handler :as handler]))
(defn split-divide [val divider]
[(Integer. (int (/ val divider))) (mod val divider)]
)
(def PRETTY-SEC-DIVIDERS
[["s" 60]
["m" 60]
["h" 24]
["d" nil]])
(def PRETTY-MS-DIVIDERS
(cons ["ms" 1000]
PRETTY-SEC-DIVIDERS))
(defn pretty-uptime-str* [val dividers]
(let [val (if (string? val) (Integer/parseInt val) val)
vals (reduce (fn [[state val] [_ divider]]
(if (pos? val)
(let [[divided mod] (if divider
(split-divide val divider)
[nil val])]
[(concat state [mod])
divided]
)
[state val]
))
[[] val]
dividers)
strs (->>
(first vals)
(map
(fn [[suffix _] val]
(str val suffix))
dividers
))]
(join " " (reverse strs))
))
(defn pretty-uptime-sec [secs]
(pretty-uptime-str* secs PRETTY-SEC-DIVIDERS))
(defn pretty-uptime-ms [ms]
(pretty-uptime-str* ms PRETTY-MS-DIVIDERS))
(defelem table [headers-map data]
[:table
[:thead
[:tr
(for [h headers-map]
[:th (if (:text h) [:span (:attr h) (:text h)] h)])
]]
[:tbody
(for [row data]
[:tr
(for [col row]
[:td col]
)]
)]
])
(defnk sort-table [id :sort-list "[[0,0]]" :time-cols []]
(let [strs (for [c time-cols] (format "%s: { sorter: 'stormtimestr'}" c))
sorters (join ", " strs)]
[:script
(format "$(document).ready(function() {
$(\"table#%s\").each(function(i) { $(this).tablesorter({ sortList: %s, headers: {%s}}); });
});"
id
sort-list
sorters)]))
(defn float-str [n]
(if n
(format "%.3f" (float n))
"0"
))
(defn swap-map-order [m]
(->> m
(map (fn [[k v]]
(into
{}
(for [[k2 v2] v]
[k2 {k v2}]
))
))
(apply merge-with merge)
))
(defn sorted-table [headers data & args]
(let [id (uuid)]
(concat
[(table {:class "zebra-striped" :id id}
headers
data)]
(if-not (empty? data)
[(apply sort-table id args)])
)))
(defn date-str [secs]
(let [dt (from-long (* 1000 (long secs)))]
(unparse (:rfc822 formatters) dt)
))
(defn url-format [fmt & args]
(String/format fmt
(to-array (map #(url-encode (str %)) args))))
(defn to-tasks [^ExecutorInfo e]
(let [start (.get_task_start e)
end (.get_task_end e)]
(range start (inc end))
))
(defn sum-tasks [executors]
(reduce + (->> executors
(map #(.get_executor_info ^ExecutorSummary %))
(map to-tasks)
(map count))))
(defn pretty-executor-info [^ExecutorInfo e]
(str "[" (.get_task_start e) "-" (.get_task_end e) "]"))
(defn unauthorized-user-html [user]
[[:h2 "User '" (escape-html user) "' is not authorized."]])
(defn- mk-ssl-connector [port ks-path ks-password ks-type]
(doto (SslSocketConnector.)
(.setExcludeCipherSuites (into-array String ["SSL_RSA_WITH_RC4_128_MD5" "SSL_RSA_WITH_RC4_128_SHA"]))
(.setAllowRenegotiate false)
(.setKeystore ks-path)
(.setKeystoreType ks-type)
(.setKeyPassword ks-password)
(.setPassword ks-password)
(.setPort port)))
(defn config-ssl [server port ks-path ks-password ks-type]
(when (> port 0)
(.addConnector server (mk-ssl-connector port ks-path ks-password ks-type))))
(defn config-filter [server handler filters-confs]
(if filters-confs
(let [servlet-holder (org.mortbay.jetty.servlet.ServletHolder.
(ring.util.servlet/servlet handler))
context (doto (org.mortbay.jetty.servlet.Context. server "/")
(.addServlet servlet-holder "/"))]
(doseq [{:keys [filter-name filter-class filter-params]} filters-confs]
(if filter-class
(let [filter-holder (doto (org.mortbay.jetty.servlet.FilterHolder.)
(.setClassName filter-class)
(.setName (or filter-name filter-class))
(.setInitParameters (or filter-params {})))]
(.addFilter context filter-holder "/*" org.mortbay.jetty.Handler/ALL))))
(.addHandler server context))))
(defn ring-response-from-exception [ex]
{:headers {}
:status 400
:body (.getMessage ex)})