aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sql/dump.sql1075
-rw-r--r--web/etc/varnish/default.vcl2
-rw-r--r--web/nms.gathering.org/nms2/img/tg15-salkart-clean-big.pngbin0 -> 84362 bytes
-rw-r--r--web/nms.gathering.org/nms2/index.html659
-rw-r--r--web/nms.gathering.org/nms2/js/nms-color-util.js111
-rw-r--r--web/nms.gathering.org/nms2/js/nms-map-handlers.js200
-rw-r--r--web/nms.gathering.org/nms2/js/nms.js578
-rwxr-xr-xweb/nms.gathering.org/port-state.pl7
-rwxr-xr-xweb/nms.gathering.org/uplinkkart-text.pl2
9 files changed, 2209 insertions, 425 deletions
diff --git a/sql/dump.sql b/sql/dump.sql
new file mode 100644
index 0000000..f65c7b9
--- /dev/null
+++ b/sql/dump.sql
@@ -0,0 +1,1075 @@
+--
+-- PostgreSQL database dump
+--
+
+SET statement_timeout = 0;
+SET lock_timeout = 0;
+SET client_encoding = 'UTF8';
+SET standard_conforming_strings = on;
+SET check_function_bodies = false;
+SET client_min_messages = warning;
+
+--
+-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner:
+--
+
+CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
+
+
+--
+-- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner:
+--
+
+COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';
+
+
+SET search_path = public, pg_catalog;
+
+--
+-- Name: comment_state; Type: TYPE; Schema: public; Owner: nms
+--
+
+CREATE TYPE comment_state AS ENUM (
+ 'active',
+ 'inactive',
+ 'persist',
+ 'delete'
+);
+
+
+ALTER TYPE comment_state OWNER TO nms;
+
+--
+-- Name: datarate; Type: TYPE; Schema: public; Owner: nms
+--
+
+CREATE TYPE datarate AS (
+ switch integer,
+ ifname character varying(30),
+ ifhcinoctets double precision,
+ ifhcoutoctets double precision,
+ last_poll_time timestamp with time zone
+);
+
+
+ALTER TYPE datarate OWNER TO nms;
+
+--
+-- Name: operstatuses; Type: TYPE; Schema: public; Owner: postgres
+--
+
+CREATE TYPE operstatuses AS (
+ switch integer,
+ ifdescr character(30),
+ ifoperstatus integer,
+ last_poll_time timestamp with time zone
+);
+
+
+ALTER TYPE operstatuses OWNER TO postgres;
+
+--
+-- Name: sample; Type: TYPE; Schema: public; Owner: postgres
+--
+
+CREATE TYPE sample AS (
+ value bigint,
+ polled timestamp with time zone
+);
+
+
+ALTER TYPE sample OWNER TO postgres;
+
+--
+-- Name: sample_state; Type: TYPE; Schema: public; Owner: postgres
+--
+
+CREATE TYPE sample_state AS (
+ last sample,
+ next_last sample
+);
+
+
+ALTER TYPE sample_state OWNER TO postgres;
+
+--
+-- Name: add_new_element(sample[], sample); Type: FUNCTION; Schema: public; Owner: postgres
+--
+
+CREATE FUNCTION add_new_element(sample[], sample) RETURNS sample[]
+ LANGUAGE sql
+ AS $_$ select ('{' || $1[1] || ', ' || $2 || '}')::sample[] $_$;
+
+
+ALTER FUNCTION public.add_new_element(sample[], sample) OWNER TO postgres;
+
+--
+-- Name: add_new_element(sample_state, sample); Type: FUNCTION; Schema: public; Owner: postgres
+--
+
+CREATE FUNCTION add_new_element(sample_state, sample) RETURNS sample_state
+ LANGUAGE sql
+ AS $_$
+ SELECT ($1.next_last, $2)::sample_state
+$_$;
+
+
+ALTER FUNCTION public.add_new_element(sample_state, sample) OWNER TO postgres;
+
+--
+-- Name: get_current_datarate(); Type: FUNCTION; Schema: public; Owner: nms
+--
+
+CREATE FUNCTION get_current_datarate() RETURNS SETOF datarate
+ LANGUAGE sql
+ AS $$
+ SELECT switch,ifname,
+ (ifhcoutoctets[1] - ifhcoutoctets[2]) / EXTRACT(EPOCH FROM (time[1] - time[2])) AS ifhcoutoctets,
+ (ifhcinoctets[1] - ifhcinoctets[2]) / EXTRACT(EPOCH FROM (time[1] - time[2])) AS ifhcinoctets,
+ time[1] AS last_poll_time
+ FROM (
+ SELECT switch,ifname,
+ ARRAY_AGG(time) AS time,
+ ARRAY_AGG(ifhcinoctets) AS ifhcinoctets,
+ ARRAY_AGG(ifhcoutoctets) AS ifhcoutoctets
+ FROM (
+ SELECT *,rank() OVER (PARTITION BY switch,ifname ORDER BY time DESC) AS poll_num
+ FROM polls WHERE time BETWEEN (now() - interval '11 minutes') AND now()
+ ) t1
+ WHERE poll_num <= 2
+ GROUP BY switch,ifname
+ ) t2
+ WHERE
+ time[2] IS NOT NULL
+ AND ifhcinoctets[1] >= 0 AND ifhcoutoctets[1] >= 0
+ AND ifhcinoctets[2] >= 0 AND ifhcoutoctets[2] >= 0
+ AND ifhcoutoctets[1] >= ifhcoutoctets[2]
+ AND ifhcinoctets[1] >= ifhcinoctets[2];
+$$;
+
+
+ALTER FUNCTION public.get_current_datarate() OWNER TO nms;
+
+--
+-- Name: get_datarate(); Type: FUNCTION; Schema: public; Owner: nms
+--
+
+CREATE FUNCTION get_datarate() RETURNS SETOF datarate
+ LANGUAGE plpgsql
+ AS $$
+DECLARE
+ num_entries INTEGER;
+ poll polls;
+ second_last_poll polls;
+ last_poll polls;
+ timediff float;
+ ret datarate;
+BEGIN
+ num_entries := 0;
+ last_poll.switch = -1;
+
+ FOR poll IN select * from polls where time >= now() - '15 minutes'::interval and time < now() order by switch,ifname,time LOOP
+ IF poll.switch <> last_poll.switch OR poll.ifname <> last_poll.ifname THEN
+ IF num_entries >= 2 THEN
+ timediff := EXTRACT(epoch from last_poll.time - second_last_poll.time);
+ ret.switch := last_poll.switch;
+ ret.ifname := last_poll.ifname;
+
+ IF last_poll.ifhcinoctets < second_last_poll.ifhcinoctets THEN
+ second_last_poll.ifhcinoctets = 0;
+ END IF;
+ IF last_poll.ifhcoutoctets < second_last_poll.ifhcoutoctets THEN
+ second_last_poll.ifhcoutoctets = 0;
+ END IF;
+
+ ret.ifhcinoctets := (last_poll.ifhcinoctets - second_last_poll.ifhcinoctets) / timediff;
+ ret.ifhcoutoctets := (last_poll.ifhcoutoctets - second_last_poll.ifhcoutoctets) / timediff;
+ ret.last_poll_time := last_poll.time;
+ return next ret;
+ ELSIF num_entries = 1 THEN
+ ret.switch := last_poll.switch;
+ ret.ifname := last_poll.ifname;
+ ret.ifhcinoctets := -1;
+ ret.ifhcoutoctets := -1;
+ ret.last_poll_time := last_poll.time;
+ return next ret;
+ END IF;
+ num_entries := 1;
+ ELSE
+ num_entries := num_entries + 1;
+ END IF;
+ second_last_poll.switch := last_poll.switch;
+ second_last_poll.ifname := last_poll.ifname;
+ second_last_poll.time := last_poll.time;
+ second_last_poll.ifhcinoctets := last_poll.ifhcinoctets;
+ second_last_poll.ifhcoutoctets := last_poll.ifhcoutoctets;
+ last_poll.switch := poll.switch;
+ last_poll.ifname := poll.ifname;
+ last_poll.time := poll.time;
+ last_poll.ifhcinoctets := poll.ifhcinoctets;
+ last_poll.ifhcoutoctets := poll.ifhcoutoctets;
+ END LOOP;
+ -- pah, and once more, for the last switch/ifname...
+ IF num_entries >= 2 THEN
+ timediff := EXTRACT(epoch from last_poll.time - second_last_poll.time);
+ ret.switch := last_poll.switch;
+ ret.ifname := last_poll.ifname;
+
+ IF last_poll.ifhcinoctets < second_last_poll.ifhcinoctets THEN
+ second_last_poll.ifhcinoctets = 0;
+ END IF;
+ IF last_poll.ifhcoutoctets < second_last_poll.ifhcoutoctets THEN
+ second_last_poll.ifhcoutoctets = 0;
+ END IF;
+
+ ret.ifhcinoctets := (last_poll.ifhcinoctets - second_last_poll.ifhcinoctets) / timediff;
+ ret.ifhcoutoctets := (last_poll.ifhcoutoctets - second_last_poll.ifhcoutoctets) / timediff;
+ ret.last_poll_time := last_poll.time;
+ return next ret;
+ ELSIF num_entries = 1 THEN
+ ret.switch := last_poll.switch;
+ ret.ifname := last_poll.ifname;
+ ret.ifhcinoctets := -1;
+ ret.ifhcoutoctets := -1;
+ ret.last_poll_time := last_poll.time;
+ return next ret;
+ END IF;
+
+ RETURN;
+END;
+$$;
+
+
+ALTER FUNCTION public.get_datarate() OWNER TO nms;
+
+--
+-- Name: current_change(sample); Type: AGGREGATE; Schema: public; Owner: postgres
+--
+
+CREATE AGGREGATE current_change(sample) (
+ SFUNC = public.add_new_element,
+ STYPE = sample_state
+);
+
+
+ALTER AGGREGATE public.current_change(sample) OWNER TO postgres;
+
+SET default_tablespace = '';
+
+SET default_with_oids = false;
+
+--
+-- Name: ap_poll; Type: TABLE; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE TABLE ap_poll (
+ switch integer NOT NULL,
+ model character varying DEFAULT ''::character varying NOT NULL,
+ last_poll timestamp with time zone
+);
+
+
+ALTER TABLE ap_poll OWNER TO nms;
+
+--
+-- Name: backup_polls; Type: TABLE; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE TABLE backup_polls (
+ "time" timestamp with time zone,
+ switch integer,
+ port integer,
+ bytes_in bigint,
+ bytes_out bigint,
+ errors_in bigint,
+ errors_out bigint
+);
+
+
+ALTER TABLE backup_polls OWNER TO nms;
+
+--
+-- Name: cpuloadpoll_id_seq; Type: SEQUENCE; Schema: public; Owner: nms
+--
+
+CREATE SEQUENCE cpuloadpoll_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+
+ALTER TABLE cpuloadpoll_id_seq OWNER TO nms;
+
+--
+-- Name: cpuloadpoll; Type: TABLE; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE TABLE cpuloadpoll (
+ id integer DEFAULT nextval('cpuloadpoll_id_seq'::regclass) NOT NULL,
+ "time" timestamp without time zone NOT NULL,
+ switch integer NOT NULL,
+ entity integer NOT NULL,
+ value integer NOT NULL
+);
+
+
+ALTER TABLE cpuloadpoll OWNER TO nms;
+
+--
+-- Name: dhcp; Type: TABLE; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE TABLE dhcp (
+ switch integer NOT NULL,
+ network cidr NOT NULL,
+ last_ack timestamp without time zone,
+ owner_color character varying
+);
+
+
+ALTER TABLE dhcp OWNER TO nms;
+
+--
+-- Name: linknet_ping; Type: TABLE; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE TABLE linknet_ping (
+ linknet integer NOT NULL,
+ updated timestamp with time zone DEFAULT now() NOT NULL,
+ latency1_ms double precision,
+ latency2_ms double precision
+);
+
+
+ALTER TABLE linknet_ping OWNER TO nms;
+
+--
+-- Name: linknets; Type: TABLE; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE TABLE linknets (
+ linknet integer NOT NULL,
+ switch1 integer NOT NULL,
+ addr1 inet NOT NULL,
+ switch2 integer NOT NULL,
+ addr2 inet NOT NULL
+);
+
+
+ALTER TABLE linknets OWNER TO nms;
+
+--
+-- Name: linknets_linknet_seq; Type: SEQUENCE; Schema: public; Owner: nms
+--
+
+CREATE SEQUENCE linknets_linknet_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+
+ALTER TABLE linknets_linknet_seq OWNER TO nms;
+
+--
+-- Name: linknets_linknet_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: nms
+--
+
+ALTER SEQUENCE linknets_linknet_seq OWNED BY linknets.linknet;
+
+
+--
+-- Name: mbd_log; Type: TABLE; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE TABLE mbd_log (
+ ts timestamp without time zone,
+ game character varying,
+ port integer,
+ description character varying,
+ active_servers integer
+);
+
+
+ALTER TABLE mbd_log OWNER TO nms;
+
+--
+-- Name: mldpolls; Type: TABLE; Schema: public; Owner: postgres; Tablespace:
+--
+
+CREATE TABLE mldpolls (
+ "time" timestamp with time zone NOT NULL,
+ switch integer NOT NULL,
+ mcast_group inet NOT NULL,
+ count integer NOT NULL,
+ raw_portlist character varying
+);
+
+
+ALTER TABLE mldpolls OWNER TO postgres;
+
+--
+-- Name: pgbench_accounts; Type: TABLE; Schema: public; Owner: postgres; Tablespace:
+--
+
+CREATE TABLE pgbench_accounts (
+ aid integer NOT NULL,
+ bid integer,
+ abalance integer,
+ filler character(84)
+)
+WITH (fillfactor=100);
+
+
+ALTER TABLE pgbench_accounts OWNER TO postgres;
+
+--
+-- Name: pgbench_branches; Type: TABLE; Schema: public; Owner: postgres; Tablespace:
+--
+
+CREATE TABLE pgbench_branches (
+ bid integer NOT NULL,
+ bbalance integer,
+ filler character(88)
+)
+WITH (fillfactor=100);
+
+
+ALTER TABLE pgbench_branches OWNER TO postgres;
+
+--
+-- Name: pgbench_history; Type: TABLE; Schema: public; Owner: postgres; Tablespace:
+--
+
+CREATE TABLE pgbench_history (
+ tid integer,
+ bid integer,
+ aid integer,
+ delta integer,
+ mtime timestamp without time zone,
+ filler character(22)
+);
+
+
+ALTER TABLE pgbench_history OWNER TO postgres;
+
+--
+-- Name: pgbench_tellers; Type: TABLE; Schema: public; Owner: postgres; Tablespace:
+--
+
+CREATE TABLE pgbench_tellers (
+ tid integer NOT NULL,
+ bid integer,
+ tbalance integer,
+ filler character(84)
+)
+WITH (fillfactor=100);
+
+
+ALTER TABLE pgbench_tellers OWNER TO postgres;
+
+--
+-- Name: ping; Type: TABLE; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE TABLE ping (
+ switch integer NOT NULL,
+ updated timestamp with time zone DEFAULT now() NOT NULL,
+ latency_ms double precision
+);
+
+
+ALTER TABLE ping OWNER TO nms;
+
+--
+-- Name: ping_secondary_ip; Type: TABLE; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE TABLE ping_secondary_ip (
+ switch integer NOT NULL,
+ updated timestamp with time zone DEFAULT now() NOT NULL,
+ latency_ms double precision
+);
+
+
+ALTER TABLE ping_secondary_ip OWNER TO nms;
+
+--
+-- Name: placements; Type: TABLE; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE TABLE placements (
+ switch integer NOT NULL,
+ placement box NOT NULL,
+ zorder integer DEFAULT 0 NOT NULL
+);
+
+
+ALTER TABLE placements OWNER TO nms;
+
+--
+-- Name: polls; Type: TABLE; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE TABLE polls (
+ switch integer NOT NULL,
+ "time" timestamp with time zone NOT NULL,
+ ifname character varying(30) NOT NULL,
+ ifhighspeed integer,
+ ifhcoutoctets bigint,
+ ifhcinoctets bigint
+);
+
+
+ALTER TABLE polls OWNER TO nms;
+
+--
+-- Name: portnames; Type: TABLE; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE TABLE portnames (
+ switchtype character varying NOT NULL,
+ port integer NOT NULL,
+ description character varying NOT NULL
+);
+
+
+ALTER TABLE portnames OWNER TO nms;
+
+--
+-- Name: seen_mac; Type: TABLE; Schema: public; Owner: postgres; Tablespace:
+--
+
+CREATE TABLE seen_mac (
+ mac macaddr NOT NULL,
+ address inet NOT NULL,
+ seen timestamp with time zone DEFAULT now() NOT NULL
+);
+
+
+ALTER TABLE seen_mac OWNER TO postgres;
+
+--
+-- Name: squeue; Type: TABLE; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE TABLE squeue (
+ id integer DEFAULT nextval(('squeue_sequence'::text)::regclass) NOT NULL,
+ gid integer NOT NULL,
+ added timestamp with time zone NOT NULL,
+ updated timestamp with time zone,
+ addr inet,
+ cmd character varying NOT NULL,
+ locked boolean DEFAULT false NOT NULL,
+ processed boolean DEFAULT false NOT NULL,
+ disabled boolean DEFAULT false NOT NULL,
+ priority integer DEFAULT 3,
+ sysname character varying NOT NULL,
+ author character varying NOT NULL,
+ result character varying,
+ delay timestamp with time zone,
+ delaytime interval DEFAULT '00:01:00'::interval
+);
+
+
+ALTER TABLE squeue OWNER TO nms;
+
+--
+-- Name: squeue_group_sequence; Type: SEQUENCE; Schema: public; Owner: nms
+--
+
+CREATE SEQUENCE squeue_group_sequence
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+
+ALTER TABLE squeue_group_sequence OWNER TO nms;
+
+--
+-- Name: squeue_sequence; Type: SEQUENCE; Schema: public; Owner: nms
+--
+
+CREATE SEQUENCE squeue_sequence
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+
+ALTER TABLE squeue_sequence OWNER TO nms;
+
+--
+-- Name: stemppoll_sequence; Type: SEQUENCE; Schema: public; Owner: nms
+--
+
+CREATE SEQUENCE stemppoll_sequence
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+
+ALTER TABLE stemppoll_sequence OWNER TO nms;
+
+--
+-- Name: switch_comments; Type: TABLE; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE TABLE switch_comments (
+ switch integer NOT NULL,
+ "time" timestamp with time zone,
+ comment text,
+ state comment_state DEFAULT 'active'::comment_state,
+ username character varying(32),
+ id integer NOT NULL
+);
+
+
+ALTER TABLE switch_comments OWNER TO nms;
+
+--
+-- Name: switch_comments_id_seq; Type: SEQUENCE; Schema: public; Owner: nms
+--
+
+CREATE SEQUENCE switch_comments_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+
+ALTER TABLE switch_comments_id_seq OWNER TO nms;
+
+--
+-- Name: switch_comments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: nms
+--
+
+ALTER SEQUENCE switch_comments_id_seq OWNED BY switch_comments.id;
+
+
+--
+-- Name: switch_temp; Type: TABLE; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE TABLE switch_temp (
+ switch integer,
+ temp integer,
+ "time" timestamp with time zone
+);
+
+
+ALTER TABLE switch_temp OWNER TO nms;
+
+--
+-- Name: switches; Type: TABLE; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE TABLE switches (
+ switch integer DEFAULT nextval(('"switches_switch_seq"'::text)::regclass) NOT NULL,
+ ip inet NOT NULL,
+ sysname character varying NOT NULL,
+ switchtype character varying NOT NULL,
+ last_updated timestamp with time zone,
+ locked boolean DEFAULT false NOT NULL,
+ priority integer DEFAULT 0 NOT NULL,
+ poll_frequency interval DEFAULT '00:01:00'::interval NOT NULL,
+ community character varying DEFAULT 'public'::character varying NOT NULL,
+ lldp_chassis_id character varying,
+ secondary_ip inet
+);
+
+
+ALTER TABLE switches OWNER TO nms;
+
+--
+-- Name: switches_switch_seq; Type: SEQUENCE; Schema: public; Owner: nms
+--
+
+CREATE SEQUENCE switches_switch_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+
+ALTER TABLE switches_switch_seq OWNER TO nms;
+
+--
+-- Name: switchtypes; Type: TABLE; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE TABLE switchtypes (
+ switchtype character varying NOT NULL,
+ ports character varying NOT NULL
+);
+
+
+ALTER TABLE switchtypes OWNER TO nms;
+
+--
+-- Name: temppoll; Type: TABLE; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE TABLE temppoll (
+ id integer DEFAULT nextval(('stemppoll_sequence'::text)::regclass) NOT NULL,
+ "time" timestamp without time zone NOT NULL,
+ switch integer NOT NULL,
+ temp double precision
+);
+
+
+ALTER TABLE temppoll OWNER TO nms;
+
+--
+-- Name: uplinks; Type: TABLE; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE TABLE uplinks (
+ switch integer NOT NULL,
+ coreswitch integer NOT NULL,
+ blade integer NOT NULL,
+ port integer NOT NULL
+);
+
+
+ALTER TABLE uplinks OWNER TO nms;
+
+--
+-- Name: linknet; Type: DEFAULT; Schema: public; Owner: nms
+--
+
+ALTER TABLE ONLY linknets ALTER COLUMN linknet SET DEFAULT nextval('linknets_linknet_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: nms
+--
+
+ALTER TABLE ONLY switch_comments ALTER COLUMN id SET DEFAULT nextval('switch_comments_id_seq'::regclass);
+
+
+--
+-- Name: cpuloadpoll_pkey; Type: CONSTRAINT; Schema: public; Owner: nms; Tablespace:
+--
+
+ALTER TABLE ONLY cpuloadpoll
+ ADD CONSTRAINT cpuloadpoll_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: pgbench_accounts_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace:
+--
+
+ALTER TABLE ONLY pgbench_accounts
+ ADD CONSTRAINT pgbench_accounts_pkey PRIMARY KEY (aid);
+
+
+--
+-- Name: pgbench_branches_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace:
+--
+
+ALTER TABLE ONLY pgbench_branches
+ ADD CONSTRAINT pgbench_branches_pkey PRIMARY KEY (bid);
+
+
+--
+-- Name: pgbench_tellers_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace:
+--
+
+ALTER TABLE ONLY pgbench_tellers
+ ADD CONSTRAINT pgbench_tellers_pkey PRIMARY KEY (tid);
+
+
+--
+-- Name: polls_time_switch_ifname_key; Type: CONSTRAINT; Schema: public; Owner: nms; Tablespace:
+--
+
+ALTER TABLE ONLY polls
+ ADD CONSTRAINT polls_time_switch_ifname_key UNIQUE ("time", switch, ifname);
+
+
+--
+-- Name: seen_mac_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace:
+--
+
+ALTER TABLE ONLY seen_mac
+ ADD CONSTRAINT seen_mac_pkey PRIMARY KEY (mac, address, seen);
+
+
+--
+-- Name: switch_comments_pkey; Type: CONSTRAINT; Schema: public; Owner: nms; Tablespace:
+--
+
+ALTER TABLE ONLY switch_comments
+ ADD CONSTRAINT switch_comments_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: switches_pkey; Type: CONSTRAINT; Schema: public; Owner: nms; Tablespace:
+--
+
+ALTER TABLE ONLY switches
+ ADD CONSTRAINT switches_pkey PRIMARY KEY (switch);
+
+
+--
+-- Name: switches_sysname_key; Type: CONSTRAINT; Schema: public; Owner: nms; Tablespace:
+--
+
+ALTER TABLE ONLY switches
+ ADD CONSTRAINT switches_sysname_key UNIQUE (sysname);
+
+
+--
+-- Name: switches_sysname_key1; Type: CONSTRAINT; Schema: public; Owner: nms; Tablespace:
+--
+
+ALTER TABLE ONLY switches
+ ADD CONSTRAINT switches_sysname_key1 UNIQUE (sysname);
+
+
+--
+-- Name: switchtypes_pkey; Type: CONSTRAINT; Schema: public; Owner: nms; Tablespace:
+--
+
+ALTER TABLE ONLY switchtypes
+ ADD CONSTRAINT switchtypes_pkey PRIMARY KEY (switchtype);
+
+
+--
+-- Name: ping_index; Type: INDEX; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE INDEX ping_index ON ping USING btree (updated);
+
+
+--
+-- Name: polls_time; Type: INDEX; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE INDEX polls_time ON polls USING btree ("time");
+
+
+--
+-- Name: seen_mac_addr_family; Type: INDEX; Schema: public; Owner: postgres; Tablespace:
+--
+
+CREATE INDEX seen_mac_addr_family ON seen_mac USING btree (family(address));
+
+
+--
+-- Name: seen_mac_seen; Type: INDEX; Schema: public; Owner: postgres; Tablespace:
+--
+
+CREATE INDEX seen_mac_seen ON seen_mac USING btree (seen);
+
+
+--
+-- Name: switch_temp_index; Type: INDEX; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE INDEX switch_temp_index ON switch_temp USING btree (switch);
+
+
+--
+-- Name: switches_ap_poll; Type: INDEX; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE UNIQUE INDEX switches_ap_poll ON ap_poll USING btree (switch);
+
+
+--
+-- Name: switches_dhcp; Type: INDEX; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE UNIQUE INDEX switches_dhcp ON dhcp USING btree (switch);
+
+
+--
+-- Name: switches_placement; Type: INDEX; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE UNIQUE INDEX switches_placement ON placements USING btree (switch);
+
+
+--
+-- Name: switches_switch; Type: INDEX; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE INDEX switches_switch ON switches USING hash (switch);
+
+
+--
+-- Name: temppoll_search; Type: INDEX; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE INDEX temppoll_search ON temppoll USING btree (switch, id);
+
+
+--
+-- Name: updated_index2; Type: INDEX; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE INDEX updated_index2 ON linknet_ping USING btree (updated);
+
+
+--
+-- Name: updated_index3; Type: INDEX; Schema: public; Owner: nms; Tablespace:
+--
+
+CREATE INDEX updated_index3 ON ping_secondary_ip USING btree (updated);
+
+
+--
+-- Name: ap_poll_switch_fkey; Type: FK CONSTRAINT; Schema: public; Owner: nms
+--
+
+ALTER TABLE ONLY ap_poll
+ ADD CONSTRAINT ap_poll_switch_fkey FOREIGN KEY (switch) REFERENCES switches(switch);
+
+
+--
+-- Name: switches_switchtype_fkey; Type: FK CONSTRAINT; Schema: public; Owner: nms
+--
+
+ALTER TABLE ONLY switches
+ ADD CONSTRAINT switches_switchtype_fkey FOREIGN KEY (switchtype) REFERENCES switchtypes(switchtype);
+
+
+--
+-- Name: switchname; Type: FK CONSTRAINT; Schema: public; Owner: nms
+--
+
+ALTER TABLE ONLY polls
+ ADD CONSTRAINT switchname FOREIGN KEY (switch) REFERENCES switches(switch);
+
+
+--
+-- Name: switchname; Type: FK CONSTRAINT; Schema: public; Owner: nms
+--
+
+ALTER TABLE ONLY ping
+ ADD CONSTRAINT switchname FOREIGN KEY (switch) REFERENCES switches(switch);
+
+
+--
+-- Name: switchname; Type: FK CONSTRAINT; Schema: public; Owner: nms
+--
+
+ALTER TABLE ONLY switch_comments
+ ADD CONSTRAINT switchname FOREIGN KEY (switch) REFERENCES switches(switch);
+
+
+--
+-- Name: temppoll_switch_fkey; Type: FK CONSTRAINT; Schema: public; Owner: nms
+--
+
+ALTER TABLE ONLY temppoll
+ ADD CONSTRAINT temppoll_switch_fkey FOREIGN KEY (switch) REFERENCES switches(switch);
+
+
+--
+-- Name: uplinks_coreswitch_fkey; Type: FK CONSTRAINT; Schema: public; Owner: nms
+--
+
+ALTER TABLE ONLY uplinks
+ ADD CONSTRAINT uplinks_coreswitch_fkey FOREIGN KEY (coreswitch) REFERENCES switches(switch);
+
+
+--
+-- Name: uplinks_switch_fkey; Type: FK CONSTRAINT; Schema: public; Owner: nms
+--
+
+ALTER TABLE ONLY uplinks
+ ADD CONSTRAINT uplinks_switch_fkey FOREIGN KEY (switch) REFERENCES switches(switch);
+
+
+--
+-- Name: public; Type: ACL; Schema: -; Owner: postgres
+--
+
+REVOKE ALL ON SCHEMA public FROM PUBLIC;
+REVOKE ALL ON SCHEMA public FROM postgres;
+GRANT ALL ON SCHEMA public TO postgres;
+GRANT ALL ON SCHEMA public TO PUBLIC;
+
+
+--
+-- Name: dhcp; Type: ACL; Schema: public; Owner: nms
+--
+
+REVOKE ALL ON TABLE dhcp FROM PUBLIC;
+REVOKE ALL ON TABLE dhcp FROM nms;
+GRANT ALL ON TABLE dhcp TO nms;
+
+
+--
+-- Name: mbd_log; Type: ACL; Schema: public; Owner: nms
+--
+
+REVOKE ALL ON TABLE mbd_log FROM PUBLIC;
+REVOKE ALL ON TABLE mbd_log FROM nms;
+GRANT ALL ON TABLE mbd_log TO nms;
+
+
+--
+-- Name: mldpolls; Type: ACL; Schema: public; Owner: postgres
+--
+
+REVOKE ALL ON TABLE mldpolls FROM PUBLIC;
+REVOKE ALL ON TABLE mldpolls FROM postgres;
+GRANT ALL ON TABLE mldpolls TO postgres;
+GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mldpolls TO nms;
+
+
+--
+-- Name: placements; Type: ACL; Schema: public; Owner: nms
+--
+
+REVOKE ALL ON TABLE placements FROM PUBLIC;
+REVOKE ALL ON TABLE placements FROM nms;
+GRANT ALL ON TABLE placements TO nms;
+
+
+--
+-- Name: seen_mac; Type: ACL; Schema: public; Owner: postgres
+--
+
+REVOKE ALL ON TABLE seen_mac FROM PUBLIC;
+REVOKE ALL ON TABLE seen_mac FROM postgres;
+GRANT ALL ON TABLE seen_mac TO postgres;
+GRANT SELECT,INSERT ON TABLE seen_mac TO nms;
+
+
+--
+-- Name: squeue; Type: ACL; Schema: public; Owner: nms
+--
+
+REVOKE ALL ON TABLE squeue FROM PUBLIC;
+REVOKE ALL ON TABLE squeue FROM nms;
+GRANT ALL ON TABLE squeue TO nms;
+
+
+--
+-- Name: switches; Type: ACL; Schema: public; Owner: nms
+--
+
+REVOKE ALL ON TABLE switches FROM PUBLIC;
+REVOKE ALL ON TABLE switches FROM nms;
+GRANT ALL ON TABLE switches TO nms;
+
+
+--
+-- PostgreSQL database dump complete
+--
+
diff --git a/web/etc/varnish/default.vcl b/web/etc/varnish/default.vcl
index 5f825a6..b4445d1 100644
--- a/web/etc/varnish/default.vcl
+++ b/web/etc/varnish/default.vcl
@@ -95,7 +95,7 @@ sub vcl_backend_response {
set beresp.ttl = 0s;
}
if(bereq.url ~ "port-state.pl" && beresp.status == 200) {
- set beresp.ttl = 30s;
+ set beresp.ttl = 1s;
}
if (beresp.status == 200 && bereq.url ~ "now=") {
set beresp.ttl = 60m;
diff --git a/web/nms.gathering.org/nms2/img/tg15-salkart-clean-big.png b/web/nms.gathering.org/nms2/img/tg15-salkart-clean-big.png
new file mode 100644
index 0000000..8d647a3
--- /dev/null
+++ b/web/nms.gathering.org/nms2/img/tg15-salkart-clean-big.png
Binary files differ
diff --git a/web/nms.gathering.org/nms2/index.html b/web/nms.gathering.org/nms2/index.html
index 42d7a35..304cece 100644
--- a/web/nms.gathering.org/nms2/index.html
+++ b/web/nms.gathering.org/nms2/index.html
@@ -21,91 +21,109 @@
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
- <![endif]-->
- <style type="text/css">
- canvas {
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -khtml-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- outline: none;
- -webkit-tap-highlight-color: rgba(255, 255, 255, 0); /* mobile webkit */
- }
- </style>
+ <![endif]-->
+ <style type="text/css">
+ canvas {
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ outline: none;
+ -webkit-tap-highlight-color: rgba(255, 255, 255, 0); /* mobile webkit */
+ }
+ </style>
</head>
-<body id="body">
+ <body id="body">
<nav class="navbar navbar-default navbar-static-top">
<div class="container-fluid">
- <div class="navbar-header">
- <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
- <span class="sr-only">Toggle navigation</span>
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- </button>
- <a class="navbar-brand" href="#">NMS</a>
- </div>
- <div id="navbar" class="navbar-collapse collapse">
- <ul class="nav navbar-nav">
- <li class="dropdown">
- <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">Map mode<span class="caret"></span></a>
- <ul class="dropdown-menu" role="menu">
- <li><a href="#ping" onclick="setUpdater(handler_ping)">Ping map</a></li>
- <li><a href="#uplink" onclick="setUpdater(handler_uplinks)">Uplink map</a></li>
- <li><a href="#temp" onclick="setUpdater(handler_temp)">Temperature map</a></li>
- <li><a href="#traffic" onclick="setUpdater(handler_traffic)">Traffic map</a></li>
- <li><a href="#comment" onclick="setUpdater(handler_comment)">Comment spotter</a></li>
- <li><a href="#disco" onclick="setUpdater(handler_disco)">DISCO</a></li>
- <li class="divider"> </li>
- <li><a href="#" onclick="toggleNightMode()" title="Add 'nightMode' anywhere in the url to auto-enable">Toggle Night Mode</a></li>
- <li><a href="#" onclick='showLayer("layerVisibility");'>Set layer visibility</a></li>
- <li class="divider"> </li>
- <li><a href="#" onclick="document.getElementById('nowPickerBox').style.display = 'block';">Travel in time</a></li>
- <li><a href="#" onclick="startReplay();" title="Replay from opening 30 minutes per second">Replay TG</a></li>
- <li><a href="#" onclick="document.getElementById('aboutData').style.display = 'block';">About TG15 data</a></li>
- <li class="divider"> </li>
- <li class="dropdown-header">Map scale</li>
- <li><input type="range" id="scaler" name="points" min="0.2" max="3" step="0.01" onchange="scaleChange()" /></li>
- <li><a href="#">Scale: <div id="scaler-text"></div></a></li>
- <li class="divider"> </li>
- <li><a onclick="document.getElementById('aboutBox').style.display = 'block'; hideSwitch();" style="cursor: pointer;" >About</a></li>
- <li><a onclick="showTimerDebug(); hideSwitch();" style="cursor: pointer;" >Debug timers</a></li>
- </ul>
- </li>
- <li><p id="updater_name" class="navbar-text"></p></li>
- <div class="navbar-form navbar-left">
- <div class="form-group">
- <button class="btn btn-default" id="legend-1"></button>
- <button class="btn btn-default" id="legend-2"></button>
- <button class="btn btn-default" id="legend-3"></button>
- <button class="btn btn-default" id="legend-4"></button>
- <button class="btn btn-default" id="legend-5"></button>
- </div>
- </div>
- </li>
- </ul>
- <ul class="nav navbar-nav navbar-right">
- <li><p id="speed" class="navbar-text" title="Client port speed / Total port speed"></p></li>
- </ul>
- </div><!--/.nav-collapse -->
+ <div class="navbar-header">
+ <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
+ <span class="sr-only">Toggle navigation</span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ </button>
+ <a class="navbar-brand" onclick="toggleLayer('aboutBox'); //document.getElementById('aboutBox').style.display = 'block'; hideSwitch();" style="cursor: pointer;" >NMS</a>
+ </div>
+ <div id="navbar" class="navbar-collapse collapse">
+ <ul class="nav navbar-nav">
+ <li class="dropdown">
+ <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">Map mode
+ <span class="caret"></span>
+ </a>
+ <ul class="dropdown-menu" role="menu">
+ <li><a href="#ping" onclick="setUpdater(handler_ping)">Ping map</a></li>
+ <li><a href="#uplink" onclick="setUpdater(handler_uplinks)">Uplink map</a></li>
+ <li><a href="#temp" onclick="setUpdater(handler_temp)">Temperature map</a></li>
+ <li><a href="#traffic" onclick="setUpdater(handler_traffic)">Traffic map</a></li>
+ <li><a href="#comment" onclick="setUpdater(handler_comment)">Comment spotter</a></li>
+ <li><a href="#traffictot" onclick="setUpdater(handler_traffic_tot)">Total switch traffic</a></li>
+ <li><a href="#disco" onclick="setUpdater(handler_disco)">DISCO</a></li>
+ <li class="divider"> </li>
+ <li><a href="#" onclick="toggleLayer('nowPickerBox');document.getElementById('nowPicker').focus();">Travel in time</a></li>
+ <li><a href="#" onclick="startReplay();" title="Replay from opening 120 minutes per second">Replay TG</a></li>
+ <li class="divider"> </li>
+ <li><a onclick="showTimerDebug(); hideSwitch();" style="cursor: pointer;" >Debug timers</a></li>
+ </ul>
+ </li>
+ <li class="dropdown">
+ <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">View<span class="caret"></span></a>
+ <ul class="dropdown-menu" role="menu">
+ <li><a href="#" onclick="toggleNightMode()">Toggle Night Mode</a></li>
+ <li><a href="#" onclick="showBlurBox()">Tweak Night Mode blur</a></li>
+ <li><a href="#" onclick='showLayer("layerVisibility");'>Set layer visibility</a></li>
+ <li class="divider"> </li>
+ <li class="dropdown-header">Map scale</li>
+ <li><a href="#"><label id="scaler-text" for='scaler'></label><input type="range" id="scaler" name="points" min="0.2" max="3" step="0.01" onchange="scaleChange()" /></a></li>
+ </ul>
+ </li>
+ <li><p id="updater_name" class="navbar-text"></p></li>
+ <div class="navbar-form navbar-left">
+ <div class="form-group">
+ <button class="btn btn-default" id="legend-1"></button>
+ <button class="btn btn-default" id="legend-2"></button>
+ <button class="btn btn-default" id="legend-3"></button>
+ <button class="btn btn-default" id="legend-4"></button>
+ <button class="btn btn-default" id="legend-5"></button>
+ </div>
+ </div>
+ </li>
+ </ul>
+ <ul class="nav navbar-nav navbar-right">
+ <li><p id="speed" class="navbar-text" title="Client port speed / Total port speed"></p></li>
+ <li class="dropdown">
+ <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">Help
+ <span class="caret"></span>
+ </a>
+ <ul class="dropdown-menu" role="menu">
+ <li><a href="#" onclick="toggleLayer('aboutData');">About TG15 data</a></li>
+ <li><a href="#" onclick="toggleLayer('aboutBox');" >About NMS</a></li>
+ <li><a href="#" onclick="toggleLayer('aboutPerformance');" >About Performance</a></li>
+ <li><a href="#" onclick="toggleLayer('aboutKeybindings');" >Keyboard Shortcuts</a></li>
+ </ul>
+ </li>
+ </ul>
+ </div><!--/.nav-collapse -->
</div>
</nav>
<div class="container-fluid">
- <div class="row-fluid">
- <div class="span12">
- <div id="aboutData" class="col-md-4"
- style="position: absolute; display:none; z-index: 130;">
- <div id="abotData" class="panel panel-default">
- <div class="panel-heading"><h3 class="panel-title">About
- the TG15 data
- <button type="button" class="close" aria-label="Close" onclick="document.getElementById('aboutData').style.display = 'none';" style="float: right"><span
- aria-hidden="true">&times;</span></button></h3></div>
- <div class="panel-body">
+ <div class="row-fluid">
+ <div class="span12">
+ <div id="aboutData" class="col-md-4" style="position: absolute; display:none; z-index: 130;">
+ <div id="abotData" class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title">About the TG15 data
+ <button type="button" class="close" aria-label="Close" onclick="document.getElementById('aboutData').style.display = 'none';" style="float: right">
+ <span aria-hidden="true">&times;</span>
+ </button>
+ </h3>
+ </div>
+ <div class="panel-body">
<p>The data you see from The Gathering 2015 will seem
"broken up". This is not because we don't have data from
the first day, but because the backend was re-written on
@@ -130,147 +148,374 @@
<p>It is also worth mentioning that things like switch
positions are not logged historically, so you see the final
position on the map.</p>
+ </div>
+ </div>
+ </div>
+ <div id="aboutPerformance" class="col-md-4" style="position: absolute; display:none; z-index: 130;">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title">Performance
+ <button type="button" class="close" aria-label="Close" onclick="document.getElementById('aboutPerformance').style.display = 'none';" style="float: right">
+ <span aria-hidden="true">&times;</span>
+ </button>
+ </h3>
+ </div>
+ <table class="table">
+ <tr>
+ <td>Outstanding AJAX requests</td>
+ <td id="outstandingAJAX"></td>
+ </tr>
+ <tr>
+ <td>Overflowed AJAX requests</td>
+ <td id="overflowAJAX"></td>
+ </tr>
+ </table>
+ <div class="panel-body">
+ <p>NMS performance is surprisingly complex. It's split into
+ several parts and dealt with differently.</p>
+ <p>Poller performance is a matter of efficiently collecting
+ data and is mostly handled in the Perl code (and ensuring
+ we use sensible database schemas).</p>
+ <p>Backend performance for the GUI is mostly about not
+ killing the database server. We do NOT try to protect
+ against malicious clients directly, since this is a
+ management system not public-facing, but Varnish is used to
+ cache requests. To be able to do that properly, we need use
+ absolute time when reviewing past events (so "2015-04-02
+ 17:30:00", not "2 hours ago"). We've also tried to minimize
+ the stupidity in the queries. There's still work to be done
+ here, though, as we need to split up a few large backend
+ requests (port-state.pl).</p>
+ <p>Front-end performance is mostly about drawing things
+ sensibly and not completely bombing the memory usage. And
+ about gracefully handling slow backends This will affect
+ you. For example, if you are reviewing past events and the
+ DB is struggling, we'll simply skip a backend request if we
+ have too many outstanding requests, that means you may jump
+ from "17:00" to "18:30" instead of going through
+ "17:30" and "18:00" too. This is working as intended. It
+ also means that you can happily spam the forward/backward
+ keyboard bindings to jump 18 hours forward: You'll overflow
+ the extra AJAX requests for individual requests, but you'll
+ land at the right time when you let go. But there could be
+ a 1 second delay (or more if the backend really struggles)
+ since you'll have to rely on the periodic backend requests
+ instead of the explicit ones triggered on hitting a
+ button.</p>
+ <p>Note that the counters on top are updated on a timer,
+ but this timer is set up at the same time as everything
+ else, which means that it's likely to update at the same
+ time as we fire off AJAX requests, so the 'outstanding ajax
+ requests' counter might either show almost constantly 3 or
+ 0 depending on what timer happens to fire first. This does
+ NOT mean that NMS has 3 requests all the time, just that
+ we're checking right after we fire off AJAX requests every
+ time.</p>
+ <p>NMS also tries to handle drawing OK, which is why things
+ are split into different HTML5 canvases. Blur and text are
+ particularly expensive, but there's no reason to re-paint
+ that all the time, etc).</p>
+ <p>The basic performance experiments are done on TG15 data
+ using a laptop and a VM with 6GB of memory, so it should
+ hold up quite well on "proper" hardware.</p>
+ </div>
+ </div>
+ </div>
+ <div id="aboutKeybindings" class="col-md-4" style="position: absolute; display:none; z-index: 130;">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title">Keyboard Shortcuts
+ <button type="button" class="close" aria-label="Close" onclick="document.getElementById('aboutKeybindings').style.display = 'none';" style="float: right">
+ <span aria-hidden="true">&times;</span>
+ </button>
+ </h3>
+ </div>
+ <table class="table table-condensed">
+ <tr>
+ <th>Key</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td>?</td>
+ <td>Toggle navigation bar</td>
+ </tr>
+ <tr>
+ <td>n</td>
+ <td>Toggle night mode</td>
+ </tr>
+ <tr>
+ <td>1</td>
+ <td>View Ping map</td>
+ </tr>
+ <tr>
+ <td>2</td>
+ <td>View uplink map</td>
+ </tr>
+ <tr>
+ <td>3</td>
+ <td>View temperature map</td>
+ </tr>
+ <tr>
+ <td>4</td>
+ <td>View uplink traffic map</td>
+ </tr>
+ <tr>
+ <td>5</td>
+ <td>View comment spotter map</td>
+ </tr>
+ <tr>
+ <td>6</td>
+ <td>View total switch traffic map</td>
+ </tr>
+ <tr>
+ <td>7</td>
+ <td>View Disco map</td>
+ </tr>
+ <tr>
+ <td>h</td>
+ <td>Step 1 hour back in time</td>
+ </tr>
+ <tr>
+ <td>j</td>
+ <td>Step 5 minutes back in time</td>
+ </tr>
+ <tr>
+ <td>k</td>
+ <td>Step 5 minutes forward in time</td>
+ </tr>
+ <tr>
+ <td>l</td>
+ <td>Step 1 hour forward in time</td>
+ </tr>
+ <tr>
+ <td>p</td>
+ <td>Toggle playback (1 hour per second)</td>
+ </tr>
+ <tr>
+ <td>r</td>
+ <td>Return to real time</td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div id="nowPickerBox" style="position: absolute; display: none; z-index: 130;" class="col-md-4">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title">Time travel
+ <button type="button" class="close" aria-labe="Close" onclick="document.getElementById('nowPickerBox').style.display = 'none';" style="float: right;">
+ <span aria-hidden="true">&times;</span>
+ </button>
+ </h3>
+ </div>
+ <div class="panel-body">
+ <p>Some features do not have time travel support (comment
+ spotting and DHCP map at the moment). We also lack
+ compatible SNMP data for the first day or so, so you'll
+ only have ping data for the first day of TG15.</p>
+ <p>It could take some time to load a specific point in time
+ for the first time. See "About performance" under the help
+ menu for more information.</p>
+ <p>You can also step backwards and forwards in time, stop
+ and start replay and go back to real time using keyboard
+ shortcuts. See the help menu for an overview of keyboard
+ shortcuts.</p>
+ <div class="input-group">
+ <input type="text" class="form-control" placeholder="YYYY-MM-DD hh:mm:ss" id="nowPicker">
+ <span class="input-group-btn">
+ <button class="btn btn-default" onclick="changeNow();">Travel</button>
+ </span>
</div>
-
- </div>
- </div>
- <div id="nowPickerBox" class="panel panel-default" style="position: absolute; display:none; z-index: 130;" >
- <div class="panel-heading"><h3
- class="panel-title">Time travel</h3></div>
- <div class="panel-body">
- <input type="text" class="form-control" placeholder="YYYY-MM-DD hh:mm:ss" id="nowPicker" value="" />
- <button class="btn btn-default" onclick="changeNow();">Travel</button>
- <button class="btn" onclick="document.getElementById('nowPickerBox').style.display = 'none';">Cancel</button>
- </div>
- </div>
- <div style="position: absolute; z-index: 120;" class="col-md-3">
- <div id="info-switch-parent" class="panel panel-default col-d-6" style="display: none; backgroun:silver; position: absolute; z-index: 120;">
- <div class="panel-heading"><h3 class="panel-title"
- id="info-switch-title"></h3></div>
- <div id="info-switch-panel-body">
- <table class="table" id="info-switch-table"></table>
- </div>
- </div>
- </div>
- <div id="aboutBox" class="col-md-4" style="display: none;
- position: absolute; z-index: 100;">
+ </div>
+ </div>
+ </div>
+ <div style="position: absolute; z-index: 120;" class="col-md-4">
+ <div id="info-switch-parent" class="panel panel-default col-d-6" style="display: none; backgroun:silver; position: absolute; z-index: 120;">
+ <div class="panel-heading">
+ <h3 class="panel-title" id="info-switch-title"></h3>
+ </div>
+ <div id="info-switch-panel-body">
+ <table class="table" id="info-switch-table"></table>
+ </div>
+ </div>
+ </div>
+ <div id="aboutBox" class="col-md-4" style="display: none; position: absolute; z-index: 100;">
<div id="abotBox" class="panel panel-default">
- <div class="panel-heading"><h3 class="panel-title">Welcome to NMS
- <button type="button" class="close" aria-labe="Close" onclick="document.getElementById('aboutBox').style.display = 'none';" style="float: right;"><span aria-hidden="true">&times;</span></button></h3></div>
- <div class="panel-body">
-
- <h3>Cool stuff:</h3>
- <ul>
- <li>Click a switch for more info</li>
- <li>Rewind: You can check out state at a specific time or replay from the beginning of the event. Only works for data where we keep time-series (so not for comments)</li>
- <li>Night mode, now with blur. Optional disco-mode (that's
- mainly for testing, though).</li>
- <li>Auto-scaling the viewport/canvas</li>
- <li>Total client speed (up right)</li>
- <li>Generic(-ish) map handlers: provide a name, init-function
- and an update-function and the nms lib does the rest as far as
- integration goes.</li>
- </ul>
- <h3>Todo list front end:</h3>
- <ul>
- <li>Polish time travel UI (Allow playing from a given time at a given speed, play/pause buttons, etc)</li>
- <li>Toggle auto-scale on/off</li>
- <li>Clean up various global variables</li>
- <li>Split blur into separate canvas (canvas is there, it's just
- not used)</li>
- <li>Add DHCP map</li>
- <li>Add magic map (combined map of sorts)</li>
- <li>Adjust updatePorts() frequency based on necessity (1sec
- updates is overkill for regular operation, but needed for time
- travel)</li>
- <li>More info on switches: Port state, possibly link time
- trends</li>
- <li>Moving switches around (like ping.html + edit)</li>
- <li>Split nms.js into multiple components to unclutter the
- code</li>
- <li>Comments: Fix UTF8 garbligash caused by $dbh-&gt;quote()</li>
- <li>More.</li>
- </ul>
- <h3>Todo for backend:</h3>
- <ul>
- <li>IPv6 support</li>
- <li>Close SQL injections (IT'S WIDE OPEN BECAUSE WHY NOT THAT'S NEVER A PROBLEM)</li>
- <li>Split port-state.pl into multiple appropriate pieces. Right
- it mixes heavy time-critical data with less time-critical and
- cheap computation.</li>
- <li>Consider time log of DHCP (right now it just stores the
- most recent timestamp, making time travel impossible)</li>
- <li>Fix SNMP-fetcher so it gets ifXTable and at least ifOperStatus from ifTable. Don't request the entire ifXTable if we can avoid it. Possibly other tweaks.</li>
- <li>Support for adding switches through an API, not just pure SQL.</li>
- <li>Integrate with FAP</li>
- <li>Clean up old interfaces</li>
- <li>Review various agents/tools</li>
- <li>Improve cache headers</li>
- <li>Cache invalidation of comments?</li>
- <li>Re-test the SQL schema. It's been modified and works fine
- on my laptop, but I need to dump it, commit it and test it.</li>
- <li>Munin plugin for ports.</li>
- </ul>
+ <div class="panel-heading">
+ <h3 class="panel-title">Welcome to NMS
+ <button type="button" class="close" aria-labe="Close" onclick="document.getElementById('aboutBox').style.display = 'none';" style="float: right;">
+ <span aria-hidden="true">&times;</span>
+ </button>
+ </h3>
+ </div>
+ <div class="panel-body">
+ <h3>Cool stuff:</h3>
+ <ul>
+ <li>Click a switch for more info</li>
+ <li>Rewind: You can check out state at a specific time or
+ replay from the beginning of the event. Only works for
+ data where we keep time-series (so not for
+ comments)</li>
+ <li>Press '?' to toggle the menu.</li>
+ <li>Auto-scaling the viewport/canvas</li>
+ <li>Total client speed (up right)</li>
+ <li>Generic(-ish) map handlers: provide a name, init-function
+ and an update-function and the nms lib does the rest as far as
+ integration goes.</li>
+ </ul>
+ <h3>Todo list front end:</h3>
+ <ul>
+ <li>Polish time travel UI (Allow playing from a given time at a given speed, play/pause buttons, etc)</li>
+ <li>Better "popup" boxes: It's growing out of control.</li>
+ <li>Toggle auto-scale on/off</li>
+ <li>Clean up various global variables</li>
+ <li>Create name spaces in nms.*: It's just barely better
+ than global stuff now.</li>
+ <li>Add DHCP map</li>
+ <li>More info on switches: Port state, possibly link time
+ trends</li>
+ <li>Moving switches around (like ping.html + edit)</li>
+ <li>Split nms.js into multiple components to unclutter the
+ code</li>
+ <li>Comments: Fix UTF8 garbligash caused by $dbh-&gt;quote()</li>
+ </ul>
+ <h3>Todo for backend:</h3>
+ <ul>
+ <li>IPv6 support</li>
+ <li>Provide public API's</li>
+ <li>Investigate a json tree filter/massager</li>
+ <li>Close SQL injections (IT'S WIDE OPEN BECAUSE WHY NOT THAT'S NEVER A PROBLEM)</li>
+ <li>Split port-state.pl into multiple appropriate pieces. Right
+ it mixes heavy time-critical data with less time-critical and
+ cheap computation.</li>
+ <li>Rip comments out of port-state.pl completely so it's not
+ bound by the same cache issues and can be reliably
+ refreshed.</li>
+ <li>Consider time log of DHCP (right now it just stores the
+ most recent timestamp, making time travel impossible)</li>
+ <li>Fix SNMP-fetcher so it gets ifXTable and at least
+ ifOperStatus from ifTable. Don't request the entire
+ ifXTable if we can avoid it. Possibly other
+ tweaks.</li>
+ <li>Support for adding switches through an API, not just pure SQL.</li>
+ <li>Integrate with FAP</li>
+ <li>Clean up old interfaces</li>
+ <li>Review various agents/tools</li>
+ <li>Improve cache headers</li>
+ <li>Cache invalidation of comments? (Probably not needed)</li>
+ <li>Re-test the SQL schema. It's been modified and works fine
+ on my laptop, but I need to dump it, commit it and test it.</li>
+ <li>Munin plugin for ports.</li>
+ </ul>
+ </div>
</div>
-
+ </div>
+ <div id="blurManic" class="panel panel-default" style="display: none; position: absolute; z-index: 100;">
+ <div class="panel-heading">
+ <h1 class="panel-title">Blur tweaks
+ <button type="button" class="close" aria-labe="Close" onclick="document.getElementById('blurManic').style.display = 'none';" style="float: right;">
+ <span aria-hidden="true">&times;</span>
+ </button>
+ </h1>
</div>
+ <div class="panel-body">
+ <div class="form">
+ <div class="form-group">
+ <label for="shadowBlur">Blur strength</label>
+ <input type="number" id="shadowBlur" class="form-control">
+ </div>
+ <div class="form-group">
+ <label for="shadowColor">Blur color</label>
+ <input type="color" id="shadowColor" class="form-control">
+ </div>
+ <button type="button" class="btn btn-default" onclick="applyBlur();">Apply</button>
+ </div>
</div>
- <div id="debugTimers" class="panel panel-default" style="display: none; position: absolute; z-index: 100;">
- <div class="panel-heading"><h1 class="panel-title">Debug
- timers (e.g.: Break stuff! FAST!)
- <button type="button" class="close" aria-labe="Close" onclick="document.getElementById('debugTimers').style.display = 'none';" style="float: right;"><span aria-hidden="true">&times;</span></button></h1></div>
- <div id="timerTableTop" class="panel-body">
+ </div>
+ </div>
+ <div id="debugTimers" class="panel panel-default" style="display: none; position: absolute; z-index: 100;">
+ <div class="panel-heading">
+ <h1 class="panel-title">Debug timers (e.g.: Break stuff! FAST!)
+ <button type="button" class="close" aria-labe="Close" onclick="document.getElementById('debugTimers').style.display = 'none';" style="float: right;">
+ <span aria-hidden="true">&times;</span>
+ </button>
+ </h1>
+ </div>
+ <div id="timerTableTop" class="panel-body">
<p>These are internal timers for the NMS frontend. They are
provided mainly to debug the frontend. Setting AJAX-triggering
counters to ridiculous numbers is not advised (mainly because
it causes server load).</p>
- <table id="timerTable"> </table>
- </div>
- </div>
- <div id="layerVisibility" class="panel panel-default" style="display: none; position: absolute; z-index: 100;">
- <div class="panel-heading"><h1 class="panel-title">Set layer visibility
- <button type="button" class="close" aria-labe="Close" onclick="document.getElementById('layerVisibility').style.display = 'none';" style="float: right;"><span aria-hidden="true">&times;</span></button></h1></div>
- <div class="panel-body">
+ </div>
+ <table id="timerTable"> </table>
+ </div>
+ <div id="layerVisibility" class="panel panel-default" style="display: none; position: absolute; z-index: 100;">
+ <div class="panel-heading">
+ <h1 class="panel-title">Set layer visibility
+ <button type="button" class="close" aria-labe="Close" onclick="document.getElementById('layerVisibility').style.display = 'none';" style="float: right;">
+ <span aria-hidden="true">&times;</span>
+ </button>
+ </h1>
+ </div>
+ <div class="panel-body">
<table id="visibilityTable" class="table">
- <tr><td>Background</td><td>
- <button onclick='hideLayer("bgCanvas");'>Hide</button>
- <button onclick='showLayer("bgCanvas");'>Show</button>
- </td></tr>
- <tr><td>Linknets</td><td>
- <button onclick='hideLayer("linkCanvas");'>Hide</button>
- <button onclick='showLayer("linkCanvas");'>Show</button>
- </td></tr>
- <tr><td>Blur</td><td>
- <button onclick='hideLayer("blurCanvas");'>Hide</button>
- <button onclick='showLayer("blurCanvas");'>Show</button>
- </td></tr>
- <tr><td>Switches</td><td>
- <button onclick='hideLayer("switchCanvas");'>Hide</button>
- <button onclick='showLayer("switchCanvas");'>Show</button>
- </td></tr>
- <tr><td>Text</td><td>
- <button onclick='hideLayer("textCanvas");'>Hide</button>
- <button onclick='showLayer("textCanvas");'>Show</button>
- </td></tr>
- <tr><td>Top</td><td>
- <button onclick='hideLayer("topCanvas");'>Hide</button>
- <button onclick='showLayer("topCanvas");'>Show</button>
- </td></tr>
- </table>
- </div>
- </div>
+ <tr>
+ <td>Background</td>
+ <td>
+ <button onclick='hideLayer("bgCanvas");'>Hide</button>
+ <button onclick='showLayer("bgCanvas");'>Show</button>
+ </td>
+ </tr>
+ <tr>
+ <td>Linknets</td>
+ <td>
+ <button onclick='hideLayer("linkCanvas");'>Hide</button>
+ <button onclick='showLayer("linkCanvas");'>Show</button>
+ </td>
+ </tr>
+ <tr>
+ <td>Blur</td>
+ <td>
+ <button onclick='hideLayer("blurCanvas");'>Hide</button>
+ <button onclick='showLayer("blurCanvas");'>Show</button>
+ </td>
+ </tr>
+ <tr>
+ <td>Switches</td>
+ <td>
+ <button onclick='hideLayer("switchCanvas");'>Hide</button>
+ <button onclick='showLayer("switchCanvas");'>Show</button>
+ </td>
+ </tr>
+ <tr>
+ <td>Text</td>
+ <td>
+ <button onclick='hideLayer("textCanvas");'>Hide</button>
+ <button onclick='showLayer("textCanvas");'>Show</button>
+ </td>
+ </tr>
+ <tr>
+ <td>Timestamp</td>
+ <td>
+ <button onclick='hideLayer("topCanvas");'>Hide</button>
+ <button onclick='showLayer("topCanvas");'>Show</button>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
-<canvas id="bgCanvas" width="1920" height="1032" style="position: absolute; z-index: 1;"> </canvas>
-<canvas id="linkCanvas" width="1920" height="1032" style="position: absolute; z-index: 10;"> </canvas>
-<canvas id="blurCanvas" width="1920" height="1032" style="position: absolute; z-index: 20;"> </canvas>
-<canvas id="switchCanvas" width="1920" height="1032" style="position: absolute; z-index: 30;"> </canvas>
-<canvas id="textCanvas" width="1920" height="1032" style="position: absolute; z-index: 40;"> </canvas>
-<canvas id="topCanvas" width="1920" height="1032" style="position: absolute; z-index: 50; cursor: pointer;" onclick="canvasClick(event)">
-</canvas>
+ <canvas id="bgCanvas" width="1920" height="1032" style="position: absolute; z-index: 1;"> </canvas>
+ <canvas id="linkCanvas" width="1920" height="1032" style="position: absolute; z-index: 10;"> </canvas>
+ <canvas id="blurCanvas" width="1920" height="1032" style="position: absolute; z-index: 20;"> </canvas>
+ <canvas id="switchCanvas" width="1920" height="1032" style="position: absolute; z-index: 30;"> </canvas>
+ <canvas id="textCanvas" width="1920" height="1032" style="position: absolute; z-index: 40;"> </canvas>
+ <canvas id="topCanvas" width="1920" height="1032" style="position: absolute; z-index: 50;"> </canvas>
+ <canvas id="inputCanvas" width="1920" height="1032" style="position: absolute; z-index: 60; cursor: pointer;" onclick="canvasClick(event)">
+ </canvas>
+ <canvas id="hiddenCanvas" width="1000" height="10" style="display: none; position: absolute; z-index: 1000 "></canvas>
-<div style="display:none;"><img id="source" src="img/tg15-salkart-full.png" ></div>
- </div>
- </div>
+ <div style="display:none;"><img id="source" src="img/tg15-salkart-clean-big.png" ></div>
+ </div>
</div><!--/.fluid-container-->
<script src="js/jquery.min.js" type="text/javascript"></script>
<script src="js/bootstrap.min.js" type="text/javascript"></script>
@@ -278,7 +523,7 @@
<script type="text/javascript" src="js/nms-color-util.js"></script>
<script type="text/javascript" src="js/nms-map-handlers.js"></script>
<script type="text/javascript">
- initNMS();
+initNMS();
</script>
-</body>
+ </body>
</html>
diff --git a/web/nms.gathering.org/nms2/js/nms-color-util.js b/web/nms.gathering.org/nms2/js/nms-color-util.js
index 28f7e1b..72d6f61 100644
--- a/web/nms.gathering.org/nms2/js/nms-color-util.js
+++ b/web/nms.gathering.org/nms2/js/nms-color-util.js
@@ -1,54 +1,91 @@
+/*
+ * Some stolen colors that look OK.
+ *
+ * PS: Stolen from boostrap, because we use bootstrap and these look good
+ * and match.
+ */
+var lightblue = "#d9edf7";
+var lightgreen = "#dff0d8";
+var lightred = "#f2dede";
+var lightorange = "#fcf8e3";
+var blue = "#337ab7";
+var green = "#5cb85c";
+var teal = "#5bc0de"; // Or whatever the hell that is
+var orange = "#f0ad4e";
+var red = "#d9534f";
+
function gradient_from_latency(latency_ms, latency_secondary_ms)
{
- if (latency_secondary_ms === undefined) {
- return rgb_from_latency(latency_ms);
- }
- return 'linear-gradient(' +
- rgb_from_latency(latency_ms) + ', ' +
- rgb_from_latency(latency_secondary_ms) + ')';
+ if (latency_ms == undefined)
+ return blue;
+ return getColorStop(parseInt(latency_ms) * 10);
}
-function rgb_from_latency(latency_ms)
+/*
+ * Return a random-ish color (for testing)
+ */
+function getRandomColor()
{
- if (latency_ms === null || latency_ms === undefined) {
- return '#0000ff';
- }
-
- var l = latency_ms / 40.0;
- if (l >= 2.0) {
- return 'rgb(255, 0, 0)';
- } else if (l >= 1.0) {
- l = 2.0 - l;
- l = Math.pow(l, 1.0/2.2);
- l = Math.floor(l * 255.0);
- return 'rgb(255, ' + l + ', 0)';
- } else {
- l = Math.pow(l, 1.0/2.2);
- l = Math.floor(l * 255.0);
- return 'rgb(' + l + ', 255, 0)';
- }
+ var colors = [ "white", red, teal, orange, green, blue ];
+ var i = Math.round(Math.random() * (colors.length-1));
+ return colors[i];
}
/*
- * Give us a color from blue (0) to red (100).
+ * Set up the hidden gradient canvas, using an array as input.
+ *
+ * This gives us a flexible way to get gradients between any number of
+ * colors (green to red, or blue to green to orange to red to white to pink
+ * to black and so on).
+ *
+ * Typically called when setting up a map handler. Currently "single
+ * tenant", since there's just one canvas.
+ *
+ * XXX: We have to store the gradients in nms.* and restore this when we
+ * resize for the moment, because this canvas is also re-sized (which isn't
+ * really necessary, but avoids special handling).
*/
-function rgb_from_max(x)
+function drawGradient(gradients)
{
- x = x/100;
- var colorred = 255 * x;
- var colorblue = 255 - colorred;
-
- return 'rgb(' + Math.floor(colorred) + ", 0, " + Math.floor(colorblue) + ')';
+ var gradient = dr.hidden.ctx.createLinearGradient(0,0,1000,0);
+ var stops = gradients.length - 1;
+ nms.gradients = gradients;
+ for (var color in gradients) {
+ var i = color / stops;
+ gradient.addColorStop(i, gradients[color]);
+ }
+ dr.hidden.ctx.beginPath();
+ dr.hidden.ctx.strokeStyle = gradient;
+ dr.hidden.ctx.moveTo(0,0);
+ dr.hidden.ctx.lineTo(1000,0);
+ dr.hidden.ctx.lineWidth = 10;
+ dr.hidden.ctx.closePath();
+ dr.hidden.ctx.stroke();
+ dr.hidden.ctx.moveTo(0,0);
}
/*
- * Return a random-ish color (for testing)
+ * Get the color of a gradient, range is from 0 to 999 (inclusive).
*/
-function getRandomColor()
-{
- var i = Math.round(Math.random() * 5);
- var colors = [ "white", "red", "pink", "yellow", "orange", "green" ];
- return colors[i];
+function getColorStop(x) {
+ x = parseInt(x);
+ if (x > 999)
+ x = 999;
+ if (x < 0)
+ x = 0;
+ return getColor(x,0);
}
+/*
+ * Get the color on the hidden canvas at a specific point. Could easily be
+ * made generic.
+ */
+function getColor(x,y) {
+ var imageData = dr.hidden.ctx.getImageData(x, y, 1, 1);
+ var data = imageData.data;
+ if (data.length < 4)
+ return false;
+ var ret = 'rgb(' + data[0] + ',' + data[1] + ',' + data[2] + ')';
+ return ret;
+}
diff --git a/web/nms.gathering.org/nms2/js/nms-map-handlers.js b/web/nms.gathering.org/nms2/js/nms-map-handlers.js
index 762788a..9b2d44c 100644
--- a/web/nms.gathering.org/nms2/js/nms-map-handlers.js
+++ b/web/nms.gathering.org/nms2/js/nms-map-handlers.js
@@ -21,38 +21,62 @@
var handler_uplinks = {
updater:uplinkUpdater,
init:uplinkInit,
+ tag:"uplink",
name:"Uplink map"
};
var handler_temp = {
updater:tempUpdater,
init:tempInit,
+ tag:"temp",
name:"Temperature map"
};
var handler_ping = {
updater:pingUpdater,
init:pingInit,
+ tag:"ping",
name:"IPv4 Ping map"
};
var handler_traffic = {
updater:trafficUpdater,
init:trafficInit,
+ tag:"traffic",
name:"Uplink traffic map"
};
+var handler_traffic_tot = {
+ updater:trafficTotUpdater,
+ init:trafficTotInit,
+ tag:"traffictot",
+ name:"Switch traffic map"
+};
+
var handler_disco = {
updater:randomizeColors,
init:discoInit,
+ tag:"disco",
name:"Disco fever"
};
var handler_comment = {
updater:commentUpdater,
init:commentInit,
+ tag:"comment",
name:"Fresh comment spotter"
};
+
+var handlers = [
+ handler_uplinks,
+ handler_temp,
+ handler_ping,
+ handler_traffic,
+ handler_disco,
+ handler_comment,
+ handler_traffic_tot
+ ];
+
/*
* Update function for uplink map
* Run periodically when uplink map is active.
@@ -78,15 +102,15 @@ function uplinkUpdater()
}
}
if (uplinks == 0) {
- setSwitchColor(sw,"blue");
+ setSwitchColor(sw,"white");
} else if (uplinks == 1) {
- setSwitchColor(sw,"red");
+ setSwitchColor(sw,red);
} else if (uplinks == 2) {
- setSwitchColor(sw, "yellow");
+ setSwitchColor(sw, orange);
} else if (uplinks == 3) {
- setSwitchColor(sw, "green");
+ setSwitchColor(sw, green);
} else if (uplinks > 3) {
- setSwitchColor(sw, "white");
+ setSwitchColor(sw, blue);
}
}
}
@@ -94,13 +118,27 @@ function uplinkUpdater()
/*
* Init-function for uplink map
*/
+function uplinkInit()
+{
+ setLegend(1,"white","0 uplinks");
+ setLegend(2,red,"1 uplink");
+ setLegend(3,orange,"2 uplinks");
+ setLegend(4,green,"3 uplinks");
+ setLegend(5,blue,"4 uplinks");
+}
+
+/*
+ * Init-function for uplink map
+ */
function trafficInit()
{
- setLegend(1,"blue","0 (N/A)");
- setLegend(5,"red", "1000Mb/s or more");
- setLegend(4,"yellow","100Mb/s to 800Mb/s");
- setLegend(3,"green", "5Mb/s to 100Mb/s");
- setLegend(2,"white","0 to 5Mb/s");
+ var m = 1024 * 1024 / 8;
+ drawGradient([lightgreen,green,orange,red]);
+ setLegend(1,colorFromSpeed(0),"0 (N/A)");
+ setLegend(5,colorFromSpeed(2000 * m) , "2000Mb/s");
+ setLegend(4,colorFromSpeed(1500 * m),"1500Mb/s");
+ setLegend(3,colorFromSpeed(500 * m),"500Mb/s");
+ setLegend(2,colorFromSpeed(10 * m),"10Mb/s");
}
function trafficUpdater()
@@ -115,37 +153,62 @@ function trafficUpdater()
/ge-0\/0\/46$/.exec(port) ||
/ge-0\/0\/47$/.exec(port))
{
+ if (!nms.switches_then["switches"][sw] ||
+ !nms.switches_then["switches"][sw]["ports"] ||
+ !nms.switches_then["switches"][sw]["ports"][port])
+ continue;
var t = nms.switches_then["switches"][sw]["ports"][port];
var n = nms.switches_now["switches"][sw]["ports"][port];
speed += (parseInt(t["ifhcoutoctets"]) -parseInt(n["ifhcoutoctets"])) / (parseInt(t["time"] - n["time"]));
speed += (parseInt(t["ifhcinoctets"]) -parseInt(n["ifhcinoctets"])) / (parseInt(t["time"] - n["time"]));
}
}
- var m = 1024 * 1024 / 8;
- if (speed == 0) {
- setSwitchColor(sw,"blue");
- } else if (speed > (1000 * m)) {
- setSwitchColor(sw,"red");
- } else if (speed > (800 * m)) {
- setSwitchColor(sw, "yellow");
- } else if (speed > (5 * m)) {
- setSwitchColor(sw, "green");
- } else {
- setSwitchColor(sw, "white");
- }
+ setSwitchColor(sw,colorFromSpeed(speed));
}
}
/*
* Init-function for uplink map
*/
-function uplinkInit()
+function trafficTotInit()
{
- setLegend(1,"blue","0 uplinks");
- setLegend(2,"red","1 uplink");
- setLegend(3,"yellow","2 uplinks");
- setLegend(4,"green","3 uplinks");
- setLegend(5,"white","4 uplinks");
+ var m = 1024 * 1024 / 8;
+ drawGradient([lightgreen,green,orange,red]);
+ setLegend(1,colorFromSpeed(0),"0 (N/A)");
+ setLegend(5,colorFromSpeed(5000 * m,5) , "5000Mb/s");
+ setLegend(4,colorFromSpeed(3000 * m,5),"3000Mb/s");
+ setLegend(3,colorFromSpeed(1000 * m,5),"1000Mb/s");
+ setLegend(2,colorFromSpeed(100 * m,5),"100Mb/s");
+}
+
+function trafficTotUpdater()
+{
+ if (!nms.switches_now["switches"])
+ return;
+ for (sw in nms.switches_now["switches"]) {
+ var speed = 0;
+ for (port in nms.switches_now["switches"][sw]["ports"]) {
+ if (!nms.switches_then["switches"][sw] ||
+ !nms.switches_then["switches"][sw]["ports"] ||
+ !nms.switches_then["switches"][sw]["ports"][port])
+ continue;
+ var t = nms.switches_then["switches"][sw]["ports"][port];
+ var n = nms.switches_now["switches"][sw]["ports"][port];
+ speed += (parseInt(t["ifhcoutoctets"]) -parseInt(n["ifhcoutoctets"])) / (parseInt(t["time"] - n["time"]));
+ }
+ setSwitchColor(sw,colorFromSpeed(speed,5));
+ }
+}
+
+function colorFromSpeed(speed,factor)
+{
+ var m = 1024 * 1024 / 8;
+ if (factor == undefined)
+ factor = 2;
+ if (speed == 0)
+ return blue;
+ speed = speed < 0 ? 0 : speed;
+ return getColorStop( 1000 * (speed / (factor * (1000 * m))));
}
@@ -158,11 +221,11 @@ function temp_color(t)
{
if (t == undefined) {
console.log("Temp_color, but temp is undefined");
- return "blue";
+ return blue;
}
- t = parseInt(t) - 20;
- t = Math.floor((t / 15) * 100);
- return rgb_from_max(t);
+ t = parseInt(t) - 12;
+ t = Math.floor((t / 23) * 1000);
+ return getColorStop(t);
}
function tempUpdater()
@@ -179,23 +242,28 @@ function tempUpdater()
function tempInit()
{
- setLegend(1,temp_color(20),"20 °C");
- setLegend(2,temp_color(22),"22 °C");
- setLegend(3,temp_color(27),"27 °C");
- setLegend(4,temp_color(31),"31 °C");
+ drawGradient(["black",blue,lightblue,lightgreen,green,orange,red]);
+ setLegend(1,temp_color(15),"15 °C");
+ setLegend(2,temp_color(20),"20 °C");
+ setLegend(3,temp_color(25),"25 °C");
+ setLegend(4,temp_color(30),"30 °C");
setLegend(5,temp_color(35),"35 °C");
}
function pingUpdater()
{
+ if (!nms.ping_data || !nms.ping_data["switches"]) {
+ resetColors();
+ return;
+ }
for (var sw in nms.switches_now["switches"]) {
- var c = "blue";
+ var c = blue;
if (nms.ping_data['switches'] && nms.ping_data['switches'][sw])
c = gradient_from_latency(nms.ping_data["switches"][sw]["latency"]);
setSwitchColor(sw, c);
}
for (var ln in nms.switches_now["linknets"]) {
- var c1 = "blue";
+ var c1 = blue;
var c2 = c1;
if (nms.ping_data['linknets'] && nms.ping_data['linknets'][ln]) {
c1 = gradient_from_latency(nms.ping_data["linknets"][ln][0]);
@@ -207,56 +275,58 @@ function pingUpdater()
function pingInit()
{
+ drawGradient([green,lightgreen,orange,red]);
setLegend(1,gradient_from_latency(1),"1ms");
setLegend(2,gradient_from_latency(30),"30ms");
setLegend(3,gradient_from_latency(60),"60ms");
- setLegend(4,gradient_from_latency(80),"80ms");
- setLegend(5,"#0000ff" ,"No response");
+ setLegend(4,gradient_from_latency(100),"100ms");
+ setLegend(5,gradient_from_latency(undefined) ,"No response");
}
function commentUpdater()
{
var realnow = Date.now();
- if (nms.now) {
- realnow = Date.parse(nms.now);
- }
var now = Math.floor(realnow / 1000);
for (var sw in nms.switches_now["switches"]) {
- var c = "green";
+ var c = "white";
var s = nms.switches_now["switches"][sw];
if (s["comments"] && s["comments"].length > 0) {
var then = 0;
+ var active = 0;
+ var persist = 0;
c = "yellow";
for (var v in s["comments"]) {
var then_test = parseInt(s["comments"][v]["time"]);
- if (then_test > then && then_test <= now)
+ if (then_test > then && s["comments"][v]["state"] != "inactive")
then = then_test;
+ if (s["comments"][v]["state"] == "active") {
+ active++;
+ }
+ if (s["comments"][v]["state"] == "persist")
+ persist++;
}
if (then > (now - (60*15))) {
- c = "red";
- } else if (then > (now - (120*60))) {
- c = "orange";
- } else if (then < (now - (60*60*24))) {
- c = "white";
+ c = red;
+ } else if (active > 0) {
+ c = orange;
+ } else if (persist > 0) {
+ c = blue;
+ } else {
+ c = green;
}
- /*
- * Special case during time travel: We have
- * comments, but are not showing them yet.
- */
- if (then == 0)
- c = "green";
}
setSwitchColor(sw, c);
}
}
+
function commentInit()
{
- setLegend(1,"green","0 comments");
- setLegend(2,"white","1d+ old");
- setLegend(3,"red", "0 - 15m old");
- setLegend(4,"orange","15m - 120m old");
- setLegend(5,"yellow" ,"2h - 24h old");
+ setLegend(1,"white","0 comments");
+ setLegend(2,blue,"Persistent");
+ setLegend(3,red, "New");
+ setLegend(4,orange,"Active");
+ setLegend(5,green ,"Old/inactive only");
}
/*
* Testing-function to randomize colors of linknets and switches
@@ -274,10 +344,10 @@ function randomizeColors()
function discoInit()
{
setNightMode(true);
- setLegend(1,"blue","Y");
- setLegend(2,"red", "M");
- setLegend(3,"yellow","C");
- setLegend(4,"green", "A");
+ setLegend(1,blue,"Y");
+ setLegend(2,red, "M");
+ setLegend(3,orange,"C");
+ setLegend(4,green, "A");
setLegend(5,"white","!");
}
diff --git a/web/nms.gathering.org/nms2/js/nms.js b/web/nms.gathering.org/nms2/js/nms.js
index 41b39d6..d4cf4e8 100644
--- a/web/nms.gathering.org/nms2/js/nms.js
+++ b/web/nms.gathering.org/nms2/js/nms.js
@@ -1,11 +1,14 @@
var nms = {
updater:undefined, // Active updater
+ update_time:0, // Client side timestamp for last update
switches_now:undefined, // Most recent data
switches_then:undefined, // 2 minutes old
speed:0, // Current aggregated speed
ping_data:undefined, // JSON data for ping history.
drawn:false, // Set to 'true' when switches are drawn
switch_showing:"", // Which switch we are displaying (if any).
+ repop_switch:false, // True if we need to repopulate the switch info when port state updates (e.g.: added comments);
+ repop_time:false, // Timestamp in case we get a cached result
nightMode:false,
/*
* Switch-specific variables. These are currently separate from
@@ -13,6 +16,8 @@ var nms = {
* new data.
*/
nightBlur:{}, // Have we blurred this switch or not?
+ shadowBlur:10,
+ shadowColor:"#EEEEEE",
switch_color:{}, // Color for switch
linknet_color:{}, // color for linknet
textDrawn:{}, // Have we drawn text for this switch?
@@ -44,14 +49,41 @@ var nms = {
timers: {
replay:false,
ports:false,
- ping:false,
- map:false,
- speed:false
+ ping:false
},
- deleteComment:0
+ menuShowing:true,
+ /*
+ * This is a list of nms[x] variables that we store in our
+ * settings-cookie when altered and restore on load.
+ */
+ settingsList:[
+ 'shadowBlur',
+ 'shadowColor',
+ 'nightMode',
+ 'menuShowing',
+ 'layerVisibility'
+ ],
+ layerVisibility:{},
+ keyBindings:{
+ '?':toggleMenu,
+ 'n':toggleNightMode,
+ '1':setMapModeFromN,
+ '2':setMapModeFromN,
+ '3':setMapModeFromN,
+ '4':setMapModeFromN,
+ '5':setMapModeFromN,
+ '6':setMapModeFromN,
+ '7':setMapModeFromN,
+ 'h':moveTimeFromKey,
+ 'j':moveTimeFromKey,
+ 'k':moveTimeFromKey,
+ 'l':moveTimeFromKey,
+ 'p':moveTimeFromKey,
+ 'r':moveTimeFromKey,
+ 'not-default':keyDebug
+ }
};
-
/*
* Returns a handler object.
*
@@ -85,6 +117,7 @@ function nmsTimer(handler, interval, name, description) {
};
}
+
/*
* Drawing primitives.
*
@@ -147,7 +180,7 @@ var margin = {
var tgStart = stringToEpoch('2015-04-01T09:00:00');
var tgEnd = stringToEpoch('2015-04-05T12:00:00');
var replayTime = 0;
-var replayIncrement = 30 * 60;
+var replayIncrement = 60 * 60;
/*
* Convenience-function to populate the 'dr' structure.
@@ -173,6 +206,12 @@ function initDrawing() {
dr['top'] = {};
dr['top']['c'] = document.getElementById("topCanvas");
dr['top']['ctx'] = dr['top']['c'].getContext('2d');
+ dr['input'] = {};
+ dr['input']['c'] = document.getElementById("inputCanvas");
+ dr['input']['ctx'] = dr['top']['c'].getContext('2d');
+ dr['hidden'] = {};
+ dr['hidden']['c'] = document.getElementById("hiddenCanvas");
+ dr['hidden']['ctx'] = dr['hidden']['c'].getContext('2d');
}
/*
@@ -196,6 +235,7 @@ function byteCount(bytes) {
function toggleNightMode()
{
setNightMode(!nms.nightMode);
+ saveSettings();
}
/*
@@ -226,7 +266,9 @@ function checkNow(now)
*/
function stringToEpoch(t)
{
- var ret = new Date(Date.parse(t));
+ var foo = t.toString();
+ foo = foo.replace('T',' ');
+ var ret = new Date(Date.parse(foo));
return parseInt(parseInt(ret.valueOf()) / 1000);
}
@@ -266,12 +308,15 @@ function epochToString(t)
*/
function timeReplay()
{
+ replayTime = stringToEpoch(nms.now);
if (replayTime >= tgEnd) {
nms.timers.replay.stop();
return;
}
replayTime = parseInt(replayTime) + parseInt(replayIncrement);
nms.now = epochToString(replayTime);
+ updatePorts();
+ updatePing();
}
/*
@@ -289,9 +334,11 @@ function timeReplay()
function startReplay() {
nms.timers.replay.stop();
resetColors();
- replayTime = tgStart;
+ nms.now = epochToString(tgStart);
timeReplay();
nms.timers.replay.start();;
+ nms.timers.ping.stop();;
+ nms.timers.ports.stop();;
}
/*
@@ -307,13 +354,36 @@ function changeNow() {
newnow = false;
nms.now = newnow;
+ if (newnow) {
+ nms.timers.ping.stop();;
+ nms.timers.ports.stop();;
+ }
updatePorts();
+ updatePing();
var boxHide = document.getElementById("nowPickerBox");
if (boxHide) {
boxHide.style.display = "none";
}
}
+function stepTime(n)
+{
+ var now;
+ nms.timers.replay.stop();
+ nms.timers.ping.stop();;
+ nms.timers.ports.stop();;
+ if (nms.now && nms.now != 0)
+ now = parseInt(stringToEpoch(nms.now));
+ else if (nms.switches_now)
+ now = parseInt(stringToEpoch(/^[^.]*/.exec(nms.switches_now.time)));
+ else
+ return;
+ newtime = parseInt(now) + parseInt(n);
+ nms.now = epochToString(parseInt(newtime));
+ updatePorts();
+ updatePing();
+}
+
/*
* Hide switch info-box
*/
@@ -335,7 +405,7 @@ function hideSwitch()
/*
* Display info on switch "x" in the info-box
*/
-function switchInfo(x)
+function showSwitch(x)
{
var sw = nms.switches_now["switches"][x];
var swtop = document.getElementById("info-switch-parent");
@@ -345,13 +415,8 @@ function switchInfo(x)
var td1;
var td2;
- if (nms.switch_showing == x) {
- hideSwitch();
- return;
- } else {
- hideSwitch();
- nms.switch_showing = x;
- }
+ hideSwitch();
+ nms.switch_showing = x;
document.getElementById("aboutBox").style.display = "none";
var switchele = document.createElement("table");
switchele.id = "info-switch-table";
@@ -490,16 +555,19 @@ function switchInfo(x)
if (comment["state"] == "active")
col = "danger";
else if (comment["state"] == "inactive")
- col = "active";
+ col = false;
else
col = "info";
tr.className = col;
+ tr.id = "commentRow" + comment["id"];
td1 = tr.insertCell(0);
td2 = tr.insertCell(1);
- var txt = '<div class="btn-group" role="group" aria-label="..."><button type="button" class="btn btn-xs" data-trigger="focus" data-toggle="popover" title="Info" data-content="Comment added ' + epochToString(comment["time"]) + " by user " + comment["username"] + ' and listed as ' + comment["state"] + '">?</button>';
- txt += '<button type="button" class="btn btn-xs" data-trigger="focus" data-toggle="tooltip" title="Mark as deleted" onclick="commentDelete(' + comment["id"] + ');">X</button>';
- txt += '<button type="button" class="btn btn-xs" data-trigger="focus" data-toggle="tooltip" title="Mark as inactive/fixed" onclick="commentInactive(' + comment["id"] + ');">V</button>';
- txt += '<button type="button" class="btn btn-xs" data-trigger="focus" data-toggle="tooltip" title="Mark as persistent" onclick="commentPersist(' + comment["id"] + ');">!</button></div>';
+ td1.style.whiteSpace = "nowrap";
+ td1.style.width = "8em";
+ var txt = '<div class="btn-group" role="group" aria-label="..."><button type="button" class="btn btn-xs btn-default" data-trigger="focus" data-toggle="popover" title="Info" data-content="Comment added ' + epochToString(comment["time"]) + " by user " + comment["username"] + ' and listed as ' + comment["state"] + '"><span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span></button>';
+ txt += '<button type="button" class="btn btn-xs btn-danger" data-trigger="focus" data-toggle="tooltip" title="Mark as deleted" onclick="commentDelete(' + comment["id"] + ');"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span></button>';
+ txt += '<button type="button" class="btn btn-xs btn-success" data-trigger="focus" data-toggle="tooltip" title="Mark as inactive/fixed" onclick="commentInactive(' + comment["id"] + ');"><span class="glyphicon glyphicon-ok" aria-hidden="true"></span></button>';
+ txt += '<button type="button" class="btn btn-xs btn-info" data-trigger="focus" data-toggle="tooltip" title="Mark as persistent" onclick="commentPersist(' + comment["id"] + ');"><span class="glyphicon glyphicon-star" aria-hidden="true"></span></button></div>';
td1.innerHTML = txt;
td2.textContent = comment['comment'];
}
@@ -514,7 +582,7 @@ function switchInfo(x)
commentbox.id = "commentbox";
commentbox.className = "panel-body";
commentbox.style.width = "100%";
- commentbox.innerHTML = '<div class="form form-inline"><div class="form-group"><input type="text" class="form-control" placeholder="Comment" id="' + x + '-comment"></div><button class="btn btn-default" onclick="addComment(\'' + x + '\',document.getElementById(\'' + x + '-comment\').value); document.getElementById(\'' + x + '-comment\').value = \'added. Wait for it....\';">Add comment</button></div>';
+ commentbox.innerHTML = '<div class="input-group"><input type="text" class="form-control" placeholder="Comment" id="' + x + '-comment"><span class=\"input-group-btn\"><button class="btn btn-default" onclick="addComment(\'' + x + '\',document.getElementById(\'' + x + '-comment\').value); document.getElementById(\'' + x + '-comment\').value = \'\'; document.getElementById(\'' + x + '-comment\').placeholder = \'Comment added. Wait for next refresh.\';">Add comment</button></span></div>';
swtop.appendChild(commentbox);
swtop.style.display = 'block';
}
@@ -530,16 +598,46 @@ function setLegend(x,color,name)
{
var el = document.getElementById("legend-" + x);
el.style.background = color;
- el.innerHTML = name;
+ el.title = name;
+ el.textContent = name;
}
+function updateAjaxInfo()
+{
+ var out = document.getElementById('outstandingAJAX');
+ var of = document.getElementById('overflowAJAX');
+ out.textContent = nms.outstandingAjaxRequests;
+ of.textContent = nms.ajaxOverflow;
+}
/*
* Run periodically to trigger map updates when a handler is active
*/
function updateMap()
{
+ /*
+ * XXX: This a bit hacky: There are a bunch of links that use
+ * href="#foo" but probably shouldn't. This breaks refresh since we
+ * base this on the location hash. To circumvent that issue
+ * somewhat, we just update the location hash if it's not
+ * "correct".
+ */
+ if (nms.updater) {
+ if (document.location.hash != ('#' + nms.updater.tag)) {
+ document.location.hash = nms.updater.tag;
+ }
+ }
+ if (!newerSwitches())
+ return;
+ if (!nms.drawn)
+ setScale();
+ if (!nms.drawn)
+ return;
+ if (!nms.ping_data)
+ return;
+ nms.update_time = Date.now();
+
if (nms.updater != undefined && nms.switches_now && nms.switches_then) {
- nms.updater();
+ nms.updater.updater();
}
drawNow();
}
@@ -552,12 +650,13 @@ function setUpdater(fo)
nms.updater = undefined;
resetColors();
fo.init();
- nms.updater = fo.updater;
+ nms.updater = fo;
var foo = document.getElementById("updater_name");
foo.innerHTML = fo.name + " ";
+ document.location.hash = fo.tag;
initialUpdate();
if (nms.ping_data && nms.switches_then && nms.switches_now) {
- nms.updater();
+ nms.updater.updater();
}
}
@@ -568,17 +667,43 @@ function setUpdater(fo)
*/
function initialUpdate()
{
+ return;
if (nms.ping_data && nms.switches_then && nms.switches_now && nms.updater != undefined && nms.did_update == false ) {
resizeEvent();
if (!nms.drawn) {
drawSwitches();
drawLinknets();
}
- nms.updater();
+ nms.updater.updater();
nms.did_update = true;
}
}
+function resetBlur()
+{
+ nms.nightBlur = {};
+ dr.blur.ctx.clearRect(0,0,canvas.width,canvas.height);
+ drawSwitches();
+}
+
+function applyBlur()
+{
+ var blur = document.getElementById("shadowBlur");
+ var col = document.getElementById("shadowColor");
+ nms.shadowBlur = blur.value;
+ nms.shadowColor = col.value;
+ resetBlur();
+ saveSettings();
+}
+
+function showBlurBox()
+{
+ var blur = document.getElementById("shadowBlur");
+ var col = document.getElementById("shadowColor");
+ blur.value = nms.shadowBlur;
+ col.value = nms.shadowColor;
+ document.getElementById("blurManic").style.display = '';
+}
/*
* Update nms.ping_data
*/
@@ -587,6 +712,7 @@ function updatePing()
var now = nms.now ? ("?now=" + nms.now) : "";
if (nms.outstandingAjaxRequests > 5) {
nms.ajaxOverflow++;
+ updateAjaxInfo();
return;
}
nms.outstandingAjaxRequests++;
@@ -597,50 +723,73 @@ function updatePing()
success: function (data, textStatus, jqXHR) {
nms.ping_data = JSON.parse(data);
initialUpdate();
+ updateMap();
},
complete: function(jqXHR, textStatus) {
nms.outstandingAjaxRequests--;
+ updateAjaxInfo();
}
});
}
-function commentInactive(id) {
+function commentInactive(id)
+{
commentChange(id,"inactive");
}
-function commentPersist(id) {
+function commentPersist(id)
+{
commentChange(id,"persist");
}
-function commentDelete(id) {
- if (id != nms.deleteComment) {
- nms.deleteComment = id;
- alert("Click the button again to delete it");
- return;
+
+function commentDelete(id)
+{
+ var r = confirm("Really delete comment? (Delted comments are still stored in the database, but never displayed)");
+ if (r == true) {
+ commentChange(id,"delete");
}
- commentChange(id,"delete");
}
-function commentChange(id,state) {
+
+/*
+ * FIXME: Neither of these two handle failures in any way, shape or form.
+ * Nor do they really give user-feedback. They work, but only by magic.
+ */
+function commentChange(id,state)
+{
var myData = {
comment:id,
state:state
};
+ var foo = document.getElementById("commentRow" + id);
+ if (foo) {
+ foo.className = '';
+ foo.style.backgroundColor = "silver";
+ }
$.ajax({
type: "POST",
url: "/comment-change.pl",
dataType: "text",
- data:myData
+ data:myData,
+ success: function (data, textStatus, jqXHR) {
+ nms.repop_switch = true;
+ }
});
}
-function addComment(sw,comment) {
+
+function addComment(sw,comment)
+{
var myData = {
switch:sw,
- comment:comment};
- console.log(myData);
+ comment:comment
+ };
$.ajax({
type: "POST",
url: "/switch-comment.pl",
dataType: "text",
- data:myData
+ data:myData,
+ success: function (data, textStatus, jqXHR) {
+ nms.repop_switch = true;
+ }
});
}
/*
@@ -651,6 +800,7 @@ function updatePorts()
var now = "";
if (nms.outstandingAjaxRequests > 5) {
nms.ajaxOverflow++;
+ updateAjaxInfo();
return;
}
nms.outstandingAjaxRequests++;
@@ -665,15 +815,26 @@ function updatePorts()
nms.switches_now = switchdata;
parseIntPlacements();
initialUpdate();
+ updateSpeed();
+ updateMap();
+ if (nms.repop_time == false && nms.repop_switch)
+ nms.repop_time = nms.switches_now.time;
+ else if (nms.repop_switch && nms.switch_showing && nms.repop_time != nms.switches_now.time) {
+ showSwitch(nms.switch_showing,true);
+ nms.repop_switch = false;
+ nms.repop_time = false;
+ }
},
complete: function(jqXHR, textStatus) {
nms.outstandingAjaxRequests--;
+ updateAjaxInfo();
}
});
now="";
if (nms.now != false)
now = "&now=" + nms.now;
nms.outstandingAjaxRequests++;
+ updateAjaxInfo();
$.ajax({
type: "GET",
url: "/port-state.pl?time=5m" + now,
@@ -682,14 +843,32 @@ function updatePorts()
var switchdata = JSON.parse(data);
nms.switches_then = switchdata;
initialUpdate();
+ updateSpeed();
+ updateMap();
},
complete: function(jqXHR, textStatus) {
nms.outstandingAjaxRequests--;
+ updateAjaxInfo();
}
})
}
/*
+ * Returns true if we have now and then-data for switches and that the
+ * "now" is actually newer. Useful for basic sanity and avoiding negative
+ * values when rewinding time.
+ */
+function newerSwitches()
+{
+ if (!nms.switches_now || !nms.switches_then)
+ return false;
+ var now_timestamp = stringToEpoch(nms.switches_now.time);
+ var then_timestamp = stringToEpoch(nms.switches_then.time);
+ if (now_timestamp == 0 || then_timestamp == 0 || then_timestamp >= now_timestamp)
+ return false;
+ return true;
+}
+/*
* Use nms.switches_now and nms.switches_then to update 'nms.speed'.
*
* nms.speed is a total of ifHCInOctets across all client-interfaces
@@ -703,6 +882,7 @@ function updatePorts()
* FIXME: Err, yeah, add this to the tail-end of updatePorts instead :D
*
*/
+
function updateSpeed()
{
var speed_in = parseInt(0);
@@ -710,6 +890,8 @@ function updateSpeed()
var counter=0;
var sw;
var speedele = document.getElementById("speed");
+ if (!newerSwitches())
+ return;
for (sw in nms.switches_now["switches"]) {
for (port in nms.switches_now["switches"][sw]["ports"]) {
if (!nms.switches_now["switches"][sw]["ports"][port]) {
@@ -763,8 +945,8 @@ function updateSpeed()
*/
function drawLinknet(i)
{
- var c1 = nms.linknet_color[i] && nms.linknet_color[i].c1 ? nms.linknet_color[i].c1 : "blue";
- var c2 = nms.linknet_color[i] && nms.linknet_color[i].c2 ? nms.linknet_color[i].c2 : "blue";
+ var c1 = nms.linknet_color[i] && nms.linknet_color[i].c1 ? nms.linknet_color[i].c1 : blue;
+ var c2 = nms.linknet_color[i] && nms.linknet_color[i].c2 ? nms.linknet_color[i].c2 : blue;
if (nms.switches_now.switches[nms.switches_now.linknets[i].sysname1] && nms.switches_now.switches[nms.switches_now.linknets[i].sysname2]) {
connectSwitches(nms.switches_now.linknets[i].sysname1,nms.switches_now.linknets[i].sysname2, c1, c2);
}
@@ -810,16 +992,18 @@ function drawSwitch(sw)
var box = nms.switches_now['switches'][sw]['placement'];
var color = nms.switch_color[sw];
if (color == undefined) {
- color = "blue";
+ color = blue;
}
dr.switch.ctx.fillStyle = color;
+ /*
+ * XXX: This is a left-over from before NMS did separate
+ * canvases, and might be done better elsewhere.
+ */
if (nms.nightMode && nms.nightBlur[sw] != true) {
- dr.switch.ctx.shadowBlur = 10;
- dr.switch.ctx.shadowColor = "#00EE00";
+ dr.blur.ctx.shadowBlur = nms.shadowBlur;
+ dr.blur.ctx.shadowColor = nms.shadowColor;
+ drawBoxBlur(box['x'],box['y'],box['width'],box['height']);
nms.nightBlur[sw] = true;
- } else {
- dr.switch.ctx.shadowBlur = 0;
- dr.switch.ctx.shadowColor = "#000000";
}
drawBox(box['x'],box['y'],box['width'],box['height']);
dr.switch.ctx.shadowBlur = 0;
@@ -871,18 +1055,20 @@ function drawSwitches()
*/
function drawNow()
{
+ if (!nms.switches_now)
+ return;
// XXX: Get rid of microseconds that we get from the backend.
var now = /^[^.]*/.exec(nms.switches_now.time);
dr.top.ctx.font = Math.round(2 * nms.fontSize * canvas.scale) + "px " + nms.fontFace;
dr.top.ctx.clearRect(0,0,Math.floor(800 * canvas.scale),Math.floor(100 * canvas.scale));
dr.top.ctx.fillStyle = "white";
dr.top.ctx.strokeStyle = "black";
- dr.top.ctx.lineWidth = Math.floor(4 * canvas.scale);
+ dr.top.ctx.lineWidth = Math.floor(2 * canvas.scale);
if (dr.top.ctx.lineWidth == 0) {
- dr.top.ctx.lineWidth = Math.round(4 * canvas.scale);
+ dr.top.ctx.lineWidth = Math.round(2 * canvas.scale);
}
- dr.top.ctx.strokeText(now, 0 + margin.text, 30 * canvas.scale);
- dr.top.ctx.fillText(now, 0 + margin.text, 30 * canvas.scale);
+ dr.top.ctx.strokeText(now, 0 + margin.text, 25 * canvas.scale);
+ dr.top.ctx.fillText(now, 0 + margin.text, 25 * canvas.scale);
}
/*
* Draw foreground/scene.
@@ -907,7 +1093,6 @@ function drawScene()
*/
function setScale()
{
-
canvas.height = orig.height * canvas.scale ;
canvas.width = orig.width * canvas.scale ;
for (var a in dr) {
@@ -916,8 +1101,11 @@ function setScale()
}
nms.nightBlur = {};
nms.textDrawn = {};
+ if (nms.gradients)
+ drawGradient(nms.gradients);
drawBG();
drawScene();
+ drawNow();
document.getElementById("scaler").value = canvas.scale;
document.getElementById("scaler-text").innerHTML = (parseFloat(canvas.scale)).toPrecision(3);
@@ -978,7 +1166,10 @@ function scaleChange()
*/
function switchClick(sw)
{
- switchInfo(sw);
+ if (nms.switch_showing == sw)
+ hideSwitch();
+ else
+ showSwitch(sw);
}
/*
@@ -993,11 +1184,11 @@ function resetColors()
return;
if (nms.switches_now.linknets) {
for (var i in nms.switches_now.linknets) {
- setLinknetColors(i, "blue","blue");
+ setLinknetColors(i, blue,blue);
}
}
for (var sw in nms.switches_now.switches) {
- setSwitchColor(sw, "blue");
+ setSwitchColor(sw, blue);
}
}
@@ -1058,6 +1249,14 @@ function setNightMode(toggle) {
nms.nightMode = toggle;
var body = document.getElementById("body");
body.style.background = toggle ? "black" : "white";
+ var nav = document.getElementsByTagName("nav")[0];
+ if (toggle) {
+ dr.blur.c.style.display = '';
+ nav.classList.add('navbar-inverse');
+ } else {
+ dr.blur.c.style.display = 'none';
+ nav.classList.remove('navbar-inverse');
+ }
setScale();
}
/*
@@ -1079,6 +1278,17 @@ function drawBox(x,y,boxw,boxh)
}
/*
+ * Draw the blur for a box.
+ */
+function drawBoxBlur(x,y,boxw,boxh)
+{
+ var myX = Math.floor(x * canvas.scale);
+ var myY = Math.floor(y * canvas.scale);
+ var myX2 = Math.floor((boxw) * canvas.scale);
+ var myY2 = Math.floor((boxh) * canvas.scale);
+ dr.blur.ctx.fillRect(myX,myY, myX2, myY2);
+}
+/*
* Draw text on a box - sideways!
*
* XXX: This is pretty nasty and should also probably take a box as input.
@@ -1149,9 +1359,9 @@ function connectSwitches(insw1, insw2,color1, color2) {
var sw1 = nms.switches_now.switches[insw1].placement;
var sw2 = nms.switches_now.switches[insw2].placement;
if (color1 == undefined)
- color1 = "blue";
+ color1 = blue;
if (color2 == undefined)
- color2 = "blue";
+ color2 = blue;
var x0 = Math.floor((sw1.x + sw1.width/2) * canvas.scale);
var y0 = Math.floor((sw1.y + sw1.height/2) * canvas.scale);
var x1 = Math.floor((sw2.x + sw2.width/2) * canvas.scale);
@@ -1178,8 +1388,6 @@ function connectSwitches(insw1, insw2,color1, color2) {
*/
function initNMS() {
initDrawing();
- updatePorts();
- updatePing();
window.addEventListener('resize',resizeEvent,true);
document.addEventListener('load',resizeEvent,true);
@@ -1189,36 +1397,23 @@ function initNMS() {
nms.timers.ping = new nmsTimer(updatePing, 1000, "Ping updater", "AJAX request to update ping data");
nms.timers.ping.start();
- nms.timers.map = new nmsTimer(updateMap, 1000, "Map handler", "Updates the map using the chosen map handler (ping, uplink, traffic, etc)");
- nms.timers.map.start();
-
- nms.timers.speed = new nmsTimer(updateSpeed, 1000, "Speed updater", "Recompute total speed (no backend requests)");
- nms.timers.speed.start();
-
- nms.timers.replay = new nmsTimer(timeReplay, 1000, "Time machine", "Handler used to change time");
+ nms.timers.replay = new nmsTimer(timeReplay, 500, "Time machine", "Handler used to change time");
detectHandler();
+ updatePorts();
+ updatePing();
+ setupKeyhandler();
+ restoreSettings();
}
function detectHandler() {
var url = document.URL;
- if (/#ping/.exec(url)) {
- setUpdater(handler_ping);
- }else if (/#uplink/.exec(url)) {
- setUpdater(handler_uplinks);
- } else if (/#temp/.exec(url)) {
- setUpdater(handler_temp);
- } else if (/#traffic/.exec(url)) {
- setUpdater(handler_traffic);
- } else if (/#comment/.exec(url)) {
- setUpdater(handler_comment);
- } else if (/#disco/.exec(url)) {
- setUpdater(handler_disco);
- } else {
- setUpdater(handler_ping);
- }
- if (/nightMode/.exec(url)) {
- toggleNightMode();
+ for (var i in handlers) {
+ if (('#' + handlers[i].tag) == document.location.hash) {
+ setUpdater(handlers[i]);
+ return;
+ }
}
+ setUpdater(handler_ping);
}
/*
@@ -1227,7 +1422,7 @@ function detectHandler() {
* Could probably be cleaned up.
*/
function showTimerDebug() {
- var tableTop = document.getElementById('timerTableTop');
+ var tableTop = document.getElementById('debugTimers');
var table = document.getElementById('timerTable');
var tr, td1, td2;
if (table)
@@ -1238,38 +1433,29 @@ function showTimerDebug() {
table.className = "table";
table.classList.add("table");
table.classList.add("table-default");
- table.border = "1";
- tr = document.createElement("tr");
- td = document.createElement("th");
+ var header = table.createTHead();
+ tr = header.insertRow(0);
+ td = tr.insertCell(0);
td.innerHTML = "Handler";
- tr.appendChild(td);
- td = document.createElement("th");
+ td = tr.insertCell(1);
td.innerHTML = "Interval (ms)";
- tr.appendChild(td);
- td = document.createElement("th");
+ td = tr.insertCell(2);
td.innerHTML = "Name";
- tr.appendChild(td);
- td = document.createElement("th");
+ td = tr.insertCell(3);
td.innerHTML = "Description";
- tr.appendChild(td);
- table.appendChild(tr);
for (var v in nms.timers) {
- console.log(v);
- tr = document.createElement("tr");
- td = document.createElement("td");
- td.innerHTML = nms.timers[v].handle;
- tr.appendChild(td);
- td = document.createElement("td");
- td.innerHTML = "<input type=\"text\" id='handlerValue" + v + "' value='" + nms.timers[v].interval + "'>";
- td.innerHTML += "<button type=\"button\" class=\"btn btn-default\" onclick=\"nms.timers['" + v + "'].setInterval(document.getElementById('handlerValue" + v + "').value);\">Apply</button>";
- tr.appendChild(td);
- td = document.createElement("td");
- td.innerHTML = nms.timers[v].name;
- tr.appendChild(td);
- td = document.createElement("td");
- td.innerHTML = nms.timers[v].description;
- tr.appendChild(td);
- table.appendChild(tr);
+ tr = table.insertRow(-1);
+ td = tr.insertCell(0);
+ td.textContent = nms.timers[v].handle;
+ td = tr.insertCell(1);
+ td.style.width = "15em";
+ var tmp = "<div class=\"input-group\"><input type=\"text\" id='handlerValue" + v + "' value='" + nms.timers[v].interval + "' class=\"form-control\"></input>";
+ tmp += "<span class=\"input-group-btn\"><button type=\"button\" class=\"btn btn-default\" onclick=\"nms.timers['" + v + "'].setInterval(document.getElementById('handlerValue" + v + "').value);\">Apply</button></span></div>";
+ td.innerHTML = tmp;
+ td = tr.insertCell(2);
+ td.textContent = nms.timers[v].name;
+ td = tr.insertCell(3);
+ td.textContent = nms.timers[v].description;
}
tableTop.appendChild(table);
document.getElementById('debugTimers').style.display = 'block';
@@ -1278,9 +1464,175 @@ function showTimerDebug() {
function hideLayer(layer) {
var l = document.getElementById(layer);
l.style.display = "none";
+ if (layer != "layerVisibility")
+ nms.layerVisibility[layer] = false;
+ saveSettings();
}
function showLayer(layer) {
var l = document.getElementById(layer);
l.style.display = "";
+ if (layer != "layerVisibility")
+ nms.layerVisibility[layer] = true;
+ saveSettings();
+}
+
+function toggleLayer(layer) {
+ var l = document.getElementById(layer);
+ if (l.style.display == 'none')
+ l.style.display = '';
+ else
+ l.style.display = 'none';
+}
+
+function applyLayerVis()
+{
+ for (var l in nms.layerVisibility) {
+ var layer = document.getElementById(l);
+ if (layer)
+ layer.style.display = nms.layerVisibility[l] ? '' : 'none';
+ }
+}
+
+function setMenu()
+{
+ var nav = document.getElementsByTagName("nav")[0];
+ nav.style.display = nms.menuShowing ? '' : 'none';
+ resizeEvent();
+
+}
+function toggleMenu()
+{
+ nms.menuShowing = ! nms.menuShowing;
+ setMenu();
+ saveSettings();
+}
+
+function setMapModeFromN(e,key)
+{
+ switch(key) {
+ case '1':
+ setUpdater(handler_ping);
+ break;
+ case '2':
+ setUpdater(handler_uplinks);
+ break;
+ case '3':
+ setUpdater(handler_temp);
+ break;
+ case '4':
+ setUpdater(handler_traffic);
+ break;
+ case '5':
+ setUpdater(handler_comment);
+ break;
+ case '6':
+ setUpdater(handler_traffic_tot);
+ break;
+ case '7':
+ setUpdater(handler_disco);
+ break;
+ }
+ return true;
+}
+
+function moveTimeFromKey(e,key)
+{
+ switch(key) {
+ case 'h':
+ stepTime(-3600);
+ break;
+ case 'j':
+ stepTime(-300);
+ break;
+ case 'k':
+ stepTime(300);
+ break;
+ case 'l':
+ stepTime(3600);
+ break;
+ case 'p':
+ if(nms.timers.replay.handle)
+ nms.timers.replay.stop();
+ else {
+ timeReplay();
+ nms.timers.replay.start();
+ }
+ break;
+ case 'r':
+ nms.timers.replay.stop();
+ nms.now = false;
+ nms.timers.ping.start();;
+ nms.timers.ports.start();;
+ updatePorts();
+ updatePing();
+ break;
+ }
+ return true;
+}
+
+var debugEvent;
+function keyDebug(e)
+{
+ console.log(e);
+ debugEvent = e;
+}
+
+function keyPressed(e)
+{
+ if (e.target.nodeName == "INPUT") {
+ return false;
+ }
+ var key = String.fromCharCode(e.keyCode);
+ if (nms.keyBindings[key])
+ return nms.keyBindings[key](e,key);
+ if (nms.keyBindings['default'])
+ return nms.keyBindings['default'](e,key);
+ return false;
+}
+
+function setupKeyhandler()
+{
+ var b = document.getElementsByTagName("body")[0];
+ b.onkeypress = function(e){keyPressed(e);};
+}
+
+
+function getCookie(cname) {
+ var name = cname + "=";
+ var ca = document.cookie.split(';');
+ for(var i=0; i<ca.length; i++) {
+ var c = ca[i];
+ while (c.charAt(0)==' ')
+ c = c.substring(1);
+ if (c.indexOf(name) == 0)
+ return c.substring(name.length,c.length);
+ }
+ return "";
+}
+
+function saveSettings()
+{
+ var foo={};
+ for (var v in nms.settingsList) {
+ foo[nms.settingsList[v]] = nms[nms.settingsList[v]];
+ }
+ document.cookie = 'nms='+btoa(JSON.stringify(foo));
+}
+
+function restoreSettings()
+{
+ var retrieve = JSON.parse(atob(getCookie("nms")));
+ for (var v in retrieve) {
+ nms[v] = retrieve[v];
+ }
+ setScale();
+ setMenu();
+ setNightMode(nms.nightMode);
+ applyLayerVis();
+}
+
+function forgetSettings()
+{
+ document.cookie = 'nms=' + btoa('{}');
}
diff --git a/web/nms.gathering.org/port-state.pl b/web/nms.gathering.org/port-state.pl
index b21bd8d..9df31c0 100755
--- a/web/nms.gathering.org/port-state.pl
+++ b/web/nms.gathering.org/port-state.pl
@@ -69,7 +69,12 @@ while (my $ref = $q4->fetchrow_hashref()) {
# push @{$json{'linknets'}}, $ref;
}
-my $q5 = $dbh->prepare ('select ' . $now . ' as time;');
+my $q5;
+if (defined($cin)) {
+ $q5 = $dbh->prepare ('select (' . $now . ' - \'' . $cin . '\'::interval) as time;');
+} else {
+ $q5 = $dbh->prepare ('select ' . $now . ' as time;');
+}
$q5->execute();
$json{'time'} = $q5->fetchrow_hashref()->{'time'};
diff --git a/web/nms.gathering.org/uplinkkart-text.pl b/web/nms.gathering.org/uplinkkart-text.pl
index de91e92..c4b31a9 100755
--- a/web/nms.gathering.org/uplinkkart-text.pl
+++ b/web/nms.gathering.org/uplinkkart-text.pl
@@ -17,7 +17,7 @@ print <<"EOF";
<map name="switches">
EOF
-my $q = $dbh->prepare("SELECT * FROM switches NATURAL JOIN placements WHERE switchtype = 'dlink3100'");
+my $q = $dbh->prepare("SELECT * FROM switches NATURAL JOIN placements WHERE switchtype = 'ex2200'");
$q->execute();
while (my $ref = $q->fetchrow_hashref()) {
$ref->{'placement'} =~ /\((\d+),(\d+)\),\((\d+),(\d+)\)/;