Giter Site home page Giter Site logo

jippi / hashi-ui Goto Github PK

View Code? Open in Web Editor NEW
1.2K 45.0 148.0 9.26 MB

A modern user interface for @hashicorp Consul & Nomad

License: MIT License

JavaScript 65.91% CSS 1.88% Go 25.56% Makefile 0.47% HCL 4.12% Shell 0.76% Dockerfile 0.22% SCSS 0.56% EJS 0.51%
nomad consul-configuration hashi-ui hashicorp-consul nomad-configuration hashicorp consul consul-template nomad-server docker

hashi-ui's Introduction

Hashi UI Build Status

Code Quality: Javascript Total Alerts

Join the chat at https://gitter.im/hashi-ui/Lobby Docker Stars Docker Pulls

An awesome user interface (even for mobile devices!) for HashiCorp Consul & Nomad, plain and simple :-)

Hashi UI

View more screenshots of Nomad & Consul interface

TOC

Why

For Nomad, it was quite simple, no mobile-optimized, (somewhat) feature-complete and live-updating interface existed.

For Consul, the built-in UI is decent, but lacks a variety of essential features:

  • Live update of Services, Nodes and Key/Value lists (nobody likes to refresh)
  • More API complete (e.g. unregister services and services checks directly from UI)
  • CAS (Check-And-Set) support in both Write and Delete actions for KV, preventing accidental modification or deleting of keys that have changed since you loaded them.
  • KV breadcrumbs could not be used for navigation
  • Sorting KV folders and keys separately (always folders first)
  • More inter-linking between services/nodes

Today the Consul and Nomad UI exist in the same binary, but do not "cross-talk" to each other, but long term goal is to integrate them even closer, so from Nomad Job UI you can see Consul health check status for the job tasks, and vice versa be able to cross-link between two otherwise distinct systems.

Long term, Vault support would be an amazing addition to the UI, contributions are more than welcome on this!

Usage

Until Hash-UI reaches 1.x, development efforts will focus on the latest versions of HashiCorp products

Download the latest release from the Github repository and start it with:

# if you got Nomad running on localhost
./hashi-ui-<os>-<arch> --nomad-enable

# if you got Nomad running on a specific Protocol/IP/Port
./hashi-ui-<os>-<arch> --nomad-enable --nomad-address http://IP:Port

# if you got Consul running on localhost
./hashi-ui-<os>-<arch> --consul-enable

# if you got Consul running on a specific IP/Port
./hashi-ui-<os>-<arch> --consul-enable  --consul-address IP:Port

# if you got nomad and Consul running on localhost
./hashi-ui-<os>-<arch> --nomad-enable --consul-enable

This will start the hashi-ui server that will try to connect to local nomad server. The frontend can be accessed on port 3000 by default. You can override this with the -listen-address.

Another way to run hashi-ui is through Docker. Run the following command to start a webserver that will serve the application.

# nomad only
docker run -e NOMAD_ENABLE=1 -e NOMAD_ADDR=... -p 8000:3000 jippi/hashi-ui
# consul only
docker run -e CONSUL_ENABLE=1 -e CONSUL_ADDR=... -p 8000:3000 jippi/hashi-ui
# consul only with https
docker run -e CONSUL_HTTP_TOKEN=one_ring -e CONSUL_HTTP_SSL_VERIFY=false -e CONSUL_HTTP_SSL=true CONSUL_ENABLE=1 -e CONSUL_ADDR=... -p 8000:3000 jippi/hashi-ui
# nomad + consul
docker run -e NOMAD_ENABLE=1 -e NOMAD_ADDR=... -e CONSUL_ENABLE=1 -e CONSUL_ADDR=... -p 8000:3000 jippi/hashi-ui

Check the releases page on GitHub to see which version is current.

The user interface will be accessible on localhost, port 8000. Adjust the Docker run parameters as needed. If you need to change the port that Nomad is listening on, you should do it with -e NOMAD_ADDR environment variable that contains both hostname and port.

Configuration

hashi-ui can be controlled by both ENV or CLI flags as described below

General Configuration

Environment CLI (--flag) Default Description
LOG_LEVEL log-level info Log level to use while running the hashi-ui server - (critical, error, warning, notice, info, debug)
PROXY_ADDRESS proxy-address <empty> (optional) The base URL of the UI when running behind a reverse proxy (ie: example.com/nomad/)
LISTEN_ADDRESS listen-address 0.0.0.0:3000 The IP + PORT to listen on
HTTPS_ENABLE https-enable false Use HTTPS instead of HTTP for Hashi-UI
SERVER_CERT server-cert <empty> Server certificate to use when HTTPS is enabled
SERVER_KEY server-key <empty> Server key to use when HTTPS is enabled
SITE_TITLE site-title <empty> Free-form text to be prepended to title-bar; eg. "Staging"
UPDATE_THROTTLE_DURATION throttle-update-duration <empty> Duration to sleep before polling Nomad/Consul for updates. Useful in busy clusters (example: 5s, 250ms)

Nomad Configuration

Environment CLI (--flag) Default Description
NOMAD_ENABLE nomad-enable false Use --nomad.enable or env NOMAD_ENABLE=1 to enable Nomad backend
NOMAD_ADDR nomad-address http://127.0.0.1:4646 Protocol + Host + Port for your Nomad instance
NOMAD_ACL_TOKEN nomad-acl-token <empty> The Nomad access token to use (optional)
NOMAD_READ_ONLY nomad-read-only false Should hash-ui allowed to modify Nomad state (stop/start jobs and so forth)
NOMAD_CACERT nomad-ca-cert <empty> (optional) path to a CA Cert file (remember to use https:// in NOMAD_ADDR if you enable TLS)
NOMAD_CLIENT_CERT nomad-client-cert <empty> (optional) path to a client cert file (remember to use https:// in NOMAD_ADDR if you enable TLS)
NOMAD_CLIENT_KEY nomad-client-key <empty> (optional) path to a client key file (remember to use https:// in NOMAD_ADDR if you enable TLS)
NOMAD_PORT_http <none> 0.0.0.0:3000 The IP + PORT to listen on (will overwrite LISTEN_ADDRESS)
NOMAD_HIDE_ENV_DATA nomad-hide-env-data false Whether Nomad env{} values should be hidden (will prevent updating jobs in the UI)
NOMAD_ALLOW_STALE nomad-allow-stale true Whether Hashi-UI should use stale mode when connecting to the nomad-api servers
NOMAD_COLOR nomad-color #4b9a7d Set the main color for nomad related screens.

Consul Configuration

Environment CLI (--flag) Default Description
CONSUL_ENABLE consul-enable false Use --consul-enable or env CONSUL_ENABLE=1 to enable Consul backend
CONSUL_ADDR consul-address 127.0.0.1:8500 Host + Port for your Consul server, e.g. localhost:8500` (Do not include protocol)
CONSUL_READ_ONLY consul-read-only false Should hash-ui be allowed to modify Consul state (modify KV, Services and so forth)
CONSUL_ACL_TOKEN consul-acl-token <empty> The Consul access token to use (optional)
CONSUL_HTTP_TOKEN <empty> <empty> Synonym for CONSUL_ACL_TOKEN
CONSUL_HTTP_SSL_VERIFY <empty> true Choose if you want your certificate to be verified (Likely to choose false if you have a custom SSL certificate)
CONSUL_HTTP_SSL <empty> false Enable HTTPS client to consul
CONSUL_CACERT <empty> <empty> (optional) path to a CA Cert file (remember to set CONSUL_HTTP_SSL to true)
CONSUL_CLIENT_CERT <empty> <empty> (optional) path to a client cert file (remember to set CONSUL_HTTP_SSL to true)
CONSUL_CLIENT_KEY <empty> <empty> (optional) path to a client key file (remember to set CONSUL_HTTP_SSL to true)
CONSUL_COLOR consul-color #694a9c Set the main color for consul related screens.

Running behind a Load Balancer

When Running Hashi UI behind AWS, an ALB is preferable as it supports HTTP websockets. Alternatively a NLB or ELB in 'TCP' mode will suffice.

Hashi-UI exposes a /_status endpoint that can be used to check the health of Nomad and Consul endpoints.

Running in Docker Compose

When running Hashi UI in Docker Compose, configure Consul with the following environment variable for Hashi UI's deregister button to work.

services:
  consul:
    image: consul
    environment:
      CONSUL_BIND_INTERFACE: eth0

Try

Nomad

You need a running nomad server to try Hashi UI:

nomad agent -server -client -bootstrap-expect 1 -data-dir /tmp/nomad

Now you can run Hashi UI in other terminal (we assume you have it in PATH):

hashi-ui-<os>-<arch> --nomad-enable

Open browser and visit http://127.0.0.1:3000.

Consul

You can run the Consul UI against the official HashiCorp Consul demo like this:

hashi-ui-<os>-<arch> --consul-enable --consul-address demo.consul.io

Open browser and visit http://127.0.0.1:3000.

Troubleshooting

  • Log lines like 19:25:54.105 nomad_hub.go:69 โ–ถ ERROR transport: websocket upgrade failed: websocket: could not find connection header with token 'upgrade' and the web interface is not working.
    • Ensure your load balancer is treating the services as TCP on port 80 (and SSL on 443). Websockets can't use HTTP/HTTPS mode.

Contributing & Development

If you would like to contribute (Thanks ! <3) please open a pull-request with your code change or a RFC issue.

See DEVELOPMENT.md for information on how to get started with hacking on hashi-ui.

hashi-ui's People

Contributors

aerickson avatar bkmit avatar burdandrei avatar cross311 avatar csawyeryumaed avatar dcarbone avatar dependabot-preview[bot] avatar dependabot[bot] avatar gpaggi avatar guillaumemorin avatar hsmade avatar iverberk avatar jackjacek avatar jippi avatar jrasell avatar lfarnell avatar lukinoh avatar mjay-taskize avatar multani avatar nicholasabriganti avatar okvic77 avatar pierresouchay avatar porshkevich avatar rimzoni avatar sboily avatar sepulworld avatar themalkolm avatar tmichaud314 avatar xxzgc avatar zhammer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hashi-ui's Issues

short/long term project goals

@iverberk thanks for a great project

could you share your thoughts on short and maybe long term goals you want to work on?

I'm currently moving our infrastructure from supervisor to nomad, and a UI is essential for that being a successful migration.

We do have some react resources at bownty, so we should be able to give something back (ala what @themalkolm did back in the beginning) to help move the project forward.

Thinks I feel is missing atm are an easy way to get an overview of errors happening in the cluster.

examples:

  • list over failed allocations, evaluations and most importantly, jobs
  • sortable columns in index / lists (e.g. on status column in jobs)
  • simple freetext search on index / list pages (on name / type)

Create UI tests

We should test that all the screens work as expected in the frontend.

'latest' - error with task groups tab for a job

When I click on the task group tab for a job I get:

main.ac0ba49ea4c8c4878963.js:11:26109 TypeError: (0,k["default"]) is not a function. (In '(0,k["default"])(n.ID)', '(0,k["default"])' is an instance of Object)

After this, it looks like a second web socket is created and the two run in parallel and seem to cause some confusion until you reload the page.

"Unable to connect to the backend..."

When trying to develop on the project locally, running npm start in frontend/ and then accessing localhost:3333 I get Unable to connect to the backend... in the dev-console

I assume the go server would need to run, but ws://localhost:3333/ws is routed through webpack, and not into the go server (which is port 3000?)

refresh loads no data on all pages

Hi

Navigating to http://localhost:8000/#/members/5b3a8a63-3a12-d0b1-2668-9407e94374b2/info?_k=tbi8os and refreshing the page yields no data / node info

If i navigate to the page again from the menu, it works fine

This seem to be for all non-index / list pages

The server log outputs

11:01:04.241 connection.go:49 โ–ถ ERRO Could not write close message to websocket: websocket: close sent

I'm running iverberk/nomad-ui:latest on nomad 0.4.1

Add nomad-0.4.1 support

Lets add nomad-0.4.1 support and enable back code that was disabled in 2c2eb24.

Do we want to build different UI binaries for different nomad versions or we simply follow the edge?

`Minified React error #31` on /jobs/:id

I'm getting the following error on #/jobs/insights-worker

Error: Minified React error #31; visit http://facebook.github.io/react/docs/error-decoder.html?invariant=31&args[]โ€ฆ0keys%20%7Bbownty.scale.queue_name%2C%20bownty.scale.use_config%7D&args[]= for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
    at n (http://localhost:8001/main.120138a39287c886fd52.js:2:17241)
    at a (http://localhost:8001/main.120138a39287c886fd52.js:5:6977)
    at o (http://localhost:8001/main.120138a39287c886fd52.js:5:7107)
    at Object.instantiateChildren (http://localhost:8001/main.120138a39287c886fd52.js:20:15334)
    at p._reconcilerInstantiateChildren (http://localhost:8001/main.120138a39287c886fd52.js:21:18816)
    at p.mountChildren (http://localhost:8001/main.120138a39287c886fd52.js:21:19023)
    at p._createInitialChildren (http://localhost:8001/main.120138a39287c886fd52.js:20:31912)
    at p.mountComponent (http://localhost:8001/main.120138a39287c886fd52.js:20:30064)
    at Object.mountComponent (http://localhost:8001/main.120138a39287c886fd52.js:3:19006)
    at p.mountChildren (http://localhost:8001/main.120138a39287c886fd52.js:21:19157)

My job file (json)

{
  "Region": "global",
  "ID": "insights-worker",
  "ParentID": "",
  "Name": "insights-worker",
  "Type": "service",
  "Priority": 50,
  "AllAtOnce": false,
  "Datacenters": [
    "production",
    "vagrant"
  ],
  "Constraints": [
    {
      "LTarget": "${meta.worker}",
      "RTarget": "1",
      "Operand": "="
    }
  ],
  "TaskGroups": [
    {
      "Name": "alert-server",
      "Count": 0,
      "Constraints": null,
      "RestartPolicy": {
        "Attempts": 2,
        "Interval": 60000000000,
        "Delay": 15000000000,
        "Mode": "delay"
      },
      "Tasks": [
        {
          "Name": "server",
          "Driver": "raw_exec",
          "User": "",
          "Config": {
            "command": "/usr/local/bin/envconsul",
            "args": [
              "-config /etc/envconsul/config.hcl -prefix apps/insights/nomad/alert-server/server/env -prefix apps/insights/env -wait 3s:6s -splay 3s -sanitize -upcase /opt/deploy/www/insights/htdocs/app/bin/cake alert server"
            ]
          },
          "Env": {
            "APP_VERSION": "1475",
            "APP_ENV": "production"
          },
          "Services": null,
          "Constraints": null,
          "Resources": {
            "CPU": 500,
            "MemoryMB": 128,
            "DiskMB": 300,
            "IOPS": 0,
            "Networks": null
          },
          "Meta": {
            "bownty.exec.command": "/opt/deploy/www/insights/htdocs/app/bin/cake alert server"
          },
          "KillTimeout": 5000000000,
          "LogConfig": {
            "MaxFiles": 10,
            "MaxFileSizeMB": 10
          },
          "Artifacts": null
        }
      ],
      "Meta": {
        "bownty.scale.use_config": "default",
        "bownty.scale.queue_name": "insights.alert_checks"
      }
    },
    {
      "Name": "click-rollup",
      "Count": 1,
      "Constraints": null,
      "RestartPolicy": {
        "Attempts": 2,
        "Interval": 60000000000,
        "Delay": 15000000000,
        "Mode": "delay"
      },
      "Tasks": [
        {
          "Name": "server",
          "Driver": "raw_exec",
          "User": "",
          "Config": {
            "command": "/usr/local/bin/envconsul",
            "args": [
              "-config /etc/envconsul/config.hcl -prefix apps/insights/nomad/click-rollup/server/env -prefix apps/insights/env -wait 3s:6s -splay 3s -sanitize -upcase /opt/deploy/www/insights/htdocs/app/bin/cake click_rollup server"
            ]
          },
          "Env": {
            "APP_VERSION": "1475",
            "APP_ENV": "production"
          },
          "Services": null,
          "Constraints": null,
          "Resources": {
            "CPU": 500,
            "MemoryMB": 128,
            "DiskMB": 300,
            "IOPS": 0,
            "Networks": null
          },
          "Meta": {
            "bownty.exec.command": "/opt/deploy/www/insights/htdocs/app/bin/cake click_rollup server"
          },
          "KillTimeout": 5000000000,
          "LogConfig": {
            "MaxFiles": 10,
            "MaxFileSizeMB": 10
          },
          "Artifacts": null
        }
      ],
      "Meta": {
        "bownty.scale.queue_name": "insights.click_rollup",
        "bownty.scale.use_config": "default"
      }
    },
    {
      "Name": "cost-rollup",
      "Count": 0,
      "Constraints": null,
      "RestartPolicy": {
        "Attempts": 2,
        "Interval": 60000000000,
        "Delay": 15000000000,
        "Mode": "delay"
      },
      "Tasks": [
        {
          "Name": "server",
          "Driver": "raw_exec",
          "User": "",
          "Config": {
            "command": "/usr/local/bin/envconsul",
            "args": [
              "-config /etc/envconsul/config.hcl -prefix apps/insights/nomad/cost-rollup/server/env -prefix apps/insights/env -wait 3s:6s -splay 3s -sanitize -upcase /opt/deploy/www/insights/htdocs/app/bin/cake campaign_cost server"
            ]
          },
          "Env": {
            "APP_ENV": "production",
            "APP_VERSION": "1475"
          },
          "Services": null,
          "Constraints": null,
          "Resources": {
            "CPU": 500,
            "MemoryMB": 128,
            "DiskMB": 300,
            "IOPS": 0,
            "Networks": null
          },
          "Meta": {
            "bownty.exec.command": "/opt/deploy/www/insights/htdocs/app/bin/cake campaign_cost server"
          },
          "KillTimeout": 5000000000,
          "LogConfig": {
            "MaxFiles": 10,
            "MaxFileSizeMB": 10
          },
          "Artifacts": null
        }
      ],
      "Meta": {
        "bownty.scale.queue_name": "insights.cost_rollups",
        "bownty.scale.use_config": "default"
      }
    },
    {
      "Name": "campaign-attribution-fixer",
      "Count": 0,
      "Constraints": null,
      "RestartPolicy": {
        "Attempts": 2,
        "Interval": 60000000000,
        "Delay": 15000000000,
        "Mode": "delay"
      },
      "Tasks": [
        {
          "Name": "server",
          "Driver": "raw_exec",
          "User": "",
          "Config": {
            "command": "/usr/local/bin/envconsul",
            "args": [
              "-config /etc/envconsul/config.hcl -prefix apps/insights/nomad/campaign-attribution-fixer/server/env -prefix apps/insights/env -wait 3s:6s -splay 3s -sanitize -upcase /opt/deploy/www/insights/htdocs/app/bin/cake campaign_attribution server"
            ]
          },
          "Env": {
            "APP_ENV": "production",
            "APP_VERSION": "1475"
          },
          "Services": null,
          "Constraints": null,
          "Resources": {
            "CPU": 500,
            "MemoryMB": 128,
            "DiskMB": 300,
            "IOPS": 0,
            "Networks": null
          },
          "Meta": {
            "bownty.exec.command": "/opt/deploy/www/insights/htdocs/app/bin/cake campaign_attribution server"
          },
          "KillTimeout": 5000000000,
          "LogConfig": {
            "MaxFiles": 10,
            "MaxFileSizeMB": 10
          },
          "Artifacts": null
        }
      ],
      "Meta": {
        "bownty.scale.queue_name": "insights.campaign_attribution_fix",
        "bownty.scale.use_config": "default"
      }
    },
    {
      "Name": "cassandra-copy-server",
      "Count": 0,
      "Constraints": null,
      "RestartPolicy": {
        "Attempts": 2,
        "Interval": 60000000000,
        "Delay": 15000000000,
        "Mode": "delay"
      },
      "Tasks": [
        {
          "Name": "server",
          "Driver": "raw_exec",
          "User": "",
          "Config": {
            "command": "/usr/local/bin/envconsul",
            "args": [
              "-config /etc/envconsul/config.hcl -prefix apps/insights/nomad/cassandra-copy-server/server/env -prefix apps/insights/env -wait 3s:6s -splay 3s -sanitize -upcase /opt/deploy/www/insights/htdocs/app/bin/cake cassandra_newsletter copy_server"
            ]
          },
          "Env": {
            "APP_VERSION": "1475",
            "APP_ENV": "production"
          },
          "Services": null,
          "Constraints": null,
          "Resources": {
            "CPU": 500,
            "MemoryMB": 128,
            "DiskMB": 300,
            "IOPS": 0,
            "Networks": null
          },
          "Meta": {
            "bownty.exec.command": "/opt/deploy/www/insights/htdocs/app/bin/cake cassandra_newsletter copy_server"
          },
          "KillTimeout": 5000000000,
          "LogConfig": {
            "MaxFiles": 10,
            "MaxFileSizeMB": 10
          },
          "Artifacts": null
        }
      ],
      "Meta": {
        "bownty.scale.queue_name": "cassandra_newsletter.copy",
        "bownty.scale.use_config": "default"
      }
    },
    {
      "Name": "cassandra-compare-server",
      "Count": 0,
      "Constraints": null,
      "RestartPolicy": {
        "Attempts": 2,
        "Interval": 60000000000,
        "Delay": 15000000000,
        "Mode": "delay"
      },
      "Tasks": [
        {
          "Name": "server",
          "Driver": "raw_exec",
          "User": "",
          "Config": {
            "args": [
              "-config /etc/envconsul/config.hcl -prefix apps/insights/nomad/cassandra-compare-server/server/env -prefix apps/insights/env -wait 3s:6s -splay 3s -sanitize -upcase /opt/deploy/www/insights/htdocs/app/bin/cake cassandra_newsletter compare_server"
            ],
            "command": "/usr/local/bin/envconsul"
          },
          "Env": {
            "APP_VERSION": "1475",
            "APP_ENV": "production"
          },
          "Services": null,
          "Constraints": null,
          "Resources": {
            "CPU": 500,
            "MemoryMB": 128,
            "DiskMB": 300,
            "IOPS": 0,
            "Networks": null
          },
          "Meta": {
            "bownty.exec.command": "/opt/deploy/www/insights/htdocs/app/bin/cake cassandra_newsletter compare_server"
          },
          "KillTimeout": 5000000000,
          "LogConfig": {
            "MaxFiles": 10,
            "MaxFileSizeMB": 10
          },
          "Artifacts": null
        }
      ],
      "Meta": {
        "bownty.scale.use_config": "default",
        "bownty.scale.queue_name": "cassandra_newsletter.compare"
      }
    },
    {
      "Name": "cassandra-move-server",
      "Count": 0,
      "Constraints": null,
      "RestartPolicy": {
        "Attempts": 2,
        "Interval": 60000000000,
        "Delay": 15000000000,
        "Mode": "delay"
      },
      "Tasks": [
        {
          "Name": "server",
          "Driver": "raw_exec",
          "User": "",
          "Config": {
            "command": "/usr/local/bin/envconsul",
            "args": [
              "-config /etc/envconsul/config.hcl -prefix apps/insights/nomad/cassandra-move-server/server/env -prefix apps/insights/env -wait 3s:6s -splay 3s -sanitize -upcase /opt/deploy/www/insights/htdocs/app/bin/cake cassandra_newsletter move_server"
            ]
          },
          "Env": {
            "APP_ENV": "production",
            "APP_VERSION": "1475"
          },
          "Services": null,
          "Constraints": null,
          "Resources": {
            "CPU": 500,
            "MemoryMB": 128,
            "DiskMB": 300,
            "IOPS": 0,
            "Networks": null
          },
          "Meta": {
            "bownty.exec.command": "/opt/deploy/www/insights/htdocs/app/bin/cake cassandra_newsletter move_server"
          },
          "KillTimeout": 5000000000,
          "LogConfig": {
            "MaxFiles": 10,
            "MaxFileSizeMB": 10
          },
          "Artifacts": null
        }
      ],
      "Meta": {
        "bownty.scale.queue_name": "cassandra_newsletter.move",
        "bownty.scale.use_config": "default"
      }
    },
    {
      "Name": "cassandra-delete-server",
      "Count": 0,
      "Constraints": null,
      "RestartPolicy": {
        "Attempts": 2,
        "Interval": 60000000000,
        "Delay": 15000000000,
        "Mode": "delay"
      },
      "Tasks": [
        {
          "Name": "server",
          "Driver": "raw_exec",
          "User": "",
          "Config": {
            "args": [
              "-config /etc/envconsul/config.hcl -prefix apps/insights/nomad/cassandra-delete-server/server/env -prefix apps/insights/env -wait 3s:6s -splay 3s -sanitize -upcase /opt/deploy/www/insights/htdocs/app/bin/cake cassandra_newsletter delete_server"
            ],
            "command": "/usr/local/bin/envconsul"
          },
          "Env": {
            "APP_ENV": "production",
            "APP_VERSION": "1475"
          },
          "Services": null,
          "Constraints": null,
          "Resources": {
            "CPU": 500,
            "MemoryMB": 128,
            "DiskMB": 300,
            "IOPS": 0,
            "Networks": null
          },
          "Meta": {
            "bownty.exec.command": "/opt/deploy/www/insights/htdocs/app/bin/cake cassandra_newsletter delete_server"
          },
          "KillTimeout": 5000000000,
          "LogConfig": {
            "MaxFiles": 10,
            "MaxFileSizeMB": 10
          },
          "Artifacts": null
        }
      ],
      "Meta": {
        "bownty.scale.queue_name": "cassandra_newsletter.delete",
        "bownty.scale.use_config": "default"
      }
    }
  ],
  "Update": {
    "Stagger": 5000000000,
    "MaxParallel": 2
  },
  "Periodic": null,
  "Meta": {
    "bownty.scale_config.default.rule.1.comparison_value": "99",
    "bownty.env.APP_ENV": "production",
    "bownty.scale_config.default.rule.1.comparison": "above",
    "bownty.scale_config.default.rule.0.comparison_value": "90",
    "bownty.scale_config.default.rule.0.rule_type": "queue_efficiency",
    "bownty.scale_config.default.rule.1.rule_type": "queue_efficiency",
    "bownty.scale_config.default.min_processes": "0",
    "bownty.scale_config.default.max_processes": "6",
    "bownty.scale_config.default.rule.1.if_true": "decr_numprocs = 1",
    "bownty.scale_config.default.rule.0.comparison": "below",
    "bownty.env.APP_VERSION": "1475",
    "bownty.scale_config.default.rule.0.if_true": "incr_numprocs = 1"
  },
  "Status": "running",
  "StatusDescription": "",
  "CreateIndex": 544329,
  "ModifyIndex": 544645,
  "JobModifyIndex": 544645
}

use node name for NODE value in /allocations

Currently the Node column output the ID of the node, would be nice if it could show the node name instead - I'm much better at remembering node names compared to node ids :)

Consistent task event ordering

Right now the task events are not displayed chronologically. This is confusing and should be ordered with the latest task events at the top.

RFC; change backend from go to nodejs

Just a personal preference here, since i don't know Go at all :)

Considering we already heavily use js for the frontend, it may be easier for new contributors to start out if the backend also is js rather than a 2nd language.

Some of the ideas I have for the project I could easily implement in node, but won't be impossible for me to do in Go.

Considering the fairly simple backend, it should be somewhat easy to it to node - and since the project is shipped through docker, it should be a safe change to do there as well, as there would be no additional complexity for just consuming the project.

Additional upside is that the nodejs community got a stupid amount of cool packages that we could benefit from, and have similar non-block async behavior as Go.

Add version compatibility check

Currently we build against nomad-0.4.0 but due the fact that everything is REST it is possible to run UI with older or newer nomad-0.4.0 version. We need a way for UI to run a sanity check and error if versions mismatch.

websocket is always opened of plaintext

I've setup nomad-ui behind nginx for ssl termination and client verification but the websocket connection still seems to connect to ws:// instead of wss://

So I get these errors in the console (of chrome):

event.js:79Mixed Content: The page at 'https://nomadui.redacted/#/cluster?_k=j315or' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint 'ws://nomadui.redacted/ws'. This request has been blocked; this endpoint must be available over WSS.

Change the colors to something more sensible

Right now, the same graph colors are used for everything. They should be differentiated on what they represent. Also think about color blindness and choose appropriate colors.

Proxy all requests to the nomad cluster?

I am running a nomad cluster and all communication for nomad is happening on the internal network and is not reachable on the outside.

I would like to use the nomad UI to easily see the state of the nomad cluster and the jobs in it. I use consul for service discovery and use nomad itself to run the nomad-ui docker container, but if I pass the "NOMAD_ADDR=nomad.service.consul" environment variable it will try to make calls from the browser (client) to "http://nomad.service.consul:4646" which obviously won't work. Would it be possible to proxy all calls to nomad so nomad itself won't have to be exposed?

If not, to make the UI work it would be preferable to create an "internal" nomad address and a "public" nomad address, that way I could use nginx to proxy the calls to nomad with tls on a regular port (443).

consistent sorting on event time / name

Most pages doesn't seem to enforce any kind of consistent sorting on the data.

E.g. members page change sorting randomly.

My suggesting is to apply ordering like this where possible (order of importance)

  • sort by event time with newest first on resources where such an event time is present
  • sort by criticality (running/status, with bad states first) and then on name
  • sort by name

ideally i would like to change the sorting in the UI as well

Why do we use /jobs prefix even for querying a single job?

I just spent some quality time debugging piece of my code to realize that I was naturally using /job/ prefix but we actually use /jobs everywhere!

<Route path="/jobs/:jobId/info" component={JobInfo} />
<Route path="/jobs/:jobId/allocations" component={JobAllocs} />
<Route path="/jobs/:jobId/evaluations" component={JobEvals} />

So what is the idea? Is it just a copy-paste legacy? Should we fix this?

UI fails on parsing TaskGroup "constraints"

When viewing a TaskGroup which has constraints configured the UI fails hard and doesn't recover until a hard reload.

Reproduce:

job "nomad-ui" {
    region = "ams1"
    datacenters = ["ams1"]

    update {
        stagger = "5s"
        max_parallel = 1
    }

    group "frontend" {
        count = 2

        constraint {
            distinct_hosts = true
        }

        task "web" {
            driver = "docker"
            config {
                image = "iverberk/nomad-ui:v0.1.2"
                network_mode = "host"
            }

            env {
                NOMAD_ADDR = "http://nomad.service.consul:4646"
            }

            service {
                port = "http"

                tags = []

                check {
                    type = "http"
                    path = "/"
                    interval = "10s"
                    timeout = "2s"
                }
            }

            resources {
                cpu = 500
                memory = 128
                network {
                    mbits = 1
                    port "http" {}
                }
            }
        }
    }
}

Open up the UI and navigate to the nomad-ui job (which has a constraint configured)

Give user a hint where to find the running ui

$ NOMAD_ADDR="localhost" ./nomad-ui-linux
2016/08/15 10:47:58 Starting server...

Whenever I start it says it is "starting" but leaves me wondering if:

  1. Did it actually start?
  2. Where exactly it is running?

What if we write something like this instead to not confuse user:

$ NOMAD_ADDR="localhost" ./nomad-ui-linux
2016/08/15 10:47:58 Starting server...
2016/08/15 10:47:58 Started server at localhost:3000

This way I see that it is started and obvious where to find it. What do you think?

add default for NOMAD_PORT

While I remember a lot of things, it's usually details like this that elude me. I do remember there are three ports for nomad (4 something 46, 47, and 48), but I only vaguely remember that 6 is the something, and I forget which of 46, 47, 48 is the "nomad server". Looking this up in nomad should be quick, but it took me a few pokes to remember that I should look at the agent section for configuration options.

Anyway.. that's a long way to say... defining a default that is correct / matches what the app expects from nomad would be great and save users one extra little detail to sort out when running nomad-ui for the first time.

I'd add this bit, but I'm not familiar enough with JS-tooling, and I see minimal bits in the production settings.json to work from.

Thanks for the great work!

[feature] tail functionality for logs

Feature request

When dealing with large amounts of log lines it becomes impossible to view them in the UI. It would be nice to be able to switch to a "tail" like view to not flood the browser with thousands of lines. This has been implemented in the nomad cli but being able to do it from the browser would be even better.

additional data on "/jobs" page

Hi,

on the jobs page, it would be nice to expose the JobSummary data to each row, to give a sense of the health of the job(s) - it could be a sum of all the different JobSummary aggregated into one column per row (e.g. Queued, Complete, Failed, Running, Starting and so on)

Also exposing the number of task groups below the job would be nice (maybe with a identicator on how many are health / busy / broken / dead)

'latest' docker image doesn't show any data

Maybe this is something you are already aware of - the ws connection works fine but the data coming back has no data. The structures are being returned but the data arrays are empty '[]'.

I assume 'latest' is a 'work in progress'

Files under an allocation are no longer viewable

Version

Docker Imageiverberk/nomad-ui:0.1.0 with ID c9e53b2c481a

Description

If I follow the linkss to the "Files" tab of an allocation, and then try to follow the path /alloc/logs to view the stderr and stdout files, those files in the "Path" box are no longer "clickable", and their contents do not show up under the "File" box.

This was working before the 0.1.0 tag.

Does not show any data

I am running the docker contains as described by exporting NOMAD_ADDR and NOMAD_PORT correctly. e.g.

docker run -d -e NOMAD_ADDR=10.0.2.15 -e NOMAD_PORT=4646 -e NODE_ENV="production" -p 8080:3000 iverberk/nomad-ui

My nomad agent (server mode) is running at 10.0.2.15:4646 and I can see the output from inside the docker container like below -

docker exec -it 39393dd12b4e /bin/sh
/nomad-ui # wget http://10.0.2.15:4646/v1/nodes -O /tmp/nodes && cat /tmp/nodes
Connecting to 10.0.2.15:4646 (10.0.2.15:4646)
nodes                100% |**********************************************************************************|   181   0:00:00 ETA
[{"ID":"78bb4343-c62f-3cbb-1fe6-71a739981a97","Datacenter":"dc1","Name":"nomad-server","NodeClass":"","Drain":false,"Status":"ready","StatusDescription":"","CreateIndex":3,"ModifyIndex":5}]/nomad-ui # 

However, when I look in the UI, I do not see any nodes in the dataset under "NODES". Any idea what could I be doing wrong ?

CPU spike

Awesome UI!

On OSX Chrome, every request to the Nomad API is sent as fast as possible. This makes the CPU go crazy... I've also downloaded ~50MB of json in the time I've typed this ;)

Maybe a timeout?

make build error

here is the console output

~/gocode/src/github.com/iverberk/nomad-ui$ make build
=> building webpack ...
npm install
npm WARN optional Skipping failed optional dependency /webpack/watchpack/chokidar/fsevents:
npm WARN notsup Not compatible with your operating system or architecture: [email protected]
npm run-script build

> [email protected] build /home/vagrant/gocode/src/github.com/iverberk/nomad-ui
> webpack --config webpack-prod.config.js -p --progress

 38% 8/17 build modulesBus error (core dumped)

npm ERR! Linux 3.13.0-86-generic
npm ERR! argv "/usr/bin/nodejs" "/usr/bin/npm" "run-script" "build"
npm ERR! node v6.4.0
npm ERR! npm  v3.10.3
npm ERR! code ELIFECYCLE
npm ERR! [email protected] build: `webpack --config webpack-prod.config.js -p --progress`
npm ERR! Exit status 135
npm ERR!
npm ERR! Failed at the [email protected] build script 'webpack --config webpack-prod.config.js -p --progress'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the nomad-ui package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR!     webpack --config webpack-prod.config.js -p --progress
npm ERR! You can get information on how to open an issue for this project with:
npm ERR!     npm bugs nomad-ui
npm ERR! Or if that isn't available, you can get their info via:
npm ERR!     npm owner ls nomad-ui
npm ERR! There is likely additional logging output above.

npm ERR! Please include the following file with any support request:
npm ERR!     /home/vagrant/gocode/src/github.com/iverberk/nomad-ui/npm-debug.log
make: *** [/home/vagrant/gocode/src/github.com/iverberk/nomad-ui/build/webpack] Error 1

UI breaks on very wide screen

I'm blessed with a 3440x1440 screen at work. Looking at the ui at this width causes overflowing in the Job overview:

image

I tried figuring out what causes this, but so far I'm stumped. The charts, while too large for their containers, do not cause all the extra height to be added as far as I can tell.

Expose port 3000 in the Dockerfile

Hi :)

Rather than port mapping nomad-ui to a port on the host I make use of Fabio to proxy http requests through to containers. However, even when not port-mapped, a container must still expose a port for it to be available to talk to from other containers.

As such, currently (because Nomad can't handle exposed ports) I'm having to create a child image of Nomad-UI just so I can add an 'EXPOSE 3000' command in the Dockerfile.

Would it be possible for you to just add that line to your Dockerfile?

new page "/job-health"

Having a list of all jobs / task groups / tasks that is in a bad / pending / progress / good state (broken down on this) would be amazing for a quick overview

Create a backend component for polling and aggregation

Reduce the burden of the client app by transferring the polling mechanisms to the backend. This would also eliminate the CORS restrictions. Maybe we can even do server side aggregation of information and potentially introduce security measures.

setup travis to publish executable (or docker image) with updates to master

With the job spec for nomad, we can easily run the executable release. If a user wishes to test the latest from master, they need to setup NPM and build the project. That isn't terrible, but automation is nice and travis can be setup to publish that executable (or build a docker image), with commits made to master. We could then grab the SHA and update the job spec to test on nomad.

Feel free to close this out if it does not suit your needs or workflow, I just realized it would be a great nice to have when testing out the project's latest features.

Assume that NOMAD_ADDR is localhost and NOMAD_PORT is 4646

Won't it be great if nomad-ui followed logic from nomad itself and always assumed that you want to talk to the local service? So it works right away instead of throwing this:

2016/08/15 10:47:14 Please provide NOMAD_ADDR in the environment, which points to the Nomad server.

It is invalid to list all job tasks in a single table

The thing is tasks are inside task groups. This way task name is unique only within task group but is not unique within job.

So main job/:jobId/info view errors with following error:

http://localhost:3333/#/jobs/ping
...
Warning: flattenChildren(...): Encountered two children with the same key, `ping-0`. Child keys must be unique; when two children share a key, only the first child will be used.
    in tbody (created by Table)
    in table (created by Table)
    in Table (created by JobInfo)
    in div (created by JobInfo)
    in div (created by JobInfo)
    in JobInfo (created by Connect(JobInfo))
    in Connect(JobInfo) (created by RouterContext)
    in div (created by Tabs)
    in div (created by Tabs)
    in Tabs (created by Job)
    in div (created by Job)
    in div (created by Job)
    in div (created by Job)
    in div (created by Job)
    in Job (created by Connect(Job))
    in Connect(Job) (created by RouterContext)
    in div (created by App)
    in div (created by App)
    in div (created by App)
    in div (created by App)
    in App (created by RouterContext)
    in RouterContext (created by Router)
    in Router (created by AppRouter)
    in AppRouter
    in Provider

Websockets break after ~ 24 hours

If I leave nomad-ui open overnight I find by the next day all the data has disappeared - no circular diagrams, no members, no nodes etc. This appears to be a websocket thing. If I reload the page, open it in a different browser etc. I see the same problem - no data and no 'frames' back from the websocket.

I can't see any output of use in the nomad logs.

The only solution seems to be to restart the container.

This is using the last 'latest' snapshot.

One point of note is that I'm using Fabio as a proxy - but as the html, css and js content is served correctly and opening in a second browser doesn't fix things I don't think Fabio is the cause of the issue.

basic filtering

Being able to filter lists by "simple" means would be very powerful

freetext = leftmost matching ala nomad would match nomad% (from SQL)
enum = dropdown

  • Members
    • ID = feetext
    • Datacenter = enum
    • Name = freetext
    • Class = enum
    • Drain = enum
    • Status = enum
  • Nodes
    • ID = freetext
    • DC = enum
    • Name = enum
    • Class = enum
    • Drain = enum
    • Status = enum
  • Job
    • ID = freetext
    • Type = enum
    • Priority = enum
    • Status = enum
  • Evaluations
    • ID = freetext
    • Job = freetext (enum if rows are few)
    • Status = enum
    • Type = enum
    • Priority = enum
  • Allocations
    • ID = freetext
    • Job = freetext (enum if rows are few)
    • Client Status = enum
    • Desired Status = enum
    • Node = freetext
    • Evaluation = freetext

bonus

For lists where there are a CreatedTime or similar time-sensitive data, it would be nice to be able to pick a date-range for the events you wish to see

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.