Merge branch 'master' of http://github.com/hashicorp/consul into issue/1447/http-access-logs
This commit is contained in:
commit
b8f8861d97
|
@ -1,7 +1,7 @@
|
|||
language: go
|
||||
|
||||
go:
|
||||
- tip
|
||||
- 1.5.2
|
||||
|
||||
branches:
|
||||
only:
|
||||
|
|
43
CHANGELOG.md
43
CHANGELOG.md
|
@ -1,4 +1,19 @@
|
|||
## 0.6.0 (Unreleased)
|
||||
## 0.6.1 (UNRELEASED)
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
* Consul is now built with Go 1.5.2
|
||||
* Added source IP address and port information to RPC-related log error
|
||||
messages [GH-1513]
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
* Fixed broken settings icon in web UI [GH-1469]
|
||||
* Fixed a web UI bug where the supplied token wasn't being passed into
|
||||
the internal endpoint, breaking some pages when multiple datacenters
|
||||
were present [GH-1071]
|
||||
|
||||
## 0.6.0 (December 3, 2015)
|
||||
|
||||
BACKWARDS INCOMPATIBILITIES:
|
||||
|
||||
|
@ -12,7 +27,7 @@ FEATURES:
|
|||
* Service ACLs now apply to service discovery [GH-1024]
|
||||
* Added event ACLs to guard firing user events [GH-1046]
|
||||
* Added keyring ACLs for gossip encryption keyring operations [GH-1090]
|
||||
* Added a new socket check type that does a connect as a check [GH-1130]
|
||||
* Added a new TCP check type that does a connect as a check [GH-1130]
|
||||
* Added new "tag override" feature that lets catalog updates to a
|
||||
service's tags flow down to agents [GH-1187]
|
||||
* Ported in-memory database from LMDB to an immutable radix tree to improve
|
||||
|
@ -33,7 +48,7 @@ FEATURES:
|
|||
|
||||
BUG FIXES:
|
||||
|
||||
* Fixes expired certificates in unit tests [GH-979]
|
||||
* Fixed expired certificates in unit tests [GH-979]
|
||||
* Allow services with `/` characters in the UI [GH-988]
|
||||
* Added SOA/NXDOMAIN records to negative DNS responses per RFC2308 [GH-995]
|
||||
[GH-1142] [GH-1195] [GH-1217]
|
||||
|
@ -82,23 +97,33 @@ IMPROVEMENTS:
|
|||
in the query string [GH-1318]
|
||||
* Increased session TTL max to 24 hours (use with caution, see note added
|
||||
to the Session HTTP endpoint documentation) [GH-1412]
|
||||
* Added support to the API client for retrying lock monitoring when Consul
|
||||
is unavailable, helping prevent false indications of lost locks (eg. apps
|
||||
like Vault can avoid failing over when a Consul leader election occurs)
|
||||
[GH-1457]
|
||||
* Added reap of receive buffer space for idle streams in the connection
|
||||
pool [GH-1452]
|
||||
|
||||
MISC:
|
||||
|
||||
* Lots of docs fixes
|
||||
* Lots of Vagrantfile cleanup
|
||||
* Data migrator utility removed to reduce cgo dependency [GH-1309]
|
||||
* Data migrator utility removed to eliminate cgo dependency [GH-1309]
|
||||
|
||||
UPGRADE NOTES:
|
||||
|
||||
* Consul will refuse to start if the data directory contains an "mdb" folder.
|
||||
This folder was used in versions of Consul up to 0.5.1. Consul version 0.5.2
|
||||
included a baked-in utility to automatically upgrade the data format, but
|
||||
this has been removed in Consul 0.6 to reduce the dependency on cgo.
|
||||
* Previously, service discovery was wide open, and any client could query
|
||||
information about any service without providing a token. Consul now requires
|
||||
read-level access at a minimum when ACLs are enabled to return service
|
||||
information over the REST or DNS interfaces.
|
||||
this has been removed in Consul 0.6 to eliminate the dependency on cgo.
|
||||
* New service read, event firing, and keyring ACLs may require special steps to
|
||||
perform during an upgrade if ACLs are enabled and set to deny by default.
|
||||
* Consul will refuse to start if there are multiple private IPs available, so
|
||||
if this is the case you will need to configure Consul's advertise or bind
|
||||
addresses before upgrading.
|
||||
|
||||
See https://www.consul.io/docs/upgrade-specific.html for detailed upgrade
|
||||
instructions.
|
||||
|
||||
## 0.5.2 (May 18, 2015)
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
VAGRANTFILE_API_VERSION = '2'
|
||||
|
||||
@script = <<SCRIPT
|
||||
GOVERSION="1.5.1"
|
||||
GOVERSION="1.5.2"
|
||||
SRCROOT="/opt/go"
|
||||
SRCPATH="/opt/gopath"
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ Consul API client
|
|||
This package provides the `api` package which attempts to
|
||||
provide programmatic access to the full Consul API.
|
||||
|
||||
Currently, all of the Consul APIs included in version 0.5.2 are supported.
|
||||
Currently, all of the Consul APIs included in version 0.6.0 are supported.
|
||||
|
||||
Documentation
|
||||
=============
|
||||
|
|
|
@ -172,11 +172,11 @@ func DefaultConfig() *Config {
|
|||
}
|
||||
|
||||
if !doVerify {
|
||||
config.HttpClient.Transport = &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
transport := cleanhttp.DefaultTransport()
|
||||
transport.TLSClientConfig = &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
}
|
||||
config.HttpClient.Transport = transport
|
||||
}
|
||||
}
|
||||
|
||||
|
|
30
api/lock.go
30
api/lock.go
|
@ -2,6 +2,7 @@ package api
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
@ -22,9 +23,15 @@ const (
|
|||
|
||||
// DefaultLockRetryTime is how long we wait after a failed lock acquisition
|
||||
// before attempting to do the lock again. This is so that once a lock-delay
|
||||
// is in affect, we do not hot loop retrying the acquisition.
|
||||
// is in effect, we do not hot loop retrying the acquisition.
|
||||
DefaultLockRetryTime = 5 * time.Second
|
||||
|
||||
// DefaultMonitorRetryTime is how long we wait after a failed monitor check
|
||||
// of a lock (500 response code). This allows the monitor to ride out brief
|
||||
// periods of unavailability, subject to the MonitorRetries setting in the
|
||||
// lock options which is by default set to 0, disabling this feature.
|
||||
DefaultMonitorRetryTime = 2 * time.Second
|
||||
|
||||
// LockFlagValue is a magic flag we set to indicate a key
|
||||
// is being used for a lock. It is used to detect a potential
|
||||
// conflict with a semaphore.
|
||||
|
@ -67,6 +74,8 @@ type LockOptions struct {
|
|||
Session string // Optional, created if not specified
|
||||
SessionName string // Optional, defaults to DefaultLockSessionName
|
||||
SessionTTL string // Optional, defaults to DefaultLockSessionTTL
|
||||
MonitorRetries int // Optional, defaults to 0 which means no retries
|
||||
MonitorRetryTime time.Duration // Optional, defaults to DefaultMonitorRetryTime
|
||||
}
|
||||
|
||||
// LockKey returns a handle to a lock struct which can be used
|
||||
|
@ -96,6 +105,9 @@ func (c *Client) LockOpts(opts *LockOptions) (*Lock, error) {
|
|||
return nil, fmt.Errorf("invalid SessionTTL: %v", err)
|
||||
}
|
||||
}
|
||||
if opts.MonitorRetryTime == 0 {
|
||||
opts.MonitorRetryTime = DefaultMonitorRetryTime
|
||||
}
|
||||
l := &Lock{
|
||||
c: c,
|
||||
opts: opts,
|
||||
|
@ -327,8 +339,24 @@ func (l *Lock) monitorLock(session string, stopCh chan struct{}) {
|
|||
kv := l.c.KV()
|
||||
opts := &QueryOptions{RequireConsistent: true}
|
||||
WAIT:
|
||||
retries := l.opts.MonitorRetries
|
||||
RETRY:
|
||||
pair, meta, err := kv.Get(l.opts.Key, opts)
|
||||
if err != nil {
|
||||
// TODO (slackpad) - Make a real error type here instead of using
|
||||
// a string check.
|
||||
const serverError = "Unexpected response code: 500"
|
||||
|
||||
// If configured we can try to ride out a brief Consul unavailability
|
||||
// by doing retries. Note that we have to attempt the retry in a non-
|
||||
// blocking fashion so that we have a clean place to reset the retry
|
||||
// counter if service is restored.
|
||||
if retries > 0 && strings.Contains(err.Error(), serverError) {
|
||||
time.Sleep(l.opts.MonitorRetryTime)
|
||||
retries--
|
||||
opts.WaitIndex = 0
|
||||
goto RETRY
|
||||
}
|
||||
return
|
||||
}
|
||||
if pair != nil && pair.Session == session {
|
||||
|
|
119
api/lock_test.go
119
api/lock_test.go
|
@ -2,6 +2,10 @@ package api
|
|||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/http/httputil"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -369,3 +373,118 @@ func TestLock_ReclaimLock(t *testing.T) {
|
|||
t.Fatalf("should not be leader")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLock_MonitorRetry(t *testing.T) {
|
||||
t.Parallel()
|
||||
raw, s := makeClient(t)
|
||||
defer s.Stop()
|
||||
|
||||
// Set up a server that always responds with 500 errors.
|
||||
failer := func(w http.ResponseWriter, req *http.Request) {
|
||||
w.WriteHeader(500)
|
||||
}
|
||||
outage := httptest.NewServer(http.HandlerFunc(failer))
|
||||
defer outage.Close()
|
||||
|
||||
// Set up a reverse proxy that will send some requests to the
|
||||
// 500 server and pass everything else through to the real Consul
|
||||
// server.
|
||||
var mutex sync.Mutex
|
||||
errors := 0
|
||||
director := func(req *http.Request) {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
req.URL.Scheme = "http"
|
||||
if errors > 0 && req.Method == "GET" && strings.Contains(req.URL.Path, "/v1/kv/test/lock") {
|
||||
req.URL.Host = outage.URL[7:] // Strip off "http://".
|
||||
errors--
|
||||
} else {
|
||||
req.URL.Host = raw.config.Address
|
||||
}
|
||||
}
|
||||
proxy := httptest.NewServer(&httputil.ReverseProxy{Director: director})
|
||||
defer proxy.Close()
|
||||
|
||||
// Make another client that points at the proxy instead of the real
|
||||
// Consul server.
|
||||
config := raw.config
|
||||
config.Address = proxy.URL[7:] // Strip off "http://".
|
||||
c, err := NewClient(&config)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// Set up a lock with retries enabled.
|
||||
opts := &LockOptions{
|
||||
Key: "test/lock",
|
||||
SessionTTL: "60s",
|
||||
MonitorRetries: 3,
|
||||
}
|
||||
lock, err := c.LockOpts(opts)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// Make sure the default got set.
|
||||
if lock.opts.MonitorRetryTime != DefaultMonitorRetryTime {
|
||||
t.Fatalf("bad: %d", lock.opts.MonitorRetryTime)
|
||||
}
|
||||
|
||||
// Now set a custom time for the test.
|
||||
opts.MonitorRetryTime = 250 * time.Millisecond
|
||||
lock, err = c.LockOpts(opts)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if lock.opts.MonitorRetryTime != 250*time.Millisecond {
|
||||
t.Fatalf("bad: %d", lock.opts.MonitorRetryTime)
|
||||
}
|
||||
|
||||
// Should get the lock.
|
||||
leaderCh, err := lock.Lock(nil)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if leaderCh == nil {
|
||||
t.Fatalf("not leader")
|
||||
}
|
||||
|
||||
// Poke the key using the raw client to force the monitor to wake up
|
||||
// and check the lock again. This time we will return errors for some
|
||||
// of the responses.
|
||||
mutex.Lock()
|
||||
errors = 2
|
||||
mutex.Unlock()
|
||||
pair, _, err := raw.KV().Get("test/lock", &QueryOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if _, err := raw.KV().Put(pair, &WriteOptions{}); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
time.Sleep(5 * opts.MonitorRetryTime)
|
||||
|
||||
// Should still be the leader.
|
||||
select {
|
||||
case <-leaderCh:
|
||||
t.Fatalf("should be leader")
|
||||
default:
|
||||
}
|
||||
|
||||
// Now return an overwhelming number of errors.
|
||||
mutex.Lock()
|
||||
errors = 10
|
||||
mutex.Unlock()
|
||||
if _, err := raw.KV().Put(pair, &WriteOptions{}); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
time.Sleep(5 * opts.MonitorRetryTime)
|
||||
|
||||
// Should lose leadership.
|
||||
select {
|
||||
case <-leaderCh:
|
||||
case <-time.After(time.Second):
|
||||
t.Fatalf("should not be leader")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"github.com/armon/go-metrics/datadog"
|
||||
"github.com/hashicorp/consul/watch"
|
||||
"github.com/hashicorp/go-checkpoint"
|
||||
"github.com/hashicorp/go-reap"
|
||||
"github.com/hashicorp/go-syslog"
|
||||
"github.com/hashicorp/logutils"
|
||||
scada "github.com/hashicorp/scada-client"
|
||||
|
@ -565,11 +566,6 @@ func (c *Command) Run(args []string) int {
|
|||
return 1
|
||||
}
|
||||
|
||||
// Check GOMAXPROCS
|
||||
if runtime.GOMAXPROCS(0) == 1 {
|
||||
c.Ui.Error("WARNING: It is highly recommended to set GOMAXPROCS higher than 1")
|
||||
}
|
||||
|
||||
// Setup the log outputs
|
||||
logGate, logWriter, logOutput := c.setupLoggers(config)
|
||||
if logWriter == nil {
|
||||
|
@ -646,6 +642,33 @@ func (c *Command) Run(args []string) int {
|
|||
defer server.Shutdown()
|
||||
}
|
||||
|
||||
// Enable child process reaping
|
||||
if (config.Reap != nil && *config.Reap) || (config.Reap == nil && os.Getpid() == 1) {
|
||||
if !reap.IsSupported() {
|
||||
c.Ui.Error("Child process reaping is not supported on this platform (set reap=false)")
|
||||
return 1
|
||||
} else {
|
||||
logger := c.agent.logger
|
||||
logger.Printf("[DEBUG] Automatically reaping child processes")
|
||||
|
||||
pids := make(reap.PidCh, 1)
|
||||
errors := make(reap.ErrorCh, 1)
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case pid := <-pids:
|
||||
logger.Printf("[DEBUG] Reaped child process %d", pid)
|
||||
case err := <-errors:
|
||||
logger.Printf("[ERR] Error reaping child process: %v", err)
|
||||
case <-c.agent.shutdownCh:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
go reap.ReapChildren(pids, errors, c.agent.shutdownCh)
|
||||
}
|
||||
}
|
||||
|
||||
// Check and shut down the SCADA listeners at the end
|
||||
defer func() {
|
||||
if c.scadaHttp != nil {
|
||||
|
|
|
@ -422,6 +422,17 @@ type Config struct {
|
|||
// Minimum Session TTL
|
||||
SessionTTLMin time.Duration `mapstructure:"-"`
|
||||
SessionTTLMinRaw string `mapstructure:"session_ttl_min"`
|
||||
|
||||
// Reap controls automatic reaping of child processes, useful if running
|
||||
// as PID 1 in a Docker container. This defaults to nil which will make
|
||||
// Consul reap only if it detects it's running as PID 1. If non-nil,
|
||||
// then this will be used to decide if reaping is enabled.
|
||||
Reap *bool `mapstructure:"reap"`
|
||||
}
|
||||
|
||||
// Bool is used to initialize bool pointers in struct literals.
|
||||
func Bool(b bool) *bool {
|
||||
return &b
|
||||
}
|
||||
|
||||
// UnixSocketPermissions contains information about a unix socket, and
|
||||
|
@ -1140,6 +1151,10 @@ func MergeConfig(a, b *Config) *Config {
|
|||
result.RetryJoinWan = append(result.RetryJoinWan, a.RetryJoinWan...)
|
||||
result.RetryJoinWan = append(result.RetryJoinWan, b.RetryJoinWan...)
|
||||
|
||||
if b.Reap != nil {
|
||||
result.Reap = b.Reap
|
||||
}
|
||||
|
||||
return &result
|
||||
}
|
||||
|
||||
|
|
|
@ -777,6 +777,27 @@ func TestDecodeConfig(t *testing.T) {
|
|||
if config.SessionTTLMin != 5*time.Second {
|
||||
t.Fatalf("bad: %s %#v", config.SessionTTLMin.String(), config)
|
||||
}
|
||||
|
||||
// Reap
|
||||
input = `{"reap": true}`
|
||||
config, err = DecodeConfig(bytes.NewReader([]byte(input)))
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if config.Reap == nil || *config.Reap != true {
|
||||
t.Fatalf("bad: reap not enabled: %#v", config)
|
||||
}
|
||||
|
||||
input = `{}`
|
||||
config, err = DecodeConfig(bytes.NewReader([]byte(input)))
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if config.Reap != nil {
|
||||
t.Fatalf("bad: reap not tri-stated: %#v", config)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeConfig_invalidKeys(t *testing.T) {
|
||||
|
@ -1266,6 +1287,7 @@ func TestMergeConfig(t *testing.T) {
|
|||
RPC: &net.TCPAddr{},
|
||||
RPCRaw: "127.0.0.5:1233",
|
||||
},
|
||||
Reap: Bool(true),
|
||||
}
|
||||
|
||||
c := MergeConfig(a, b)
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/armon/go-metrics"
|
||||
"github.com/hashicorp/consul/consul"
|
||||
"github.com/hashicorp/consul/consul/structs"
|
||||
"github.com/miekg/dns"
|
||||
|
@ -165,6 +166,7 @@ START:
|
|||
func (d *DNSServer) handlePtr(resp dns.ResponseWriter, req *dns.Msg) {
|
||||
q := req.Question[0]
|
||||
defer func(s time.Time) {
|
||||
metrics.MeasureSince([]string{"consul", "dns", "ptr_query", d.agent.config.NodeName}, s)
|
||||
d.logger.Printf("[DEBUG] dns: request for %v (%v) from client %s (%s)",
|
||||
q, time.Now().Sub(s), resp.RemoteAddr().String(),
|
||||
resp.RemoteAddr().Network())
|
||||
|
@ -227,6 +229,7 @@ func (d *DNSServer) handlePtr(resp dns.ResponseWriter, req *dns.Msg) {
|
|||
func (d *DNSServer) handleQuery(resp dns.ResponseWriter, req *dns.Msg) {
|
||||
q := req.Question[0]
|
||||
defer func(s time.Time) {
|
||||
metrics.MeasureSince([]string{"consul", "dns", "domain_query", d.agent.config.NodeName}, s)
|
||||
d.logger.Printf("[DEBUG] dns: request for %v (%v) from client %s (%s)",
|
||||
q, time.Now().Sub(s), resp.RemoteAddr().String(),
|
||||
resp.RemoteAddr().Network())
|
||||
|
|
|
@ -567,7 +567,7 @@ func (l *localState) syncService(id string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// syncCheck is used to sync a service to the server
|
||||
// syncCheck is used to sync a check to the server
|
||||
func (l *localState) syncCheck(id string) error {
|
||||
// Pull in the associated service if any
|
||||
check := l.checks[id]
|
||||
|
|
|
@ -48,21 +48,6 @@ func (i *InfoCommand) Run(args []string) int {
|
|||
return 1
|
||||
}
|
||||
|
||||
// Check for specific warnings
|
||||
didWarn := false
|
||||
runtime, ok := stats["runtime"]
|
||||
if ok {
|
||||
if maxprocs := runtime["max_procs"]; maxprocs == "1" {
|
||||
i.Ui.Output("WARNING: It is highly recommended to set GOMAXPROCS higher than 1")
|
||||
didWarn = true
|
||||
}
|
||||
}
|
||||
|
||||
// Add a blank line if there are any warnings
|
||||
if didWarn {
|
||||
i.Ui.Output("")
|
||||
}
|
||||
|
||||
// Get the keys in sorted order
|
||||
keys := make([]string, 0, len(stats))
|
||||
for key := range stats {
|
||||
|
|
|
@ -76,7 +76,7 @@ func (c *Coordinate) batchApplyUpdates() error {
|
|||
break
|
||||
}
|
||||
|
||||
updates[i] = &structs.Coordinate{node, coord}
|
||||
updates[i] = &structs.Coordinate{Node: node, Coord: coord}
|
||||
i++
|
||||
}
|
||||
|
||||
|
|
|
@ -103,6 +103,12 @@ func (c *Conn) returnClient(client *StreamClient) {
|
|||
if c.clients.Len() < c.pool.maxStreams && atomic.LoadInt32(&c.shouldClose) == 0 {
|
||||
c.clients.PushFront(client)
|
||||
didSave = true
|
||||
|
||||
// If this is a Yamux stream, shrink the internal buffers so that
|
||||
// we can GC the idle memory
|
||||
if ys, ok := client.stream.(*yamux.Stream); ok {
|
||||
ys.Shrink()
|
||||
}
|
||||
}
|
||||
c.clientLock.Unlock()
|
||||
if !didSave {
|
||||
|
|
|
@ -219,8 +219,6 @@ func (p *PreparedQuery) Get(args *structs.PreparedQuerySpecificRequest,
|
|||
reply.Queries = structs.PreparedQueries{query}
|
||||
return nil
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// List returns all the prepared queries.
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/armon/go-metrics"
|
||||
"github.com/hashicorp/consul/consul/state"
|
||||
"github.com/hashicorp/consul/consul/structs"
|
||||
"github.com/hashicorp/memberlist"
|
||||
"github.com/hashicorp/net-rpc-msgpackrpc"
|
||||
"github.com/hashicorp/yamux"
|
||||
"github.com/inconshreveable/muxado"
|
||||
|
@ -69,6 +70,12 @@ func (s *Server) listen() {
|
|||
}
|
||||
}
|
||||
|
||||
// logConn is a wrapper around memberlist's LogConn so that we format references
|
||||
// to "from" addresses in a consistent way. This is just a shorter name.
|
||||
func logConn(conn net.Conn) string {
|
||||
return memberlist.LogConn(conn)
|
||||
}
|
||||
|
||||
// handleConn is used to determine if this is a Raft or
|
||||
// Consul type RPC connection and invoke the correct handler
|
||||
func (s *Server) handleConn(conn net.Conn, isTLS bool) {
|
||||
|
@ -76,7 +83,7 @@ func (s *Server) handleConn(conn net.Conn, isTLS bool) {
|
|||
buf := make([]byte, 1)
|
||||
if _, err := conn.Read(buf); err != nil {
|
||||
if err != io.EOF {
|
||||
s.logger.Printf("[ERR] consul.rpc: failed to read byte: %v", err)
|
||||
s.logger.Printf("[ERR] consul.rpc: failed to read byte: %v %s", err, logConn(conn))
|
||||
}
|
||||
conn.Close()
|
||||
return
|
||||
|
@ -84,7 +91,7 @@ func (s *Server) handleConn(conn net.Conn, isTLS bool) {
|
|||
|
||||
// Enforce TLS if VerifyIncoming is set
|
||||
if s.config.VerifyIncoming && !isTLS && RPCType(buf[0]) != rpcTLS {
|
||||
s.logger.Printf("[WARN] consul.rpc: Non-TLS connection attempted with VerifyIncoming set")
|
||||
s.logger.Printf("[WARN] consul.rpc: Non-TLS connection attempted with VerifyIncoming set %s", logConn(conn))
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
|
@ -103,7 +110,7 @@ func (s *Server) handleConn(conn net.Conn, isTLS bool) {
|
|||
|
||||
case rpcTLS:
|
||||
if s.rpcTLS == nil {
|
||||
s.logger.Printf("[WARN] consul.rpc: TLS connection attempted, server not configured for TLS")
|
||||
s.logger.Printf("[WARN] consul.rpc: TLS connection attempted, server not configured for TLS %s", logConn(conn))
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
|
@ -114,7 +121,7 @@ func (s *Server) handleConn(conn net.Conn, isTLS bool) {
|
|||
s.handleMultiplexV2(conn)
|
||||
|
||||
default:
|
||||
s.logger.Printf("[ERR] consul.rpc: unrecognized RPC byte: %v", buf[0])
|
||||
s.logger.Printf("[ERR] consul.rpc: unrecognized RPC byte: %v %s", buf[0], logConn(conn))
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
|
@ -129,7 +136,7 @@ func (s *Server) handleMultiplex(conn net.Conn) {
|
|||
sub, err := server.Accept()
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "closed") {
|
||||
s.logger.Printf("[ERR] consul.rpc: multiplex conn accept failed: %v", err)
|
||||
s.logger.Printf("[ERR] consul.rpc: multiplex conn accept failed: %v %s", err, logConn(conn))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -148,7 +155,7 @@ func (s *Server) handleMultiplexV2(conn net.Conn) {
|
|||
sub, err := server.Accept()
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
s.logger.Printf("[ERR] consul.rpc: multiplex conn accept failed: %v", err)
|
||||
s.logger.Printf("[ERR] consul.rpc: multiplex conn accept failed: %v %s", err, logConn(conn))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -169,7 +176,7 @@ func (s *Server) handleConsulConn(conn net.Conn) {
|
|||
|
||||
if err := s.rpcServer.ServeRequest(rpcCodec); err != nil {
|
||||
if err != io.EOF && !strings.Contains(err.Error(), "closed") {
|
||||
s.logger.Printf("[ERR] consul.rpc: RPC error: %v (%v)", err, conn)
|
||||
s.logger.Printf("[ERR] consul.rpc: RPC error: %v %s", err, logConn(conn))
|
||||
metrics.IncrCounter([]string{"consul", "rpc", "request_error"}, 1)
|
||||
}
|
||||
return
|
||||
|
|
|
@ -371,7 +371,7 @@ func getDatacenterMaps(s serfer, dcs []string) []structs.DatacenterMap {
|
|||
nodes := s.GetNodesForDatacenter(dc)
|
||||
for _, node := range nodes {
|
||||
if coord, ok := s.GetCachedCoordinate(node); ok {
|
||||
entry := &structs.Coordinate{node, coord}
|
||||
entry := &structs.Coordinate{Node: node, Coord: coord}
|
||||
m.Coordinates = append(m.Coordinates, entry)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,6 +76,19 @@ func (s *StateStore) preparedQuerySetTxn(tx *memdb.Txn, idx uint64, query *struc
|
|||
query.ModifyIndex = idx
|
||||
}
|
||||
|
||||
// Verify that the query name doesn't already exist, or that we are
|
||||
// updating the same instance that has this name.
|
||||
if query.Name != "" {
|
||||
alias, err := tx.First("prepared-queries", "name", query.Name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed prepared query lookup: %s", err)
|
||||
}
|
||||
if alias != nil && (existing == nil ||
|
||||
existing.(*structs.PreparedQuery).ID != alias.(*structs.PreparedQuery).ID) {
|
||||
return fmt.Errorf("name '%s' aliases an existing query name", query.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that the name doesn't alias any existing ID. We allow queries
|
||||
// to be looked up by ID *or* name so we don't want anyone to try to
|
||||
// register a query with a name equal to some other query's ID in an
|
||||
|
@ -86,12 +99,12 @@ func (s *StateStore) preparedQuerySetTxn(tx *memdb.Txn, idx uint64, query *struc
|
|||
// index will complain if we look up something that's not formatted
|
||||
// like one.
|
||||
if isUUID(query.Name) {
|
||||
existing, err := tx.First("prepared-queries", "id", query.Name)
|
||||
alias, err := tx.First("prepared-queries", "id", query.Name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed prepared query lookup: %s", err)
|
||||
}
|
||||
if existing != nil {
|
||||
return fmt.Errorf("name '%s' aliases an existing query id", query.Name)
|
||||
if alias != nil {
|
||||
return fmt.Errorf("name '%s' aliases an existing query ID", query.Name)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -175,27 +175,22 @@ func TestStateStore_PreparedQuerySet_PreparedQueryGet(t *testing.T) {
|
|||
t.Fatalf("bad: %v", actual)
|
||||
}
|
||||
|
||||
// Finally, try to abuse the system by trying to register a query whose
|
||||
// name aliases a real query ID.
|
||||
// Try to register a query with the same name and make sure it fails.
|
||||
{
|
||||
evil := &structs.PreparedQuery{
|
||||
ID: testUUID(),
|
||||
Name: query.ID,
|
||||
Name: query.Name,
|
||||
Service: structs.ServiceQuery{
|
||||
Service: "redis",
|
||||
},
|
||||
}
|
||||
err = s.PreparedQuerySet(7, evil)
|
||||
if err == nil || !strings.Contains(err.Error(), "aliases an existing query") {
|
||||
err := s.PreparedQuerySet(7, evil)
|
||||
if err == nil || !strings.Contains(err.Error(), "aliases an existing query name") {
|
||||
t.Fatalf("bad: %v", err)
|
||||
}
|
||||
|
||||
// Index is not updated if nothing is saved.
|
||||
if idx := s.maxIndex("prepared-queries"); idx != 6 {
|
||||
t.Fatalf("bad index: %d", idx)
|
||||
}
|
||||
|
||||
// Sanity check to make sure it's not there.
|
||||
idx, actual, err = s.PreparedQueryGet(evil.ID)
|
||||
idx, actual, err := s.PreparedQueryGet(evil.ID)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
@ -205,6 +200,40 @@ func TestStateStore_PreparedQuerySet_PreparedQueryGet(t *testing.T) {
|
|||
if actual != nil {
|
||||
t.Fatalf("bad: %v", actual)
|
||||
}
|
||||
}
|
||||
|
||||
// Try to abuse the system by trying to register a query whose name
|
||||
// aliases a real query ID.
|
||||
{
|
||||
evil := &structs.PreparedQuery{
|
||||
ID: testUUID(),
|
||||
Name: query.ID,
|
||||
Service: structs.ServiceQuery{
|
||||
Service: "redis",
|
||||
},
|
||||
}
|
||||
err := s.PreparedQuerySet(8, evil)
|
||||
if err == nil || !strings.Contains(err.Error(), "aliases an existing query ID") {
|
||||
t.Fatalf("bad: %v", err)
|
||||
}
|
||||
|
||||
// Sanity check to make sure it's not there.
|
||||
idx, actual, err := s.PreparedQueryGet(evil.ID)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if idx != 6 {
|
||||
t.Fatalf("bad index: %d", idx)
|
||||
}
|
||||
if actual != nil {
|
||||
t.Fatalf("bad: %v", actual)
|
||||
}
|
||||
}
|
||||
|
||||
// Index is not updated if nothing is saved.
|
||||
if idx := s.maxIndex("prepared-queries"); idx != 6 {
|
||||
t.Fatalf("bad index: %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateStore_PreparedQueryDelete(t *testing.T) {
|
||||
|
|
|
@ -3,11 +3,12 @@
|
|||
$script = <<SCRIPT
|
||||
|
||||
echo Installing dependencies...
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y unzip curl
|
||||
|
||||
echo Fetching Consul...
|
||||
cd /tmp/
|
||||
wget https://dl.bintray.com/mitchellh/consul/0.5.2_linux_amd64.zip -O consul.zip
|
||||
wget https://releases.hashicorp.com/consul/0.6.0/consul_0.6.0_linux_amd64.zip -O consul.zip
|
||||
|
||||
echo Installing Consul...
|
||||
unzip consul.zip
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
{
|
||||
"ImportPath": "github.com/hashicorp/consul",
|
||||
"GoVersion": "go1.5.1",
|
||||
"Deps": [
|
||||
{
|
||||
"ImportPath": "github.com/DataDog/datadog-go/statsd",
|
||||
"Rev": "b050cd8f4d7c394545fd7d966c8e2909ce89d552"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/armon/circbuf",
|
||||
"Rev": "bbbad097214e2918d8543d5201d12bfd7bca254d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/armon/go-metrics",
|
||||
"Rev": "6c5fa0d8f48f4661c9ba8709799c88d425ad20f0"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/armon/go-radix",
|
||||
"Rev": "fbd82e84e2b13651f3abc5ffd26b65ba71bc8f93"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/boltdb/bolt",
|
||||
"Comment": "v1.1.0-19-g0b00eff",
|
||||
"Rev": "0b00effdd7a8270ebd91c24297e51643e370dd52"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/fsouza/go-dockerclient",
|
||||
"Rev": "2350d7bc12bb04f2d7d6824c7718012b1397b760"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/errwrap",
|
||||
"Rev": "7554cd9344cec97297fa6649b055a8c98c2a1e55"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/go-checkpoint",
|
||||
"Rev": "e4b2dc34c0f698ee04750bf2035d8b9384233e1b"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/go-cleanhttp",
|
||||
"Rev": "5df5ddc69534f1a4697289f1dca2193fbb40213f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/go-immutable-radix",
|
||||
"Rev": "aca1bd0689e10884f20d114aff148ddb849ece80"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/go-memdb",
|
||||
"Rev": "9ea975be0e31ada034a5760340d4892f3f543d20"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/go-msgpack/codec",
|
||||
"Rev": "fa3f63826f7c23912c15263591e65d54d080b458"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/go-multierror",
|
||||
"Rev": "d30f09973e19c1dfcd120b2d9c4f168e68d6b5d5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/go-syslog",
|
||||
"Rev": "42a2b573b664dbf281bd48c3cc12c086b17a39ba"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/golang-lru",
|
||||
"Rev": "a6091bb5d00e2e9c4a16a0e739e306f8a3071a3c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/hcl",
|
||||
"Rev": "2deb1d1db27ed473f38fe65a16044572b9ff9d30"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/logutils",
|
||||
"Rev": "0dc08b1671f34c4250ce212759ebd880f743d883"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/memberlist",
|
||||
"Rev": "28424fb38c7c3e30f366b72b1a55f690d318d8f3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/net-rpc-msgpackrpc",
|
||||
"Rev": "a14192a58a694c123d8fe5481d4a4727d6ae82f3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/raft",
|
||||
"Rev": "d136cd15dfb7876fd7c89cad1995bc4f19ceb294"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/raft-boltdb",
|
||||
"Rev": "d1e82c1ec3f15ee991f7cc7ffd5b67ff6f5bbaee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/scada-client",
|
||||
"Rev": "84989fd23ad4cc0e7ad44d6a871fd793eb9beb0a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/serf/coordinate",
|
||||
"Comment": "v0.6.4-145-ga72c045",
|
||||
"Rev": "a72c0453da2ba628a013e98bf323a76be4aa1443"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/serf/serf",
|
||||
"Comment": "v0.6.4-145-ga72c045",
|
||||
"Rev": "a72c0453da2ba628a013e98bf323a76be4aa1443"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/yamux",
|
||||
"Rev": "df949784da9ed028ee76df44652e42d37a09d7e4"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/inconshreveable/muxado",
|
||||
"Rev": "f693c7e88ba316d1a0ae3e205e22a01aa3ec2848"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/miekg/dns",
|
||||
"Rev": "d27455715200c7d3e321a1e5cadb27c9ee0b0f02"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mitchellh/cli",
|
||||
"Rev": "8102d0ed5ea2709ade1243798785888175f6e415"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mitchellh/mapstructure",
|
||||
"Rev": "281073eb9eb092240d33ef253c404f1cca550309"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/ryanuber/columnize",
|
||||
"Comment": "v2.0.1-8-g983d3a5",
|
||||
"Rev": "983d3a5fab1bf04d1b412465d2d9f8430e2e917e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/ssh/terminal",
|
||||
"Rev": "346896d57731cb5670b36c6178fc5519f3225980"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -57,3 +57,6 @@ development configuration.
|
|||
`make dist`
|
||||
|
||||
The `dist` folder will contain the files you should use for deployment.
|
||||
|
||||
###Acknowledgements
|
||||
cog icon by useiconic.com from the [Noun Project](https://thenounproject.com/term/setting/45865/)
|
||||
|
|
|
@ -161,7 +161,11 @@
|
|||
</div>
|
||||
|
||||
<div class="col-md-1 col-sm-2 col-xs-2 col-md-offset-0 col-sm-offset-0 col-xs-offset-0">
|
||||
{{#link-to 'settings' class='btn btn-default col-xs-6 icon'}}<span class="wrap">⚙</span>{{/link-to}}
|
||||
{{#link-to 'settings' class='btn btn-default col-xs-6 icon'}}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" data-icon="cog" viewBox="0 0 32 40">
|
||||
<path d="M14 0l-1.313 4c-1 .3-1.975.688-2.875 1.188l-3.72-1.875-2.78 2.78 1.875 3.72c-.5.9-.888 1.875-1.188 2.875L0 14v4l4 1.314c.3 1 .687 1.975 1.187 2.875l-1.78 3.718 2.78 2.78 3.72-1.874c.9.5 1.905.887 2.905 1.188l1.28 4h4l1.314-4c1-.3 2.006-.688 2.906-1.188L26 28.594l2.813-2.78-1.906-3.72c.5-.9.887-1.905 1.188-2.905L32 18v-4l-4-1.312c-.3-1-.687-1.975-1.187-2.875l1.78-3.72-2.78-2.78-3.72 1.875c-.9-.5-1.905-.888-2.905-1.188L18 0h-4zm2 9c3.9 0 7 3.1 7 7s-3.1 7-7 7-7-3.1-7-7 3.1-7 7-7z"/>
|
||||
</svg>
|
||||
{{/link-to}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -88,12 +88,14 @@ App.IndexRoute = App.BaseRoute.extend({
|
|||
// functioning, as well as the per-dc requests.
|
||||
App.DcRoute = App.BaseRoute.extend({
|
||||
model: function(params) {
|
||||
var token = App.get('settings.token');
|
||||
|
||||
// Return a promise hash to retreieve the
|
||||
// dcs and nodes used in the header
|
||||
return Ember.RSVP.hash({
|
||||
dc: params.dc,
|
||||
dcs: Ember.$.getJSON('/v1/catalog/datacenters'),
|
||||
nodes: Ember.$.getJSON(formatUrl('/v1/internal/ui/nodes', params.dc)).then(function(data) {
|
||||
nodes: Ember.$.getJSON(formatUrl('/v1/internal/ui/nodes', params.dc, token)).then(function(data) {
|
||||
var objs = [];
|
||||
|
||||
// Merge the nodes into a list and create objects out of them
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -112,13 +112,11 @@
|
|||
.topbar {
|
||||
.btn.icon {
|
||||
min-width: 50px;
|
||||
font-size: 30px;
|
||||
height: 33px;
|
||||
padding: 0;
|
||||
.wrap {
|
||||
position: absolute;
|
||||
top: -8px;
|
||||
left: 14px;
|
||||
padding: 6px 0;
|
||||
svg {
|
||||
height: 20px;
|
||||
fill: currentColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,9 +7,9 @@ var (
|
|||
)
|
||||
|
||||
// The main version number that is being run at the moment.
|
||||
const Version = "0.6.0"
|
||||
const Version = "0.6.1"
|
||||
|
||||
// A pre-release marker for the version. If this is "" (empty string)
|
||||
// then it means that it is a final release. Otherwise, this is a pre-release
|
||||
// such as "dev" (in development), "beta", "rc1", etc.
|
||||
const VersionPrerelease = "rc2"
|
||||
const VersionPrerelease = "dev"
|
||||
|
|
|
@ -6,7 +6,7 @@ set :base_url, "https://www.consul.io/"
|
|||
|
||||
activate :hashicorp do |h|
|
||||
h.name = "consul"
|
||||
h.version = "0.5.2"
|
||||
h.version = "0.6.0"
|
||||
h.github_slug = "hashicorp/consul"
|
||||
end
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,50 @@
|
|||
(function(){
|
||||
|
||||
Sidebar = Base.extend({
|
||||
|
||||
$body: null,
|
||||
$overlay: null,
|
||||
$sidebar: null,
|
||||
$sidebarHeader: null,
|
||||
$sidebarImg: null,
|
||||
$toggleButton: null,
|
||||
|
||||
constructor: function(){
|
||||
this.$body = $('body');
|
||||
this.$overlay = $('.sidebar-overlay');
|
||||
this.$sidebar = $('#sidebar');
|
||||
this.$sidebarHeader = $('#sidebar .sidebar-header');
|
||||
this.$toggleButton = $('.navbar-toggle');
|
||||
this.sidebarImg = this.$sidebarHeader.css('background-image');
|
||||
|
||||
this.addEventListeners();
|
||||
},
|
||||
|
||||
addEventListeners: function(){
|
||||
var _this = this;
|
||||
|
||||
_this.$toggleButton.on('click', function() {
|
||||
_this.$sidebar.toggleClass('open');
|
||||
if ((_this.$sidebar.hasClass('sidebar-fixed-left') || _this.$sidebar.hasClass('sidebar-fixed-right')) && _this.$sidebar.hasClass('open')) {
|
||||
_this.$overlay.addClass('active');
|
||||
_this.$body.css('overflow', 'hidden');
|
||||
} else {
|
||||
_this.$overlay.removeClass('active');
|
||||
_this.$body.css('overflow', 'auto');
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
_this.$overlay.on('click', function() {
|
||||
$(this).removeClass('active');
|
||||
_this.$body.css('overflow', 'auto');
|
||||
_this.$sidebar.removeClass('open');
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
window.Sidebar = Sidebar;
|
||||
|
||||
})();
|
|
@ -4,8 +4,15 @@
|
|||
|
||||
var APP = (function() {
|
||||
|
||||
function initialize (){
|
||||
function initializeSidebar() {
|
||||
new Sidebar();
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
APP.Utils.runIfClassNamePresent('page-home', initHome);
|
||||
|
||||
//always init sidebar
|
||||
initializeSidebar();
|
||||
}
|
||||
|
||||
function initHome() {
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
(function(){
|
||||
|
||||
var mainContentMin = 600;
|
||||
|
||||
var Init = {
|
||||
|
||||
start: function(){
|
||||
var classname = this.hasClass(document.body, 'page-sub');
|
||||
|
||||
if (classname) {
|
||||
this.addEventListeners();
|
||||
}
|
||||
},
|
||||
|
||||
hasClass: function (elem, className) {
|
||||
return new RegExp(' ' + className + ' ').test(' ' + elem.className + ' ');
|
||||
},
|
||||
|
||||
addEventListeners: function(){
|
||||
var _this = this;
|
||||
//console.log(document.querySelectorAll('.navbar-static-top')[0]);
|
||||
window.addEventListener('resize', _this.resizeImage, false);
|
||||
|
||||
this.resizeImage();
|
||||
},
|
||||
|
||||
resizeImage: function(){
|
||||
|
||||
var header = document.getElementById('header'),
|
||||
footer = document.getElementById('footer'),
|
||||
main = document.getElementById('main-content'),
|
||||
vp = window.innerHeight,
|
||||
bodyHeight = document.body.clientHeight,
|
||||
hHeight = header.clientHeight,
|
||||
fHeight = footer.clientHeight,
|
||||
withMinHeight = hHeight + fHeight + mainContentMin;
|
||||
|
||||
if(withMinHeight < vp && bodyHeight < vp){
|
||||
var newHeight = mainContentMin + (vp-withMinHeight) + 'px';
|
||||
main.style.height = newHeight;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Init.start();
|
||||
|
||||
})();
|
|
@ -46,4 +46,3 @@ var APP = APP || {};
|
|||
}());
|
||||
|
||||
}(jQuery, this));
|
||||
|
||||
|
|
|
@ -28,6 +28,6 @@ APP.Utils = (function () {
|
|||
initFunction();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}());
|
|
@ -2,6 +2,10 @@
|
|||
#= require jquery
|
||||
#= require bootstrap
|
||||
|
||||
#= require lib/Base
|
||||
|
||||
#= require _app/docs
|
||||
#= require _app/Sidebar
|
||||
#= require _app/app
|
||||
#= require _app/homepage
|
||||
#= require _app/util
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
Based on Base.js 1.1a (c) 2006-2010, Dean Edwards
|
||||
Updated to pass JSHint and converted into a module by Kenneth Powers
|
||||
License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
/*global define:true module:true*/
|
||||
/*jshint eqeqeq:true*/
|
||||
(function (name, global, definition) {
|
||||
if (typeof module !== 'undefined') {
|
||||
module.exports = definition();
|
||||
} else if (typeof define !== 'undefined' && typeof define.amd === 'object') {
|
||||
define(definition);
|
||||
} else {
|
||||
global[name] = definition();
|
||||
}
|
||||
})('Base', this, function () {
|
||||
// Base Object
|
||||
var Base = function () {};
|
||||
|
||||
// Implementation
|
||||
Base.extend = function (_instance, _static) { // subclass
|
||||
var extend = Base.prototype.extend;
|
||||
// build the prototype
|
||||
Base._prototyping = true;
|
||||
var proto = new this();
|
||||
extend.call(proto, _instance);
|
||||
proto.base = function () {
|
||||
// call this method from any other method to invoke that method's ancestor
|
||||
};
|
||||
delete Base._prototyping;
|
||||
// create the wrapper for the constructor function
|
||||
//var constructor = proto.constructor.valueOf(); //-dean
|
||||
var constructor = proto.constructor;
|
||||
var klass = proto.constructor = function () {
|
||||
if (!Base._prototyping) {
|
||||
if (this._constructing || this.constructor === klass) { // instantiation
|
||||
this._constructing = true;
|
||||
constructor.apply(this, arguments);
|
||||
delete this._constructing;
|
||||
} else if (arguments[0] !== null) { // casting
|
||||
return (arguments[0].extend || extend).call(arguments[0], proto);
|
||||
}
|
||||
}
|
||||
};
|
||||
// build the class interface
|
||||
klass.ancestor = this;
|
||||
klass.extend = this.extend;
|
||||
klass.forEach = this.forEach;
|
||||
klass.implement = this.implement;
|
||||
klass.prototype = proto;
|
||||
klass.toString = this.toString;
|
||||
klass.valueOf = function (type) {
|
||||
return (type === 'object') ? klass : constructor.valueOf();
|
||||
};
|
||||
extend.call(klass, _static);
|
||||
// class initialization
|
||||
if (typeof klass.init === 'function') klass.init();
|
||||
return klass;
|
||||
};
|
||||
|
||||
Base.prototype = {
|
||||
extend: function (source, value) {
|
||||
if (arguments.length > 1) { // extending with a name/value pair
|
||||
var ancestor = this[source];
|
||||
if (ancestor && (typeof value === 'function') && // overriding a method?
|
||||
// the valueOf() comparison is to avoid circular references
|
||||
(!ancestor.valueOf || ancestor.valueOf() !== value.valueOf()) && /\bbase\b/.test(value)) {
|
||||
// get the underlying method
|
||||
var method = value.valueOf();
|
||||
// override
|
||||
value = function () {
|
||||
var previous = this.base || Base.prototype.base;
|
||||
this.base = ancestor;
|
||||
var returnValue = method.apply(this, arguments);
|
||||
this.base = previous;
|
||||
return returnValue;
|
||||
};
|
||||
// point to the underlying method
|
||||
value.valueOf = function (type) {
|
||||
return (type === 'object') ? value : method;
|
||||
};
|
||||
value.toString = Base.toString;
|
||||
}
|
||||
this[source] = value;
|
||||
} else if (source) { // extending with an object literal
|
||||
var extend = Base.prototype.extend;
|
||||
// if this object has a customized extend method then use it
|
||||
if (!Base._prototyping && typeof this !== 'function') {
|
||||
extend = this.extend || extend;
|
||||
}
|
||||
var proto = {
|
||||
toSource: null
|
||||
};
|
||||
// do the "toString" and other methods manually
|
||||
var hidden = ['constructor', 'toString', 'valueOf'];
|
||||
// if we are prototyping then include the constructor
|
||||
for (var i = Base._prototyping ? 0 : 1; i < hidden.length; i++) {
|
||||
var h = hidden[i];
|
||||
if (source[h] !== proto[h])
|
||||
extend.call(this, h, source[h]);
|
||||
}
|
||||
// copy each of the source object's properties to this object
|
||||
for (var key in source) {
|
||||
if (!proto[key]) extend.call(this, key, source[key]);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
// initialize
|
||||
Base = Base.extend({
|
||||
constructor: function () {
|
||||
this.extend(arguments[0]);
|
||||
}
|
||||
}, {
|
||||
ancestor: Object,
|
||||
version: '1.1',
|
||||
forEach: function (object, block, context) {
|
||||
for (var key in object) {
|
||||
if (this.prototype[key] === undefined) {
|
||||
block.call(context, object[key], key, object);
|
||||
}
|
||||
}
|
||||
},
|
||||
implement: function () {
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
if (typeof arguments[i] === 'function') {
|
||||
// if it's a function, call it
|
||||
arguments[i](this.prototype);
|
||||
} else {
|
||||
// add the interface using the extend method
|
||||
this.prototype.extend(arguments[i]);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
toString: function () {
|
||||
return String(this.valueOf());
|
||||
}
|
||||
});
|
||||
|
||||
// Return Base implementation
|
||||
return Base;
|
||||
});
|
|
@ -6,6 +6,10 @@ body.layout-docs,
|
|||
body.layout-intro{
|
||||
background: $light-purple image-url('sidebar-dots.jpg') left 62px no-repeat;
|
||||
|
||||
#main-content{
|
||||
min-height: 600px;
|
||||
}
|
||||
|
||||
>.container{
|
||||
.col-md-8[role=main]{
|
||||
min-height: 800px;
|
||||
|
@ -140,7 +144,7 @@ body.layout-intro{
|
|||
|
||||
> a{
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-family: $font-family-open-sans;
|
||||
font-family: $font-family-source-sans;
|
||||
padding: 6px 15px;
|
||||
}
|
||||
|
||||
|
@ -152,14 +156,14 @@ body.layout-intro{
|
|||
padding: 6px 0;
|
||||
> a{
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-family: $font-family-open-sans;
|
||||
}
|
||||
font-family: $font-family-source-sans;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.bs-docs-section{
|
||||
|
@ -177,7 +181,7 @@ body.layout-intro{
|
|||
|
||||
p, li, .alert {
|
||||
font-size: 20px;
|
||||
font-family: $font-family-open-sans;
|
||||
font-family: $font-family-source-sans;
|
||||
font-weight: $font-weight-open;
|
||||
line-height: 1.5em;
|
||||
margin: 0 0 18px;
|
||||
|
@ -253,4 +257,3 @@ body.layout-intro{
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,8 +19,3 @@
|
|||
font-family: $font-family-museo;
|
||||
font-weight: $font-weight-museo-xb;
|
||||
}
|
||||
|
||||
.os{
|
||||
font-family: $font-family-open-sans;
|
||||
font-weight: $font-weight-open;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
#footer{
|
||||
padding: 64px 0;
|
||||
background-color: $black;
|
||||
|
||||
.hashicorp-project{
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.pull-right{
|
||||
padding-right: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.edit-page-link{
|
||||
position: absolute;
|
||||
top: -110px;
|
||||
right: 30px;
|
||||
z-index: 9999;
|
||||
|
||||
a{
|
||||
text-transform: uppercase;
|
||||
color: $black;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
#footer{
|
||||
text-align: center;
|
||||
|
||||
.footer-hashi {
|
||||
float: none !important;
|
||||
display: block;
|
||||
|
||||
.pull-right{
|
||||
float: none !important;
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
ul{
|
||||
float: none;
|
||||
display: inline-block;
|
||||
margin-bottom: 36px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 414px) {
|
||||
#footer{
|
||||
ul{
|
||||
display: block;
|
||||
li{
|
||||
display: block;
|
||||
float: none;
|
||||
}
|
||||
|
||||
&.external-links{
|
||||
li{
|
||||
svg{
|
||||
position: relative;
|
||||
left: 0;
|
||||
top: 2px;
|
||||
margin-top: 0;
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,8 +3,8 @@
|
|||
// --------------------------------------------------
|
||||
|
||||
/*html{
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}*/
|
||||
|
||||
body {
|
||||
|
@ -81,3 +81,10 @@ pre {
|
|||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.edit-this-page{
|
||||
padding-top: 48px;
|
||||
a{
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,322 +1,77 @@
|
|||
//
|
||||
// Header
|
||||
// - Project Specific
|
||||
// - edits should be made here
|
||||
// --------------------------------------------------
|
||||
|
||||
body.page-sub{
|
||||
#header{
|
||||
@include consul-gradient-bg();
|
||||
|
||||
.navbar-brand {
|
||||
.logo{
|
||||
&:hover{
|
||||
color: $black;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#footer,
|
||||
#header {
|
||||
@include anti-alias();
|
||||
position: relative;
|
||||
color: $white;
|
||||
text-rendering: optimizeLegibility;
|
||||
margin-bottom: 0;
|
||||
|
||||
.navbar-collapse{
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&.navbar-static-top{
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
a{
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.navbar-toggle{
|
||||
margin-top: 14px;
|
||||
margin-bottom: 14px;
|
||||
border: 2px solid $white;
|
||||
.icon-bar{
|
||||
border: 1px solid $white;
|
||||
}
|
||||
}
|
||||
|
||||
.brand {
|
||||
padding: 13px 15px;
|
||||
line-height: 0;
|
||||
|
||||
.navbar-brand {
|
||||
.logo{
|
||||
display: block;
|
||||
width: 179px;
|
||||
height: 59px;
|
||||
background: image-url('consul-header-logo.png') 0 0 no-repeat;
|
||||
@include img-retina("consul-header-logo.png", "consul-header-logo@2x.png", 179px, 59px);
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-nav{
|
||||
-webkit-font-smoothing: antialiased;
|
||||
li{
|
||||
position: relative;
|
||||
|
||||
> a {
|
||||
font-size: 12px;
|
||||
padding-left: 50px;
|
||||
font-size: 0;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 3px;
|
||||
padding-left: 22px;
|
||||
background: image-url('../images/consul-hero-logo.png') 0 0 no-repeat;
|
||||
@include img-retina("../images/consul-hero-logo.png", "../images/consul-hero-logo@2x.png", $project-logo-width, $project-logo-height);
|
||||
background-position: 0 center;
|
||||
|
||||
&:hover{
|
||||
opacity: .4;
|
||||
}
|
||||
}
|
||||
|
||||
&.first{
|
||||
>a{
|
||||
padding-left: 15px;
|
||||
.by-hashicorp{
|
||||
&:hover{
|
||||
svg{
|
||||
.svg-bg-line{
|
||||
opacity: .4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nav.li-under a::after {
|
||||
|
||||
}
|
||||
|
||||
.nav > li > a:hover, .nav > li > a:focus {
|
||||
background-color: transparent;
|
||||
/*color: $p;
|
||||
@include transition( color 0.3s ease );*/
|
||||
}
|
||||
|
||||
.main-links.navbar-nav{
|
||||
li + li::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 35px;
|
||||
width: 4px;
|
||||
height: 23px;
|
||||
background: image-url('nav-dotpipes.png') 0 0 no-repeat;
|
||||
@include img-retina("nav-dotpipes.png", "nav-dotpipes@2x.png", 4px, 23px);
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
/*li + li.li-under a::after{
|
||||
left: 15px;
|
||||
}*/
|
||||
|
||||
li > a {
|
||||
line-height: 62px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.buttons.navbar-nav{
|
||||
margin-top: 26px;
|
||||
margin-left: 30px;
|
||||
|
||||
li{
|
||||
&.first{
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
&.download{
|
||||
a{
|
||||
background: image-url('icon-download.png') 8px 6px no-repeat;
|
||||
@include img-retina("icon-download.png", "icon-download@2x.png", 20px, 20px);
|
||||
}
|
||||
}
|
||||
|
||||
&.github{
|
||||
a{
|
||||
background: image-url('icon-github.png') 8px 6px no-repeat;
|
||||
@include img-retina("icon-github.png", "icon-github@2x.png", 20px, 20px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
li > a {
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
padding-left: 40px;
|
||||
}
|
||||
.buttons{
|
||||
margin-top: 2px; //baseline everything
|
||||
}
|
||||
}
|
||||
|
||||
#footer{
|
||||
height: 650px;
|
||||
text-align: center;
|
||||
color: $purple;
|
||||
|
||||
.main-links.navbar-nav{
|
||||
float: none;
|
||||
display: inline-block;
|
||||
padding-top: 155px;
|
||||
|
||||
.li-under a::after {
|
||||
background-color: $purple;
|
||||
}
|
||||
}
|
||||
|
||||
.footer-hashi{
|
||||
padding-top: 110px;
|
||||
}
|
||||
|
||||
a{
|
||||
color: $purple;
|
||||
}
|
||||
|
||||
.buttons.navbar-nav{
|
||||
float: none;
|
||||
display: inline-block;
|
||||
margin-bottom: 30px;
|
||||
margin-top: 0px;
|
||||
|
||||
li{
|
||||
&.first{
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
&.download{
|
||||
a{
|
||||
background: image-url('icon-download-purple.png') 8px 6px no-repeat;
|
||||
@include img-retina("icon-download-purple.png", "icon-download-purple@2x.png", 20px, 20px);
|
||||
}
|
||||
}
|
||||
|
||||
&.github{
|
||||
a{
|
||||
background: image-url('icon-github-purple.png') 8px 6px no-repeat;
|
||||
@include img-retina("icon-github-purple.png", "icon-github-purple@2x.png", 20px, 20px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
li > a {
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
padding-left: 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 992px) {
|
||||
@media (max-width: 414px) {
|
||||
#header {
|
||||
.brand {
|
||||
.navbar-brand {
|
||||
.logo{
|
||||
width: 120px;
|
||||
height: 39px;
|
||||
margin-top: 12px;
|
||||
background-size: 120px 39px;
|
||||
}
|
||||
}
|
||||
padding-left: 37px;
|
||||
@include img-retina("../images/consul-hero-logo.png", "../images/consul-hero-logo@2x.png", $project-logo-width * .75, $project-logo-height * .75);
|
||||
|
||||
.buttons.navbar-nav{
|
||||
li{
|
||||
a{
|
||||
background: none !important;
|
||||
padding-left: 15px;
|
||||
img{
|
||||
width: 72px;
|
||||
height: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
|
||||
#footer,
|
||||
#header{
|
||||
.buttons.navbar-nav,
|
||||
.main-links.navbar-nav{
|
||||
display: block;
|
||||
padding-bottom: 15px;
|
||||
li{
|
||||
display: block;
|
||||
float: none;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.li-under a::after,
|
||||
li + li::before {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#header,
|
||||
#footer{
|
||||
.main-links.navbar-nav{
|
||||
li > a {
|
||||
padding: 0;
|
||||
padding-left: 0;
|
||||
line-height: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#footer{
|
||||
.footer-hashi {
|
||||
span{
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.hashi-logo{
|
||||
display: block;
|
||||
margin-top: 15px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.buttons.navbar-nav{
|
||||
margin-left: 0;
|
||||
|
||||
li.first {
|
||||
margin-right: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#header{
|
||||
@include consul-gradient-bg();
|
||||
|
||||
.navbar-right{
|
||||
float: none !important;
|
||||
}
|
||||
|
||||
.brand {
|
||||
@media (max-width: 320px) {
|
||||
#header {
|
||||
.navbar-brand {
|
||||
.logo{
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-nav > li{
|
||||
float: none;
|
||||
}
|
||||
|
||||
.buttons.navbar-nav{
|
||||
margin-top: 15px;
|
||||
margin-left: 0px;
|
||||
|
||||
li{
|
||||
a{
|
||||
padding-left: 40px;
|
||||
}
|
||||
&.first{
|
||||
margin-right: 0;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
&.download{
|
||||
a{
|
||||
background: image-url('icon-download.png') 8px 6px no-repeat !important;;
|
||||
@include img-retina("icon-download.png", "icon-download@2x.png", 20px, 20px);
|
||||
}
|
||||
}
|
||||
|
||||
&.github{
|
||||
a{
|
||||
background: image-url('icon-github.png') 8px 6px no-repeat !important;;
|
||||
@include img-retina("icon-github.png", "icon-github@2x.png", 20px, 20px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
|
||||
}
|
||||
|
|
|
@ -127,37 +127,6 @@ body.page-home{
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#footer{
|
||||
background-color: $consul-footer-gray;
|
||||
background: $consul-footer-gray image-url('consul-footer-logo.png') center center no-repeat;
|
||||
@include img-retina("consul-footer-logo.png", "consul-footer-logo@2x.png", 446px, 443px);
|
||||
|
||||
.footer-links{
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.footer-hashi{
|
||||
letter-spacing: 2px;
|
||||
margin-bottom: 30px;
|
||||
|
||||
a{
|
||||
font-weight: $font-weight-museo-xb;
|
||||
}
|
||||
|
||||
span{
|
||||
margin-right: 20px;
|
||||
}
|
||||
img{
|
||||
display: inline-block;
|
||||
width: 37px;
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 992px) {
|
||||
#features{
|
||||
top: $large-negative-hero-margin;
|
||||
|
@ -174,6 +143,17 @@ body.page-home{
|
|||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px){
|
||||
#cta{
|
||||
text-align: center;
|
||||
.intro{
|
||||
.left{
|
||||
text-align: center !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
#features{
|
||||
text-align: center;
|
||||
|
@ -236,7 +216,6 @@ body.page-home{
|
|||
|
||||
h2 {
|
||||
font-size: 22px;
|
||||
color: lighten($gray-light, 15%);
|
||||
text-transform: uppercase;
|
||||
font-family: $font-family-museo;
|
||||
font-weight: $font-weight-museo-xb;
|
||||
|
|
|
@ -1,724 +0,0 @@
|
|||
//
|
||||
// Mixins
|
||||
// --------------------------------------------------
|
||||
|
||||
|
||||
// Utilities
|
||||
// -------------------------
|
||||
|
||||
// Clearfix
|
||||
// Source: http://nicolasgallagher.com/micro-clearfix-hack/
|
||||
//
|
||||
// For modern browsers
|
||||
// 1. The space content is one way to avoid an Opera bug when the
|
||||
// contenteditable attribute is included anywhere else in the document.
|
||||
// Otherwise it causes space to appear at the top and bottom of elements
|
||||
// that are clearfixed.
|
||||
// 2. The use of `table` rather than `block` is only necessary if using
|
||||
// `:before` to contain the top-margins of child elements.
|
||||
@mixin clearfix() {
|
||||
&:before,
|
||||
&:after {
|
||||
content: " "; /* 1 */
|
||||
display: table; /* 2 */
|
||||
}
|
||||
&:after {
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
|
||||
// Webkit-style focus
|
||||
@mixin tab-focus() {
|
||||
// Default
|
||||
outline: thin dotted #333;
|
||||
// Webkit
|
||||
outline: 5px auto -webkit-focus-ring-color;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
// Center-align a block level element
|
||||
@mixin center-block() {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
// Sizing shortcuts
|
||||
@mixin size($width, $height) {
|
||||
width: $width;
|
||||
height: $height;
|
||||
}
|
||||
@mixin square($size) {
|
||||
@include size($size, $size);
|
||||
}
|
||||
|
||||
// Placeholder text
|
||||
@mixin placeholder($color: $input-color-placeholder) {
|
||||
&:-moz-placeholder { color: $color; } // Firefox 4-18
|
||||
&::-moz-placeholder { color: $color; } // Firefox 19+
|
||||
&:-ms-input-placeholder { color: $color; } // Internet Explorer 10+
|
||||
&::-webkit-input-placeholder { color: $color; } // Safari and Chrome
|
||||
}
|
||||
|
||||
// Text overflow
|
||||
// Requires inline-block or block for proper styling
|
||||
@mixin text-overflow() {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
// CSS image replacement
|
||||
// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757
|
||||
@mixin hide-text() {
|
||||
font: #{"0/0"} a;
|
||||
color: transparent;
|
||||
text-shadow: none;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// CSS3 PROPERTIES
|
||||
// --------------------------------------------------
|
||||
|
||||
// Single side border-radius
|
||||
@mixin border-top-radius($radius) {
|
||||
border-top-right-radius: $radius;
|
||||
border-top-left-radius: $radius;
|
||||
}
|
||||
@mixin border-right-radius($radius) {
|
||||
border-bottom-right-radius: $radius;
|
||||
border-top-right-radius: $radius;
|
||||
}
|
||||
@mixin border-bottom-radius($radius) {
|
||||
border-bottom-right-radius: $radius;
|
||||
border-bottom-left-radius: $radius;
|
||||
}
|
||||
@mixin border-left-radius($radius) {
|
||||
border-bottom-left-radius: $radius;
|
||||
border-top-left-radius: $radius;
|
||||
}
|
||||
|
||||
// Drop shadows
|
||||
@mixin box-shadow($shadow) {
|
||||
-webkit-box-shadow: $shadow; // iOS <4.3 & Android <4.1
|
||||
box-shadow: $shadow;
|
||||
}
|
||||
|
||||
// Transitions
|
||||
@mixin transition($transition) {
|
||||
-webkit-transition: $transition;
|
||||
transition: $transition;
|
||||
}
|
||||
@mixin transition-delay($transition-delay) {
|
||||
-webkit-transition-delay: $transition-delay;
|
||||
transition-delay: $transition-delay;
|
||||
}
|
||||
@mixin transition-duration($transition-duration) {
|
||||
-webkit-transition-duration: $transition-duration;
|
||||
transition-duration: $transition-duration;
|
||||
}
|
||||
@mixin transition-transform($transition) {
|
||||
-webkit-transition: -webkit-transform $transition;
|
||||
-moz-transition: -moz-transform $transition;
|
||||
-o-transition: -o-transform $transition;
|
||||
transition: transform $transition;
|
||||
}
|
||||
|
||||
// Transformations
|
||||
@mixin rotate($degrees) {
|
||||
-webkit-transform: rotate($degrees);
|
||||
-ms-transform: rotate($degrees); // IE9+
|
||||
transform: rotate($degrees);
|
||||
}
|
||||
@mixin scale($ratio) {
|
||||
-webkit-transform: scale($ratio);
|
||||
-ms-transform: scale($ratio); // IE9+
|
||||
transform: scale($ratio);
|
||||
}
|
||||
@mixin translate($x, $y) {
|
||||
-webkit-transform: translate($x, $y);
|
||||
-ms-transform: translate($x, $y); // IE9+
|
||||
transform: translate($x, $y);
|
||||
}
|
||||
@mixin skew($x, $y) {
|
||||
-webkit-transform: skew($x, $y);
|
||||
-ms-transform: skewX($x) skewY($y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+
|
||||
transform: skew($x, $y);
|
||||
}
|
||||
@mixin translate3d($x, $y, $z) {
|
||||
-webkit-transform: translate3d($x, $y, $z);
|
||||
transform: translate3d($x, $y, $z);
|
||||
}
|
||||
|
||||
// Backface visibility
|
||||
// Prevent browsers from flickering when using CSS 3D transforms.
|
||||
// Default value is `visible`, but can be changed to `hidden`
|
||||
// See git pull https://github.com/dannykeane/bootstrap.git backface-visibility for examples
|
||||
@mixin backface-visibility($visibility) {
|
||||
-webkit-backface-visibility: $visibility;
|
||||
-moz-backface-visibility: $visibility;
|
||||
backface-visibility: $visibility;
|
||||
}
|
||||
|
||||
// Box sizing
|
||||
@mixin box-sizing($boxmodel) {
|
||||
-webkit-box-sizing: $boxmodel;
|
||||
-moz-box-sizing: $boxmodel;
|
||||
box-sizing: $boxmodel;
|
||||
}
|
||||
|
||||
// User select
|
||||
// For selecting text on the page
|
||||
@mixin user-select($select) {
|
||||
-webkit-user-select: $select;
|
||||
-moz-user-select: $select;
|
||||
-ms-user-select: $select; // IE10+
|
||||
-o-user-select: $select;
|
||||
user-select: $select;
|
||||
}
|
||||
|
||||
// Resize anything
|
||||
@mixin resizable($direction) {
|
||||
resize: $direction; // Options: horizontal, vertical, both
|
||||
overflow: auto; // Safari fix
|
||||
}
|
||||
|
||||
// CSS3 Content Columns
|
||||
@mixin content-columns($column-count, $column-gap: $grid-gutter-width) {
|
||||
-webkit-column-count: $column-count;
|
||||
-moz-column-count: $column-count;
|
||||
column-count: $column-count;
|
||||
-webkit-column-gap: $column-gap;
|
||||
-moz-column-gap: $column-gap;
|
||||
column-gap: $column-gap;
|
||||
}
|
||||
|
||||
// Optional hyphenation
|
||||
@mixin hyphens($mode: auto) {
|
||||
word-wrap: break-word;
|
||||
-webkit-hyphens: $mode;
|
||||
-moz-hyphens: $mode;
|
||||
-ms-hyphens: $mode; // IE10+
|
||||
-o-hyphens: $mode;
|
||||
hyphens: $mode;
|
||||
}
|
||||
|
||||
// Opacity
|
||||
@mixin opacity($opacity) {
|
||||
opacity: $opacity;
|
||||
// IE8 filter
|
||||
$opacity-ie: ($opacity * 100);
|
||||
filter: #{"alpha(opacity=${opacity-ie})"};
|
||||
}
|
||||
|
||||
|
||||
|
||||
// GRADIENTS
|
||||
// --------------------------------------------------
|
||||
|
||||
#gradient {
|
||||
|
||||
// Horizontal gradient, from left to right
|
||||
//
|
||||
// Creates two color stops, start and end, by specifying a color and position for each color stop.
|
||||
// Color stops are not available in IE9 and below.
|
||||
@mixin horizontal($start-color: #555, $end-color: #333, $start-percent: 0%, $end-percent: 100%) {
|
||||
background-image: -webkit-gradient(linear, $start-percent top, $end-percent top, from($start-color), to($end-color)); // Safari 4+, Chrome 2+
|
||||
background-image: -webkit-linear-gradient(left, color-stop($start-color $start-percent), color-stop($end-color $end-percent)); // Safari 5.1+, Chrome 10+
|
||||
background-image: -moz-linear-gradient(left, $start-color $start-percent, $end-color $end-percent); // FF 3.6+
|
||||
background-image: linear-gradient(to right, $start-color $start-percent, $end-color $end-percent); // Standard, IE10
|
||||
background-repeat: repeat-x;
|
||||
// filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)",argb($start-color),argb($end-color))); // IE9 and down
|
||||
}
|
||||
|
||||
// Vertical gradient, from top to bottom
|
||||
//
|
||||
// Creates two color stops, start and end, by specifying a color and position for each color stop.
|
||||
// Color stops are not available in IE9 and below.
|
||||
@mixin vertical($start-color: #555, $end-color: #333, $start-percent: 0%, $end-percent: 100%) {
|
||||
background-image: -webkit-gradient(linear, left $start-percent, left $end-percent, from($start-color), to($end-color)); // Safari 4+, Chrome 2+
|
||||
background-image: -webkit-linear-gradient(top, $start-color, $start-percent, $end-color, $end-percent); // Safari 5.1+, Chrome 10+
|
||||
background-image: -moz-linear-gradient(top, $start-color $start-percent, $end-color $end-percent); // FF 3.6+
|
||||
background-image: linear-gradient(to bottom, $start-color $start-percent, $end-color $end-percent); // Standard, IE10
|
||||
background-repeat: repeat-x;
|
||||
// filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb($start-color),argb($end-color))); // IE9 and down
|
||||
}
|
||||
|
||||
@mixin directional($start-color: #555, $end-color: #333, $deg: 45deg) {
|
||||
background-repeat: repeat-x;
|
||||
background-image: -webkit-linear-gradient($deg, $start-color, $end-color); // Safari 5.1+, Chrome 10+
|
||||
background-image: -moz-linear-gradient($deg, $start-color, $end-color); // FF 3.6+
|
||||
background-image: linear-gradient($deg, $start-color, $end-color); // Standard, IE10
|
||||
}
|
||||
@mixin horizontal-three-colors($start-color: #00b3ee, $mid-color: #7a43b6, $color-stop: 50%, $end-color: #c3325f) {
|
||||
background-image: -webkit-gradient(left, linear, 0 0, 0 100%, from($start-color), color-stop($color-stop, $mid-color), to($end-color));
|
||||
background-image: -webkit-linear-gradient(left, $start-color, $mid-color $color-stop, $end-color);
|
||||
background-image: -moz-linear-gradient(left, $start-color, $mid-color $color-stop, $end-color);
|
||||
background-image: linear-gradient(to right, $start-color, $mid-color $color-stop, $end-color);
|
||||
background-repeat: no-repeat;
|
||||
// filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)",argb($start-color),argb($end-color))); // IE9 and down, gets no color-stop at all for proper fallback
|
||||
}
|
||||
@mixin vertical-three-colors($start-color: #00b3ee, $mid-color: #7a43b6, $color-stop: 50%, $end-color: #c3325f) {
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from($start-color), color-stop($color-stop, $mid-color), to($end-color));
|
||||
background-image: -webkit-linear-gradient($start-color, $mid-color $color-stop, $end-color);
|
||||
background-image: -moz-linear-gradient(top, $start-color, $mid-color $color-stop, $end-color);
|
||||
background-image: linear-gradient($start-color, $mid-color $color-stop, $end-color);
|
||||
background-repeat: no-repeat;
|
||||
// filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb($start-color),argb($end-color))); // IE9 and down, gets no color-stop at all for proper fallback
|
||||
}
|
||||
@mixin radial($inner-color: #555, $outer-color: #333) {
|
||||
background-image: -webkit-gradient(radial, center center, 0, center center, 460, from($inner-color), to($outer-color));
|
||||
background-image: -webkit-radial-gradient(circle, $inner-color, $outer-color);
|
||||
background-image: -moz-radial-gradient(circle, $inner-color, $outer-color);
|
||||
background-image: radial-gradient(circle, $inner-color, $outer-color);
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
@mixin striped($color: #555, $angle: 45deg) {
|
||||
background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,.15)), color-stop(.75, rgba(255,255,255,.15)), color-stop(.75, transparent), to(transparent));
|
||||
background-image: -webkit-linear-gradient($angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent);
|
||||
background-image: -moz-linear-gradient($angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent);
|
||||
background-image: linear-gradient($angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent);
|
||||
}
|
||||
}
|
||||
|
||||
// Reset filters for IE
|
||||
//
|
||||
// When you need to remove a gradient background, do not forget to use this to reset
|
||||
// the IE filter for IE9 and below.
|
||||
@mixin reset-filter() {
|
||||
// filter: e(%("progid:DXImageTransform.Microsoft.gradient(enabled = false)"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Retina images
|
||||
//
|
||||
// Short retina mixin for setting background-image and -size
|
||||
|
||||
@mixin img-retina($file-1x, $file-2x, $width-1x, $height-1x) {
|
||||
background-image: image-url("#{$file-1x}");
|
||||
background-size: $width-1x $height-1x;
|
||||
|
||||
@media
|
||||
only screen and (-webkit-min-device-pixel-ratio: 2),
|
||||
only screen and ( min--moz-device-pixel-ratio: 2),
|
||||
only screen and ( -o-min-device-pixel-ratio: 2/1),
|
||||
only screen and ( min-device-pixel-ratio: 2),
|
||||
only screen and ( min-resolution: 192dpi),
|
||||
only screen and ( min-resolution: 2dppx) {
|
||||
background-image: image-url("#{$file-2x}");
|
||||
background-size: $width-1x $height-1x;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Responsive image
|
||||
//
|
||||
// Keep images from scaling beyond the width of their parents.
|
||||
|
||||
@mixin img-responsive($display: block) {
|
||||
display: $display;
|
||||
max-width: 100%; // Part 1: Set a maximum relative to the parent
|
||||
height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching
|
||||
}
|
||||
|
||||
|
||||
// COMPONENT MIXINS
|
||||
// --------------------------------------------------
|
||||
|
||||
// Horizontal dividers
|
||||
// -------------------------
|
||||
// Dividers (basically an hr) within dropdowns and nav lists
|
||||
@mixin nav-divider($color: #e5e5e5) {
|
||||
height: 1px;
|
||||
margin: (($line-height-computed / 2) - 1) 0;
|
||||
overflow: hidden;
|
||||
background-color: $color;
|
||||
}
|
||||
|
||||
// Panels
|
||||
// -------------------------
|
||||
@mixin panel-variant($border, $heading-text-color, $heading-bg-color, $heading-border) {
|
||||
border-color: $border;
|
||||
& > .panel-heading {
|
||||
color: $heading-text-color;
|
||||
background-color: $heading-bg-color;
|
||||
border-color: $heading-border;
|
||||
+ .panel-collapse .panel-body {
|
||||
border-top-color: $border;
|
||||
}
|
||||
}
|
||||
& > .panel-footer {
|
||||
+ .panel-collapse .panel-body {
|
||||
border-bottom-color: $border;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Alerts
|
||||
// -------------------------
|
||||
@mixin alert-variant($background, $border, $text-color) {
|
||||
background-color: $background;
|
||||
border-color: $border;
|
||||
color: $text-color;
|
||||
hr {
|
||||
border-top-color: darken($border, 5%);
|
||||
}
|
||||
.alert-link {
|
||||
color: darken($text-color, 10%);
|
||||
}
|
||||
}
|
||||
|
||||
// Tables
|
||||
// -------------------------
|
||||
@mixin table-row-variant($state, $background, $border) {
|
||||
// Exact selectors below required to override `.table-striped` and prevent
|
||||
// inheritance to nested tables.
|
||||
.table > thead > tr,
|
||||
.table > tbody > tr,
|
||||
.table > tfoot > tr {
|
||||
> td.#{state},
|
||||
> th.#{state},
|
||||
&.#{state} > td,
|
||||
&.#{state} > th {
|
||||
background-color: $background;
|
||||
border-color: $border;
|
||||
}
|
||||
}
|
||||
|
||||
// Hove# states for `.table-hover`
|
||||
// Note: this is not available for cells or rows within `thead` or `tfoot`.
|
||||
.table-hover > tbody > tr {
|
||||
> td.#{state}:hover,
|
||||
> th.#{state}:hover,
|
||||
&.#{state}:hover > td {
|
||||
background-color: darken($background, 5%);
|
||||
border-color: darken($border, 5%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Button variants
|
||||
// -------------------------
|
||||
// Easily pump out default styles, as well as :hover, :focus, :active,
|
||||
// and disabled options for all buttons
|
||||
@mixin button-variant($color, $background, $border) {
|
||||
color: $color;
|
||||
background-color: $background;
|
||||
border-color: $border;
|
||||
|
||||
&:hover,
|
||||
&:focus,
|
||||
&:active,
|
||||
&.active,
|
||||
.open .dropdown-toggle& {
|
||||
color: $color;
|
||||
background-color: darken($background, 8%);
|
||||
border-color: darken($border, 12%);
|
||||
}
|
||||
&:active,
|
||||
&.active,
|
||||
.open .dropdown-toggle& {
|
||||
background-image: none;
|
||||
}
|
||||
&.disabled,
|
||||
&[disabled],
|
||||
fieldset[disabled] & {
|
||||
&,
|
||||
&:hover,
|
||||
&:focus,
|
||||
&:active,
|
||||
&.active {
|
||||
background-color: $background;
|
||||
border-color: $border
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Button sizes
|
||||
// -------------------------
|
||||
@mixin button-size($padding-vertical, $padding-horizontal, $font-size, $line-height, $border-radius) {
|
||||
padding: $padding-vertical $padding-horizontal;
|
||||
font-size: $font-size;
|
||||
line-height: $line-height;
|
||||
border-radius: $border-radius;
|
||||
}
|
||||
|
||||
// Pagination
|
||||
// -------------------------
|
||||
@mixin pagination-size($padding-vertical, $padding-horizontal, $font-size, $border-radius) {
|
||||
> li {
|
||||
> a,
|
||||
> span {
|
||||
padding: $padding-vertical $padding-horizontal;
|
||||
font-size: $font-size;
|
||||
}
|
||||
&:first-child {
|
||||
> a,
|
||||
> span {
|
||||
@include border-left-radius($border-radius);
|
||||
}
|
||||
}
|
||||
&:last-child {
|
||||
> a,
|
||||
> span {
|
||||
@include border-right-radius($border-radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Labels
|
||||
// -------------------------
|
||||
@mixin label-variant($color) {
|
||||
background-color: $color;
|
||||
&[href] {
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: darken($color, 10%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Navbar vertical align
|
||||
// -------------------------
|
||||
// Vertically center elements in the navbar.
|
||||
// Example: an element has a height of 30px, so write out `@include navbar-vertical-align(30px);` to calculate the appropriate top margin.
|
||||
@mixin navbar-vertical-align($element-height) {
|
||||
margin-top: (($navbar-height - $element-height) / 2);
|
||||
margin-bottom: (($navbar-height - $element-height) / 2);
|
||||
}
|
||||
|
||||
// Progress bars
|
||||
// -------------------------
|
||||
// @mixin progress-bar-variant($color) {
|
||||
// background-color: $color;
|
||||
// .progress-striped & {
|
||||
// #gradient > @include striped($color);
|
||||
// }
|
||||
// }
|
||||
|
||||
// Responsive utilities
|
||||
// -------------------------
|
||||
// More easily include all the states for responsive-utilities.less.
|
||||
@mixin responsive-visibility() {
|
||||
display: block !important;
|
||||
tr& { display: table-row !important; }
|
||||
th&,
|
||||
td& { display: table-cell !important; }
|
||||
}
|
||||
|
||||
@mixin responsive-invisibility() {
|
||||
display: none !important;
|
||||
tr& { display: none !important; }
|
||||
th&,
|
||||
td& { display: none !important; }
|
||||
}
|
||||
|
||||
// Grid System
|
||||
// -----------
|
||||
|
||||
// Centered container element
|
||||
@mixin container-fixed() {
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
padding-left: ($grid-gutter-width / 2);
|
||||
padding-right: ($grid-gutter-width / 2);
|
||||
@include clearfix();
|
||||
}
|
||||
|
||||
// Creates a wrapper for a series of columns
|
||||
@mixin make-row($gutter: $grid-gutter-width) {
|
||||
margin-left: ($gutter / -2);
|
||||
margin-right: ($gutter / -2);
|
||||
@include clearfix();
|
||||
}
|
||||
|
||||
// Generate the extra small columns
|
||||
@mixin make-xs-column($columns, $gutter: $grid-gutter-width) {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: percentage(($columns / $grid-columns));
|
||||
// Prevent columns from collapsing when empty
|
||||
min-height: 1px;
|
||||
// Inner gutter via padding
|
||||
padding-left: ($gutter / 2);
|
||||
padding-right: ($gutter / 2);
|
||||
}
|
||||
|
||||
// Generate the small columns
|
||||
@mixin make-sm-column($columns, $gutter: $grid-gutter-width) {
|
||||
position: relative;
|
||||
// Prevent columns from collapsing when empty
|
||||
min-height: 1px;
|
||||
// Inner gutter via padding
|
||||
padding-left: ($gutter / 2);
|
||||
padding-right: ($gutter / 2);
|
||||
|
||||
// Calculate width based on number of columns available
|
||||
@media (min-width: $screen-sm) {
|
||||
float: left;
|
||||
width: percentage(($columns / $grid-columns));
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the small column offsets
|
||||
@mixin make-sm-column-offset($columns) {
|
||||
@media (min-width: $screen-sm) {
|
||||
margin-left: percentage(($columns / $grid-columns));
|
||||
}
|
||||
}
|
||||
@mixin make-sm-column-push($columns) {
|
||||
@media (min-width: $screen-sm) {
|
||||
left: percentage(($columns / $grid-columns));
|
||||
}
|
||||
}
|
||||
@mixin make-sm-column-pull($columns) {
|
||||
@media (min-width: $screen-sm) {
|
||||
right: percentage(($columns / $grid-columns));
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the medium columns
|
||||
@mixin make-md-column($columns, $gutter: $grid-gutter-width) {
|
||||
position: relative;
|
||||
// Prevent columns from collapsing when empty
|
||||
min-height: 1px;
|
||||
// Inner gutter via padding
|
||||
padding-left: ($gutter / 2);
|
||||
padding-right: ($gutter / 2);
|
||||
|
||||
// Calculate width based on number of columns available
|
||||
@media (min-width: $screen-md) {
|
||||
float: left;
|
||||
width: percentage(($columns / $grid-columns));
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the large column offsets
|
||||
@mixin make-md-column-offset($columns) {
|
||||
@media (min-width: $screen-md) {
|
||||
margin-left: percentage(($columns / $grid-columns));
|
||||
}
|
||||
}
|
||||
@mixin make-md-column-push($columns) {
|
||||
@media (min-width: $screen-md) {
|
||||
left: percentage(($columns / $grid-columns));
|
||||
}
|
||||
}
|
||||
@mixin make-md-column-pull($columns) {
|
||||
@media (min-width: $screen-md) {
|
||||
right: percentage(($columns / $grid-columns));
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the large columns
|
||||
@mixin make-lg-column($columns, $gutter: $grid-gutter-width) {
|
||||
position: relative;
|
||||
// Prevent columns from collapsing when empty
|
||||
min-height: 1px;
|
||||
// Inner gutter via padding
|
||||
padding-left: ($gutter / 2);
|
||||
padding-right: ($gutter / 2);
|
||||
|
||||
// Calculate width based on number of columns available
|
||||
@media (min-width: $screen-lg) {
|
||||
float: left;
|
||||
width: percentage(($columns / $grid-columns));
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the large column offsets
|
||||
@mixin make-lg-column-offset($columns) {
|
||||
@media (min-width: $screen-lg) {
|
||||
margin-left: percentage(($columns / $grid-columns));
|
||||
}
|
||||
}
|
||||
@mixin make-lg-column-push($columns) {
|
||||
@media (min-width: $screen-lg) {
|
||||
left: percentage(($columns / $grid-columns));
|
||||
}
|
||||
}
|
||||
@mixin make-lg-column-pull($columns) {
|
||||
@media (min-width: $screen-lg) {
|
||||
right: percentage(($columns / $grid-columns));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Form validation states
|
||||
//
|
||||
// Used in forms.less to generate the form validation CSS for warnings, errors,
|
||||
// and successes.
|
||||
|
||||
@mixin form-control-validation($text-color: #555, $border-color: #ccc, $background-color: #f5f5f5) {
|
||||
// Color the label and help text
|
||||
.help-block,
|
||||
.control-label {
|
||||
color: $text-color;
|
||||
}
|
||||
// Set the border and box shadow on specific inputs to match
|
||||
.form-control {
|
||||
border-color: $border-color;
|
||||
@include box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work
|
||||
&:focus {
|
||||
border-color: darken($border-color, 10%);
|
||||
$shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten($border-color, 20%);
|
||||
@include box-shadow($shadow);
|
||||
}
|
||||
}
|
||||
// Set validation states also for addons
|
||||
.input-group-addon {
|
||||
color: $text-color;
|
||||
border-color: $border-color;
|
||||
background-color: $background-color;
|
||||
}
|
||||
}
|
||||
|
||||
// Form control focus state
|
||||
//
|
||||
// Generate a customized focus state and for any input with the specified color,
|
||||
// which defaults to the `$input-focus-border` variable.
|
||||
//
|
||||
// We highly encourage you to not customize the default value, but instead use
|
||||
// this to tweak colors on an as-needed basis. This aesthetic change is based on
|
||||
// WebKit's default styles, but applicable to a wider range of browsers. Its
|
||||
// usability and accessibility should be taken into account with any change.
|
||||
//
|
||||
// Example usage: change the default blue border and shadow to white for better
|
||||
// contrast against a dark gray background.
|
||||
|
||||
@mixin form-control-focus($color: $input-border-focus) {
|
||||
$color-rgba: rgba(red($color), green($color), blue($color), .6);
|
||||
&:focus {
|
||||
border-color: $color;
|
||||
outline: 0;
|
||||
@include box-shadow(#{"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px ${color-rgba}"});
|
||||
}
|
||||
}
|
||||
|
||||
// Form control sizing
|
||||
//
|
||||
// Relative text size, padding, and border-radii changes for form controls. For
|
||||
// horizontal sizing, wrap controls in the predefined grid classes. `<select>`
|
||||
// element gets special love because it's special, and that's a fact!
|
||||
|
||||
@mixin input-size($input-height, $padding-vertical, $padding-horizontal, $font-size, $line-height, $border-radius) {
|
||||
height: $input-height;
|
||||
padding: $padding-vertical $padding-horizontal;
|
||||
font-size: $font-size;
|
||||
line-height: $line-height;
|
||||
border-radius: $border-radius;
|
||||
|
||||
select& {
|
||||
height: $input-height;
|
||||
line-height: $input-height;
|
||||
}
|
||||
|
||||
textarea& {
|
||||
height: auto;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// Sidebar
|
||||
// - Project Specific
|
||||
// - Make sidebar edits here
|
||||
// --------------------------------------------------
|
||||
|
||||
.sidebar {
|
||||
.sidebar-nav {
|
||||
// Links
|
||||
//----------------
|
||||
li {
|
||||
a {
|
||||
color: $purple;
|
||||
|
||||
svg{
|
||||
path{
|
||||
fill: $purple;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,5 +20,4 @@
|
|||
background: -ms-linear-gradient(left, #694a9c 0%,#cd2028 100%); /* IE10+ */
|
||||
background: linear-gradient(to right, #694a9c 0%,#cd2028 100%); /* W3C */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#694a9c', endColorstr='#cd2028',GradientType=1 ); /* IE6-9 */
|
||||
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ $link-hover-color: darken($link-color, 15%);
|
|||
// Typography
|
||||
// -------------------------
|
||||
$font-family-museo: 'museo-sans', "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
$font-family-open-sans: 'Source Sans Pro', "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
$font-family-source-sans: 'Source Sans Pro', "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
$font-weight-museo-xl: 100;
|
||||
$font-weight-museo-reg: 300;
|
||||
$font-weight-museo-sb: 500;
|
||||
|
|
|
@ -3,11 +3,10 @@
|
|||
@import "bootstrap";
|
||||
|
||||
// Remote fonts
|
||||
@import url("//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700");
|
||||
@import url("//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700|Open+Sans:300,600");
|
||||
|
||||
// Core variables and mixins
|
||||
@import "_variables";
|
||||
@import "_mixins";
|
||||
|
||||
// Utility classes
|
||||
@import "_utilities";
|
||||
|
@ -18,10 +17,18 @@
|
|||
//Global Site
|
||||
@import "_global";
|
||||
|
||||
// Hashicorp Shared Project Styles
|
||||
@import 'hashicorp-shared/_hashicorp-utility';
|
||||
@import 'hashicorp-shared/_project-utility';
|
||||
@import 'hashicorp-shared/_hashicorp-header';
|
||||
@import 'hashicorp-shared/_hashicorp-sidebar';
|
||||
|
||||
// Components
|
||||
@import "_header";
|
||||
@import '_footer';
|
||||
@import "_jumbotron";
|
||||
@import "_buttons";
|
||||
@import '_sidebar';
|
||||
|
||||
// Pages
|
||||
@import "_home";
|
||||
|
|
|
@ -0,0 +1,323 @@
|
|||
//
|
||||
// Hashicorp header
|
||||
// - Shared throughout projects
|
||||
// - Edits should not be made here
|
||||
// --------------------------------------------------
|
||||
|
||||
#header{
|
||||
position: relative;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.navigation {
|
||||
color: black;
|
||||
text-rendering: optimizeLegibility;
|
||||
transition: all 1s ease;
|
||||
|
||||
&.white{
|
||||
.navbar-brand {
|
||||
.logo {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.main-links,
|
||||
.external-links {
|
||||
li > a {
|
||||
&:hover{
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-toggle{
|
||||
height: $header-height;
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
.icon-bar{
|
||||
border: 1px solid $black;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.external-links {
|
||||
&.white{
|
||||
svg path{
|
||||
fill: $white;
|
||||
}
|
||||
}
|
||||
|
||||
li {
|
||||
position: relative;
|
||||
|
||||
svg path{
|
||||
@include transition( all 300ms ease-in );
|
||||
}
|
||||
|
||||
&:hover{
|
||||
svg path{
|
||||
@include transition( all 300ms ease-in );
|
||||
}
|
||||
}
|
||||
|
||||
&.download{
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
> a {
|
||||
padding-left: 12px !important;
|
||||
svg{
|
||||
position: absolute;
|
||||
left: -12px;
|
||||
top: 50%;
|
||||
margin-top: -7px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.main-links{
|
||||
margin-right: $nav-margin-right * 2;
|
||||
}
|
||||
|
||||
.main-links,
|
||||
.external-links {
|
||||
&.white{
|
||||
li > a {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
li > a {
|
||||
@include hashi-a-style();
|
||||
margin: 0 10px;
|
||||
padding-top: 1px;
|
||||
line-height: $header-height;
|
||||
@include project-a-style();
|
||||
}
|
||||
}
|
||||
|
||||
.nav > li > a:hover, .nav > li > a:focus {
|
||||
background-color: transparent;
|
||||
@include transition( all 300ms ease-in );
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
display: block;
|
||||
height: $header-height;
|
||||
padding: 0;
|
||||
margin: 0 10px 0 0;
|
||||
|
||||
.logo{
|
||||
display: inline-block;
|
||||
height: $header-height;
|
||||
vertical-align:top;
|
||||
padding: 0;
|
||||
line-height: $header-height;
|
||||
padding-left: $project-logo-width + $project-logo-pad-left;
|
||||
background-position: 0 center;
|
||||
@include transition(all 300ms ease-in);
|
||||
|
||||
&:hover{
|
||||
@include transition(all 300ms ease-in);
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-toggle{
|
||||
&.white{
|
||||
.icon-bar{
|
||||
border: 1px solid white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.by-hashicorp{
|
||||
display: inline-block;
|
||||
vertical-align:top;
|
||||
height: $header-height;
|
||||
margin-left: 3px;
|
||||
padding-top: 2px;
|
||||
color: black;
|
||||
line-height: $header-height;
|
||||
font-family: $header-font-family;
|
||||
font-weight: 600;
|
||||
font-size: 0;
|
||||
text-decoration: none;
|
||||
|
||||
&.white{
|
||||
color: white;
|
||||
font-weight: 300;
|
||||
svg{
|
||||
path,
|
||||
polygon,
|
||||
rect{
|
||||
fill: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:focus,
|
||||
&:hover{
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.svg-wrap{
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
svg{
|
||||
&.svg-by{
|
||||
width: $by-hashicorp-width;
|
||||
height: $by-hashicorp-height;
|
||||
margin-bottom: -4px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
&.svg-logo{
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-bottom: -3px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
path,
|
||||
polygon{
|
||||
fill: black;
|
||||
@include transition(all 300ms ease-in);
|
||||
|
||||
&:hover{
|
||||
@include transition(all 300ms ease-in);
|
||||
}
|
||||
}
|
||||
.svg-bg-line{
|
||||
@include transition(all 300ms ease-in);
|
||||
|
||||
&:hover{
|
||||
@include transition(all 300ms ease-in);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.hashicorp-project{
|
||||
display: inline-block;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
text-decoration: none;
|
||||
font-size: 14px;
|
||||
color: $black;
|
||||
font-weight: 600;
|
||||
|
||||
&.white{
|
||||
color: white;
|
||||
svg{
|
||||
path,
|
||||
polygon,
|
||||
rect{
|
||||
fill: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:focus{
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&:hover{
|
||||
text-decoration: none;
|
||||
svg{
|
||||
&.svg-by{
|
||||
line{
|
||||
stroke: $purple;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
span{
|
||||
margin-right: 4px;
|
||||
font-family: $header-font-family;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
span,
|
||||
svg{
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
svg{
|
||||
&.svg-by{
|
||||
width: $by-hashicorp-width;
|
||||
height: $by-hashicorp-height;
|
||||
margin-bottom: -4px;
|
||||
margin-left: -3px;
|
||||
}
|
||||
|
||||
&.svg-logo{
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin-bottom: -10px;
|
||||
margin-left: -1px;
|
||||
}
|
||||
|
||||
path,
|
||||
line{
|
||||
fill: $black;
|
||||
@include transition(all 300ms ease-in);
|
||||
|
||||
&:hover{
|
||||
@include transition(all 300ms ease-in);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.navigation {
|
||||
> .container{
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.navigation {
|
||||
.main-links{
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 414px) {
|
||||
#header {
|
||||
.navbar-toggle{
|
||||
padding-top: 10px;
|
||||
height: $header-mobile-height;
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
height: $header-mobile-height;
|
||||
|
||||
.logo{
|
||||
height: $header-mobile-height;
|
||||
line-height: $header-mobile-height;
|
||||
}
|
||||
.by-hashicorp{
|
||||
height: $header-mobile-height;
|
||||
line-height: $header-mobile-height;
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
.main-links,
|
||||
.external-links {
|
||||
li > a {
|
||||
line-height: $header-mobile-height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,293 @@
|
|||
//
|
||||
// Hashicorp Sidebar
|
||||
// - Shared throughout projects
|
||||
// - Edits should not be made here
|
||||
// --------------------------------------------------
|
||||
|
||||
// Base variables
|
||||
// --------------------------------------------------
|
||||
$screen-tablet: 768px;
|
||||
|
||||
$gray-darker: #212121; // #212121 - text
|
||||
$gray-secondary: #757575; // #757575 - secondary text, icons
|
||||
$gray: #bdbdbd; // #bdbdbd - hint text
|
||||
$gray-light: #e0e0e0; // #e0e0e0 - divider
|
||||
$gray-lighter: #f5f5f5; // #f5f5f5 - background
|
||||
$link-color: $gray-darker;
|
||||
$link-bg: transparent;
|
||||
$link-hover-color: $gray-lighter;
|
||||
$link-hover-bg: $gray-lighter;
|
||||
$link-active-color: $gray-darker;
|
||||
$link-active-bg: $gray-light;
|
||||
$link-disabled-color: $gray-light;
|
||||
$link-disabled-bg: transparent;
|
||||
|
||||
/* -- Sidebar style ------------------------------- */
|
||||
|
||||
// Sidebar variables
|
||||
// --------------------------------------------------
|
||||
$zindex-sidebar-fixed: 1035;
|
||||
|
||||
$sidebar-desktop-width: 280px;
|
||||
$sidebar-width: 240px;
|
||||
|
||||
$sidebar-padding: 16px;
|
||||
$sidebar-divider: $sidebar-padding/2;
|
||||
|
||||
$sidebar-icon-width: 40px;
|
||||
$sidebar-icon-height: 20px;
|
||||
|
||||
@mixin sidebar-nav-base {
|
||||
text-align: center;
|
||||
|
||||
&:last-child{
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
li > a {
|
||||
background-color: $link-bg;
|
||||
}
|
||||
li:hover > a {
|
||||
background-color: $link-hover-bg;
|
||||
}
|
||||
li:focus > a, li > a:focus {
|
||||
background-color: $link-bg;
|
||||
}
|
||||
|
||||
> .open > a {
|
||||
&,
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: $link-hover-bg;
|
||||
}
|
||||
}
|
||||
|
||||
> .active > a {
|
||||
&,
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: $link-active-bg;
|
||||
}
|
||||
}
|
||||
> .disabled > a {
|
||||
&,
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: $link-disabled-bg;
|
||||
}
|
||||
}
|
||||
|
||||
// Dropdown menu items
|
||||
> .dropdown {
|
||||
// Remove background color from open dropdown
|
||||
> .dropdown-menu {
|
||||
background-color: $link-hover-bg;
|
||||
|
||||
> li > a {
|
||||
&:focus {
|
||||
background-color: $link-hover-bg;
|
||||
}
|
||||
&:hover {
|
||||
background-color: $link-hover-bg;
|
||||
}
|
||||
}
|
||||
|
||||
> .active > a {
|
||||
&,
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: $link-active-color;
|
||||
background-color: $link-active-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Sidebar
|
||||
// --------------------------------------------------
|
||||
|
||||
// Sidebar Elements
|
||||
//
|
||||
// Basic style of sidebar elements
|
||||
.sidebar {
|
||||
position: relative;
|
||||
display: block;
|
||||
min-height: 100%;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
border: none;
|
||||
@include transition(all 0.5s cubic-bezier(0.55, 0, 0.1, 1));
|
||||
@include clearfix();
|
||||
background-color: $white;
|
||||
|
||||
ul{
|
||||
padding-left: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.sidebar-divider, .divider {
|
||||
width: 80%;
|
||||
height: 1px;
|
||||
margin: 8px auto;
|
||||
background-color: lighten($gray, 20%);
|
||||
}
|
||||
|
||||
// Sidebar heading
|
||||
//----------------
|
||||
.sidebar-header {
|
||||
position: relative;
|
||||
margin-bottom: $sidebar-padding;
|
||||
@include transition(all .2s ease-in-out);
|
||||
}
|
||||
|
||||
.sidebar-image {
|
||||
padding-top: 24px;
|
||||
img {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Sidebar icons
|
||||
//----------------
|
||||
.sidebar-icon {
|
||||
display: inline-block;
|
||||
height: $sidebar-icon-height;
|
||||
margin-right: $sidebar-divider;
|
||||
text-align: left;
|
||||
font-size: $sidebar-icon-height;
|
||||
vertical-align: middle;
|
||||
|
||||
&:before, &:after {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-nav {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
@include sidebar-nav-base();
|
||||
|
||||
// Links
|
||||
//----------------
|
||||
li {
|
||||
position: relative;
|
||||
list-style-type: none;
|
||||
text-align: center;
|
||||
|
||||
a {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
@include hashi-a-style-core();
|
||||
|
||||
svg{
|
||||
top: 2px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
margin-bottom: -2px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sidebar toggling
|
||||
//
|
||||
// Hide sidebar
|
||||
.sidebar {
|
||||
width: 0;
|
||||
@include translate3d(-$sidebar-desktop-width, 0, 0);
|
||||
|
||||
&.open {
|
||||
min-width: $sidebar-desktop-width;
|
||||
width: $sidebar-desktop-width;
|
||||
@include translate3d(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Sidebar positions: fix the left/right sidebars
|
||||
.sidebar-fixed-left,
|
||||
.sidebar-fixed-right,
|
||||
.sidebar-stacked {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: $zindex-sidebar-fixed;
|
||||
}
|
||||
.sidebar-stacked {
|
||||
left: 0;
|
||||
}
|
||||
.sidebar-fixed-left {
|
||||
left: 0;
|
||||
box-shadow: 2px 0px 25px rgba(0,0,0,0.15);
|
||||
-webkit-box-shadow: 2px 0px 25px rgba(0,0,0,0.15);
|
||||
}
|
||||
.sidebar-fixed-right {
|
||||
right: 0;
|
||||
box-shadow: 0px 2px 25px rgba(0,0,0,0.15);
|
||||
-webkit-box-shadow: 0px 2px 25px rgba(0,0,0,0.15);
|
||||
|
||||
@include translate3d($sidebar-desktop-width, 0, 0);
|
||||
&.open {
|
||||
@include translate3d(0, 0, 0);
|
||||
}
|
||||
.icon-material-sidebar-arrow:before {
|
||||
content: "\e614"; // icon-material-arrow-forward
|
||||
}
|
||||
}
|
||||
|
||||
// Sidebar size
|
||||
//
|
||||
// Change size of sidebar and sidebar elements on small screens
|
||||
@media (max-width: $screen-tablet) {
|
||||
.sidebar.open {
|
||||
min-width: $sidebar-width;
|
||||
width: $sidebar-width;
|
||||
}
|
||||
|
||||
.sidebar .sidebar-header {
|
||||
//height: $sidebar-width * 9/16; // 16:9 header dimension
|
||||
}
|
||||
|
||||
.sidebar .sidebar-image {
|
||||
/* img {
|
||||
width: $sidebar-width/4 - $sidebar-padding;
|
||||
height: $sidebar-width/4 - $sidebar-padding;
|
||||
} */
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-overlay {
|
||||
visibility: hidden;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
opacity: 0;
|
||||
background: $white;
|
||||
z-index: $zindex-sidebar-fixed - 1;
|
||||
|
||||
-webkit-transition: visibility 0 linear .4s,opacity .4s cubic-bezier(.4,0,.2,1);
|
||||
-moz-transition: visibility 0 linear .4s,opacity .4s cubic-bezier(.4,0,.2,1);
|
||||
transition: visibility 0 linear .4s,opacity .4s cubic-bezier(.4,0,.2,1);
|
||||
-webkit-transform: translateZ(0);
|
||||
-moz-transform: translateZ(0);
|
||||
-ms-transform: translateZ(0);
|
||||
-o-transform: translateZ(0);
|
||||
transform: translateZ(0);
|
||||
}
|
||||
|
||||
.sidebar-overlay.active {
|
||||
opacity: 0.3;
|
||||
visibility: visible;
|
||||
-webkit-transition-delay: 0;
|
||||
-moz-transition-delay: 0;
|
||||
transition-delay: 0;
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
//
|
||||
// Hashicorp Nav (header/footer) Utiliy Vars and Mixins
|
||||
//
|
||||
// Notes:
|
||||
// - Include this in Application.scss before header and feature-footer
|
||||
// - Open Sans Google (Semibold - 600) font needs to be included if not already
|
||||
// --------------------------------------------------
|
||||
|
||||
// Variables
|
||||
$font-family-open-sans: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
$header-font-family: $font-family-open-sans;
|
||||
$header-font-weight: 600; // semi-bold
|
||||
|
||||
$header-height: 74px;
|
||||
$header-mobile-height: 60px;
|
||||
$by-hashicorp-width: 74px;
|
||||
$by-hashicorp-height: 16px;
|
||||
$nav-margin-right: 12px;
|
||||
|
||||
// Mixins
|
||||
@mixin hashi-a-style-core{
|
||||
font-family: $header-font-family;
|
||||
font-weight: $header-font-weight;
|
||||
font-size: 14px;
|
||||
//letter-spacing: 0.0625em;
|
||||
}
|
||||
|
||||
@mixin hashi-a-style{
|
||||
margin: 0 15px;
|
||||
padding: 0;
|
||||
line-height: 22px;
|
||||
@include hashi-a-style-core();
|
||||
@include transition( all 0.3s ease );
|
||||
|
||||
&:hover{
|
||||
@include transition( all 0.3s ease );
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
//general shared project mixins
|
||||
@mixin img-retina($image1x, $image, $width, $height) {
|
||||
background-image: url($image1x);
|
||||
background-size: $width $height;
|
||||
background-repeat: no-repeat;
|
||||
|
||||
@media (min--moz-device-pixel-ratio: 1.3),
|
||||
(-o-min-device-pixel-ratio: 2.6/2),
|
||||
(-webkit-min-device-pixel-ratio: 1.3),
|
||||
(min-device-pixel-ratio: 1.3),
|
||||
(min-resolution: 1.3dppx) {
|
||||
/* on retina, use image that's scaled by 2 */
|
||||
background-image: url($image);
|
||||
background-size: $width $height;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// -------------------------
|
||||
@mixin anti-alias() {
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
@mixin open-light() {
|
||||
font-family: $font-family-open-sans;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
@mixin open() {
|
||||
font-family: $font-family-open-sans;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
@mixin open-sb() {
|
||||
font-family: $font-family-open-sans;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@mixin open-bold() {
|
||||
font-family: $font-family-open-sans;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
@mixin bez-1-transition{
|
||||
@include transition( all 300ms ease-in-out );
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// Mixins Specific to project
|
||||
// - make edits to mixins here
|
||||
// --------------------------------------------------
|
||||
|
||||
// Variables
|
||||
$project-logo-width: 40px;
|
||||
$project-logo-height: 40px;
|
||||
$project-logo-pad-left: 0px;
|
||||
|
||||
// Mixins
|
||||
@mixin project-a-style{
|
||||
font-weight: 300;
|
||||
opacity: .75;
|
||||
|
||||
&:hover{
|
||||
color: $white;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin project-footer-a-style{
|
||||
line-height: 30px;
|
||||
|
||||
&:hover{
|
||||
opacity: .5;
|
||||
}
|
||||
}
|
|
@ -93,6 +93,59 @@ description: |-
|
|||
|
||||
<div class="clearfix"></div>
|
||||
|
||||
<div class="person">
|
||||
<img class="pull-left" src="//avatars0.githubusercontent.com/u/1642288?v=3&s=125">
|
||||
<div class="bio">
|
||||
<h3>Ryan Uber (<a href="https://github.com/ryanuber">@ryanuber</a>)</h3>
|
||||
<p>
|
||||
Ryan Uber is a core contributor to Consul where he works on all
|
||||
facets of Consul. He is also a core committer to
|
||||
<a href="https://www.serfdom.io">Serf</a>,
|
||||
<a href="https://www.nomadproject.io">Nomad</a>, and
|
||||
the Consul tools ecosystem, all while being an employee at
|
||||
<a href="https://www.hashicorp.com">HashiCorp</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
|
||||
<div class="person">
|
||||
<img class="pull-left" src="//avatars3.githubusercontent.com/u/673509?v=3&s=125">
|
||||
<div class="bio">
|
||||
<h3>James Phillips (<a href="https://github.com/slackpad">@slackpad</a>)</h3>
|
||||
<p>
|
||||
James Phillips is a core contributor to Consul where he works on all
|
||||
facets of Consul, including network tomography and prepared
|
||||
queries. He is also a core committer to
|
||||
<a href="https://www.serfdom.io">Serf</a> and
|
||||
the Consul tools ecosystem, all while being an employee at
|
||||
<a href="https://www.hashicorp.com">HashiCorp</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
|
||||
<div class="person">
|
||||
<img class="pull-left" src="//avatars1.githubusercontent.com/u/408570?v=3&s=125">
|
||||
<div class="bio">
|
||||
<h3>Seth Vargo (<a href="https://github.com/sethvargo">@sethvargo</a>)</h3>
|
||||
<p>
|
||||
Seth Vargo is a contributor to Consul, but his main focus is the
|
||||
<a href="https://www.consul.io/downloads_tools.html">Consul tools ecosystem</a>.
|
||||
He is also a core committer to
|
||||
<a href="https://www.vagrantup.com">Vagrant</a>,
|
||||
<a href="https://www.packer.io">Packer</a>, and
|
||||
<a href="https://www.vaultproject.io">Vault</a>, and many more
|
||||
open source projects, all while being an employee at
|
||||
<a href="https://www.hashicorp.com">HashiCorp</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
|
||||
<div class="person">
|
||||
<img class="pull-left" src="//www.gravatar.com/avatar/1e87e6016a7c4f4ecbd2517d84058467.png?s=125">
|
||||
<div class="bio">
|
||||
|
|
|
@ -127,6 +127,7 @@ A TTL check:
|
|||
```
|
||||
|
||||
A Docker check:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"check": {
|
||||
|
|
|
@ -15,7 +15,7 @@ descriptions.
|
|||
|
||||
When loading configuration, Consul loads the configuration from files
|
||||
and directories in lexical order. For example, configuration file `basic_config.json`
|
||||
will be processed before `extra_config.js`. Configuration specified later
|
||||
will be processed before `extra_config.json`. Configuration specified later
|
||||
will be merged into configuration specified earlier. In most cases,
|
||||
"merge" means that the later version will override the earlier. In
|
||||
some cases, such as event handlers, merging appends the handlers to the
|
||||
|
@ -504,6 +504,11 @@ definitions support being updated during a reload.
|
|||
* <a name="protocol"></a><a href="#protocol">`protocol`</a> Equivalent to the
|
||||
[`-protocol` command-line flag](#_protocol).
|
||||
|
||||
* <a name="reap"></a><a href="#reap">`reap`</a> controls Consul's automatic reaping of child processes, which
|
||||
is useful if Consul is running as PID 1 in a Docker container. If this isn't specified, then Consul will
|
||||
automatically reap child processes if it detects it is running as PID 1. If this is specified, then it
|
||||
controls reaping regardless of Consul's PID.
|
||||
|
||||
* <a name="recursor"></a><a href="#recursor">`recursor`</a> Provides a single recursor address.
|
||||
This has been deprecated, and the value is appended to the [`recursors`](#recursors) list for
|
||||
backwards compatibility.
|
||||
|
@ -557,24 +562,25 @@ definitions support being updated during a reload.
|
|||
* <a name="start_join_wan"></a><a href="#start_join_wan">`start_join_wan`</a> An array of strings specifying
|
||||
addresses of WAN nodes to [`-join-wan`](#_join_wan) upon startup.
|
||||
|
||||
* <a name="statsd_addr"></a><a href="#statsd_addr">`statsd_addr`</a> This provides the address of a statsd
|
||||
instance. If provided, Consul will send various telemetry information to that instance for aggregation.
|
||||
This can be used to capture runtime information. This sends UDP packets only and can be used with statsd
|
||||
or statsite.
|
||||
* <a name="statsd_addr"></a><a href="#statsd_addr">`statsd_addr`</a> This provides the address of a
|
||||
statsd instance in the format `host:port`. If provided, Consul will send various telemetry information
|
||||
to that instance for aggregation. This can be used to capture runtime information. This sends UDP packets
|
||||
only and can be used with statsd or statsite.
|
||||
|
||||
* <a name="dogstatsd_addr"></a><a href="#dogstatsd_addr">`dogstatsd_addr`</a> This provides the
|
||||
address of a DogStatsD instance. DogStatsD is a protocol-compatible flavor of statsd, with the added ability
|
||||
to decorate metrics with tags and event information. If provided, Consul will send various telemetry information
|
||||
to that instance for aggregation. This can be used to capture runtime information.
|
||||
address of a DogStatsD instance in the format `host:port`. DogStatsD is a protocol-compatible flavor of
|
||||
statsd, with the added ability to decorate metrics with tags and event information. If provided, Consul will
|
||||
send various telemetry information to that instance for aggregation. This can be used to capture runtime
|
||||
information.
|
||||
|
||||
* <a name="dogstatsd_tags"></a><a href="#dogstatsd_tags">`dogstatsd_tags`</a> This provides a list of global tags
|
||||
that will be added to all telemetry packets sent to DogStatsD. It is a list of strings, where each string
|
||||
looks like "my_tag_name:my_tag_value".
|
||||
|
||||
* <a name="statsite_addr"></a><a href="#statsite_addr">`statsite_addr`</a> This provides the address of a
|
||||
statsite instance. If provided, Consul will stream various telemetry information to that instance for
|
||||
aggregation. This can be used to capture runtime information. This streams via
|
||||
TCP and can only be used with statsite.
|
||||
statsite instance in the format `host:port`. If provided, Consul will stream various telemetry information
|
||||
to that instance for aggregation. This can be used to capture runtime information. This streams via TCP and
|
||||
can only be used with statsite.
|
||||
|
||||
* <a name="statsite_prefix"></a><a href="#statsite_prefix">`statsite_prefix`</a>
|
||||
The prefix used while writing all telemetry data to statsite. By default, this
|
||||
|
|
|
@ -38,6 +38,11 @@ The list of available flags are:
|
|||
to send this command. If this isn't specified, the command will contact
|
||||
"127.0.0.1:8500" which is the default HTTP address of a Consul agent.
|
||||
|
||||
The following environment variables control accessing the HTTP server via SSL:
|
||||
|
||||
* `CONSUL_HTTP_SSL` Set this to enable SSL
|
||||
* `CONSUL_HTTP_SSL_VERIFY` Set this to disable certificate checking (not recommended)
|
||||
|
||||
## Output
|
||||
|
||||
If coordinates are available, the command will print the estimated round trip
|
||||
|
|
|
@ -18,7 +18,7 @@ Atlas is able to securely retrieve data from nodes as Consul maintains a long-ru
|
|||
|
||||
To enable Atlas integration, you must specify the name of the Atlas infrastructure and the Atlas authentication
|
||||
token in your Consul configuration. The Atlas infrastructure name can be set either with the [`-atlas` CLI flag](/docs/agent/options.html#_atlas) or with the [`atlas_infrastructure` configuration option](/docs/agent/options.html#atlas_infrastructure). The Atlas token is set with the [`-atlas-token` CLI flag](/docs/agent/options.html#_atlas_token),
|
||||
[`-atlas-token` configuration option](/docs/agent/options.html#atlas_token), or `ATLAS_TOKEN` environment variable.
|
||||
[`atlas_token` configuration option](/docs/agent/options.html#atlas_token), or `ATLAS_TOKEN` environment variable.
|
||||
|
||||
To get an Atlas username and token, [create an account here](https://atlas.hashicorp.com/account/new?utm_source=oss&utm_medium=guide-atlas&utm_campaign=consul) and replace the respective values in your Consul configuration with your credentials.
|
||||
|
||||
|
|
|
@ -39,11 +39,11 @@ downloadable versions of the tool.
|
|||
Consul 0.6 introduces enhancements to the ACL system which may require special
|
||||
handling:
|
||||
|
||||
* Service ACL's are enforced during service discovery (REST + DNS)
|
||||
* Service ACLs are enforced during service discovery (REST + DNS)
|
||||
|
||||
Previously, service discovery was wide open, and any client could query
|
||||
information about any service without providing a token. Consul now requires
|
||||
read-level access at a minimum when ACL's are enabled to return service
|
||||
read-level access at a minimum when ACLs are enabled to return service
|
||||
information over the REST or DNS interfaces. If clients depend on an open
|
||||
service discovery system, then the following should be added to all ACL tokens
|
||||
which require it:
|
||||
|
@ -57,6 +57,40 @@ Note that the agent's [`acl_token`](/docs/agent/options.html#acl_token) is used
|
|||
when the DNS interface is queried, so be sure that token has sufficient
|
||||
privileges to return the DNS records you expect to retrieve from it.
|
||||
|
||||
* Event and keyring ACLs
|
||||
|
||||
Similar to service discovery, the new event and keyring ACLs will block access
|
||||
to these operations if the `acl_default_policy` is set to `deny`. If clients depend
|
||||
on open access to these, then the following should be added to all ACL tokens which
|
||||
require them:
|
||||
|
||||
event "" {
|
||||
policy = "write"
|
||||
}
|
||||
|
||||
keyring = "write"
|
||||
|
||||
Unfortunately, these are new ACLs for Consul 0.6, so they must be added after the
|
||||
upgrade is complete.
|
||||
|
||||
#### Prepared Queries
|
||||
|
||||
Prepared queries introduce a new Raft log entry type that isn't supported on older
|
||||
versions of Consul. It's important to not use the prepared query features of Consul
|
||||
until all servers in a cluster have been upgraded to version 0.6.0.
|
||||
|
||||
#### Single Private IP Enforcement
|
||||
|
||||
Consul will refuse to start if there are multiple private IPs available, so
|
||||
if this is the case you will need to configure Consul's advertise or bind addresses
|
||||
before upgrading.
|
||||
|
||||
#### New Web UI File Layout
|
||||
|
||||
The release .zip file for Consul's web UI no longer contains a `dist` sub-folder;
|
||||
everything has been moved up one level. If you have any automated scripts that
|
||||
expect the old layout you may need to update them.
|
||||
|
||||
## Consul 0.5.1
|
||||
|
||||
Consul version 0.5.1 uses a different backend store for persisting the Raft
|
||||
|
|
|
@ -178,6 +178,8 @@ description: Service discovery and configuration made easy. Distributed, highly
|
|||
<p> "Value": <span class="txt-p">"YmFy"</span></p>
|
||||
<p> }</p>
|
||||
<p>]</p>
|
||||
<p class="command"><span class="txt-r">admin@hashicorp</span>: echo "YmFy" | base64 --decode</p>
|
||||
<p>bar</p>
|
||||
<p class="command"><span class="txt-r">admin@hashicorp</span>: <span class="cursor"> </span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -196,7 +198,7 @@ description: Service discovery and configuration made easy. Distributed, highly
|
|||
<p>The intro and getting started guide contain
|
||||
a simple and approachable walkthrough for running Consul locally.</p>
|
||||
</div>
|
||||
<div class="col-xs-offset-5 col-xs-12 col-sm-6 col-sm-offset-0 right">
|
||||
<div class="col-xs-12 col-sm-6 col-sm-offset-0 right">
|
||||
<a class="outline-btn purple" href="/intro/index.html">Read the intro »</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -28,7 +28,6 @@ For simplicity, we'll run a single Consul agent in server mode:
|
|||
$ consul agent -server -bootstrap-expect 1 -data-dir /tmp/consul
|
||||
==> WARNING: BootstrapExpect Mode is specified as 1; this is the same as Bootstrap mode.
|
||||
==> WARNING: Bootstrap mode enabled! Do not enable unless necessary
|
||||
==> WARNING: It is highly recommended to set GOMAXPROCS higher than 1
|
||||
==> Starting Consul agent...
|
||||
==> Starting Consul agent RPC...
|
||||
==> Consul agent running!
|
||||
|
|
|
@ -40,7 +40,7 @@ and replace the respective values in your Consul configuration with
|
|||
your credentials.
|
||||
|
||||
You can view a live demo
|
||||
[here](https://atlas.hashicorp.com/hashicorp/infrastructures/consul-demo).
|
||||
[here](https://atlas.hashicorp.com/hashicorp/environments/consul-demo).
|
||||
|
||||
## Self-hosted Dashboard
|
||||
|
||||
|
|
|
@ -1,29 +1,40 @@
|
|||
<div id="footer">
|
||||
<div id="footer" class="navigation">
|
||||
<div class="container">
|
||||
<div class="footer-links">
|
||||
<ul class="main-links nav navbar-nav rls-sb">
|
||||
<li class="li-under"><a href="/intro/index.html">Intro</a></li>
|
||||
<li class="active li-under"><a href="/docs/index.html">Docs</a></li>
|
||||
<li class="li-under"><a href="/community.html">Community</a></li>
|
||||
<li class="li-under"><a href="http://demo.consul.io/">Demo</a></li>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<% if current_page.url != '/' %>
|
||||
<li class="li-under"><a href="<%= github_url :current_page %>">Edit this page</a></li>
|
||||
<div class="edit-page-link"><a href="<%= github_url :current_page %>">Edit this page</a></div>
|
||||
<% end %>
|
||||
<div>
|
||||
<ul class="main-links white nav navbar-nav">
|
||||
<li><a href="/intro/index.html">Intro</a></li>
|
||||
<li><a href="/docs/index.html">Docs</a></li>
|
||||
<li><a href="/community.html">Community</a></li>
|
||||
<li><a href="http://demo.consul.io/">Demo</a></li>
|
||||
</ul>
|
||||
|
||||
<ul class="buttons nav navbar-nav rls-sb">
|
||||
<li class="first download outline-btn purple"><a href="/downloads.html">Download</a></li>
|
||||
<li class="github outline-btn purple"><a href="https://github.com/hashicorp/consul">GitHub</a></li>
|
||||
<ul class="external-links white nav navbar-nav">
|
||||
<li class="first download">
|
||||
<a href="/downloads.html"><%= partial "layouts/svg/svg-download" %>Download</a>
|
||||
</li>
|
||||
<li class="github">
|
||||
<a href="https://github.com/hashicorp/consul"><%= partial "layouts/svg/svg-github" %>GitHub</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer-logo">
|
||||
<span></span>
|
||||
</div>
|
||||
<div class="footer-hashi os">
|
||||
<span>Copyright © <%= Time.now.year %>. A <a href="https://www.hashicorp.com">HashiCorp</a> Project.</span>
|
||||
<a class="hashi-logo" href="http://www.hashicorp.com"><%= image_tag 'footer-hashicorp-logo.png' %></a>
|
||||
</ div>
|
||||
<div class="footer-hashi pull-right">
|
||||
<div class="">
|
||||
<a class="hashicorp-project white" href="https://www.hashicorp.com">
|
||||
<span class="project-text">A </span>
|
||||
<%= partial "layouts/svg/svg-by-hashicorp" %>
|
||||
<span class="project-text">Project</span>
|
||||
<%= partial "layouts/svg/svg-hashicorp-logo" %>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
|
|
@ -25,26 +25,33 @@
|
|||
</head>
|
||||
|
||||
<body class="page-<%= current_page.data.page_title ? "#{current_page.data.page_title} layout-#{current_page.data.layout} page-sub" : "home layout-#{current_page.data.layout}" %>">
|
||||
<div id="header" class="<%= current_page.data.page_title == "home" ? "" : "navbar-static-top" %>">
|
||||
<div id="header" class="navigation <%= current_page.data.page_title == "home" ? "" : "navbar-static-top" %>">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="navbar-header">
|
||||
<button class="navbar-toggle" type="button" data-toggle="collapse" data-target=".bs-navbar-collapse">
|
||||
<div class="navbar-brand">
|
||||
<a class="logo" href="/"><img src="<%= image_path('wordtype@2x.png') %>" width="96px" height="18px">Consul</a>
|
||||
<a class="by-hashicorp white" href="https://hashicorp.com/"><span class="svg-wrap">by</span><%= partial "layouts/svg/svg-by-hashicorp" %><%= partial "layouts/svg/svg-hashicorp-logo" %>Hashicorp</a>
|
||||
</div>
|
||||
<button class="navbar-toggle white" type="button">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<div class="brand">
|
||||
<a class="logo" href="/"></a>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="collapse navbar-collapse bs-navbar-collapse" role="navigation">
|
||||
<ul class="buttons nav navbar-nav navbar-right rls-sb">
|
||||
<li class="first download outline-btn"><a href="/downloads.html">Download</a></li>
|
||||
<li class="github outline-btn"><a href="https://github.com/hashicorp/consul">GitHub</a></li>
|
||||
<div class="buttons hidden-xs">
|
||||
<nav class="navigation-links" role="navigation">
|
||||
<ul class="external-links white nav navbar-nav navbar-right">
|
||||
<li class="first download">
|
||||
<a href="/downloads.html"><%= partial "layouts/svg/svg-download" %>Download</a>
|
||||
</li>
|
||||
<li class="github">
|
||||
<a href="https://github.com/hashicorp/consul"><%= partial "layouts/svg/svg-github" %>GitHub</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="main-links nav navbar-nav navbar-right rls-sb">
|
||||
<ul class="main-links white nav navbar-nav navbar-right">
|
||||
<li class="first li-under"><a href="/intro/index.html">Intro</a></li>
|
||||
<li class="li-under"><a href="/docs/index.html">Docs</a></li>
|
||||
<li class="li-under"><a href="/community.html">Community</a></li>
|
||||
|
@ -53,3 +60,6 @@
|
|||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
<!-- Overlay for fixed sidebar -->
|
||||
<div class="sidebar-overlay"></div>
|
||||
|
||||
<!-- Material sidebar -->
|
||||
<aside id="sidebar" class="sidebar sidebar-default sidebar-fixed-right" role="navigation">
|
||||
<!-- Sidebar header -->
|
||||
<div class="sidebar-header header-cover">
|
||||
<!-- Sidebar brand image -->
|
||||
<div class="sidebar-image">
|
||||
<img src="<%= image_path('logo-header-gradient@2x.png') %>" width="50px" height="50px">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sidebar navigation -->
|
||||
<ul class="main nav sidebar-nav">
|
||||
<li class="first"><a href="/intro/index.html">Intro</a></li>
|
||||
<li class=""><a href="/docs/index.html">Docs</a></li>
|
||||
<li class=""><a href="/community.html">Community</a></li>
|
||||
<li class=""><a href="http://demo.consul.io/">Demo</a></li>
|
||||
</ul>
|
||||
<div class="divider"></div>
|
||||
<!-- Sidebar navigation 2-->
|
||||
<ul class="external nav sidebar-nav">
|
||||
<li class="first"><a class="v-btn gray sml" href="/downloads.html"><%= partial "layouts/svg/svg-download" %>Download</a></li>
|
||||
<li class=""><a class="v-btn gray sml" href="https://github.com/hashicorp/consul"><%= partial "layouts/svg/svg-github" %>GitHub</a></li>
|
||||
</ul>
|
||||
</aside>
|
|
@ -3,7 +3,7 @@
|
|||
<div class="col-md-4">
|
||||
<%= yield_content :sidebar %>
|
||||
</div> <!-- /col-md-4 -->
|
||||
<div class="col-md-8" role="main">
|
||||
<div id="main-content" class="col-md-8" role="main">
|
||||
<div class="bs-docs-section">
|
||||
<%= yield %>
|
||||
</div>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<%= partial "layouts/header" %>
|
||||
<%= partial "layouts/sidebar" %>
|
||||
<%= yield %>
|
||||
<%= partial "layouts/footer" %>
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<svg class="svg-by" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" viewBox="-1337.4 1130.1 73.8 16.1" xml:space="preserve" enable-background="new -1337.4 1130.1 73.8 16.1">
|
||||
<g>
|
||||
<path d="M-1329.6 1142.4v-4.9h-4.3v4.9h-2.2v-11.6h2.2v4.8h4.3v-4.8h2.2v11.6H-1329.6z"/>
|
||||
<path d="M-1318.8 1142.4h-1.7l-0.2-0.6c-0.8 0.5-1.7 0.8-2.5 0.8 -1.6 0-2.2-1.1-2.2-2.5 0-1.7 0.8-2.4 2.5-2.4h2v-0.9c0-0.9-0.3-1.3-1.6-1.3 -0.8 0-1.6 0.1-2.4 0.3l-0.3-1.6c0.8-0.2 2-0.4 2.9-0.4 2.7 0 3.5 0.9 3.5 3.1V1142.4zM-1321 1139.2h-1.6c-0.7 0-0.9 0.2-0.9 0.8 0 0.6 0.2 0.9 0.9 0.9 0.6 0 1.2-0.2 1.6-0.4V1139.2z"/>
|
||||
<path d="M-1314.2 1142.6c-0.9 0-2.1-0.2-2.9-0.5l0.3-1.6c0.7 0.2 1.7 0.4 2.5 0.4 0.9 0 1.1-0.2 1.1-0.9 0-0.5-0.1-0.8-1.5-1.1 -2.1-0.5-2.3-1-2.3-2.7s0.8-2.5 3.2-2.5c0.8 0 1.8 0.1 2.5 0.3l-0.2 1.7c-0.6-0.1-1.7-0.2-2.3-0.2 -0.9 0-1.1 0.2-1.1 0.7 0 0.7 0.1 0.7 1.2 1 2.4 0.6 2.6 0.9 2.6 2.7C-1311.1 1141.6-1311.6 1142.6-1314.2 1142.6z"/>
|
||||
<path d="M-1304.3 1142.4v-5.9c0-0.5-0.2-0.7-0.7-0.7s-1.4 0.3-2.2 0.7v5.9h-2.1v-12l2.1-0.3v4.4c0.9-0.5 2.2-0.8 3.1-0.8 1.4 0 1.9 1 1.9 2.5v6.2H-1304.3L-1304.3 1142.4z"/>
|
||||
<path d="M-1300.1 1132.7v-2.5h2.1v2.5H-1300.1zM-1300.1 1142.4v-8.5h2.1v8.5H-1300.1z"/>
|
||||
<path d="M-1296 1134c0-2.1 1.2-3.4 4.1-3.4 1.1 0 2.2 0.1 3.2 0.4l-0.2 1.9c-0.9-0.2-2-0.3-2.8-0.3 -1.5 0-2 0.5-2 1.8v4.5c0 1.2 0.5 1.8 2 1.8 0.8 0 1.9-0.1 2.8-0.3l0.2 1.9c-1 0.2-2.1 0.4-3.2 0.4 -2.9 0-4.1-1.2-4.1-3.4V1134z"/>
|
||||
<path d="M-1283.8 1142.6c-2.9 0-3.7-1.6-3.7-3.3v-2.1c0-1.7 0.8-3.4 3.7-3.4s3.7 1.6 3.7 3.4v2.1C-1280.1 1141-1280.9 1142.6-1283.8 1142.6zM-1283.8 1135.6c-1.1 0-1.6 0.5-1.6 1.5v2.3c0 1 0.4 1.5 1.6 1.5 1.1 0 1.6-0.5 1.6-1.5v-2.4C-1282.2 1136.1-1282.7 1135.6-1283.8 1135.6z"/>
|
||||
<path d="M-1273.9 1135.7c-0.8 0.4-1.5 0.8-2.3 1.2v5.5h-2.1v-8.5h1.8l0.1 0.9c0.5-0.3 1.5-0.9 2.2-1.1L-1273.9 1135.7z"/>
|
||||
<path d="M-1265.6 1139.6c0 1.9-0.8 3-2.8 3 -0.8 0-1.6-0.1-2.3-0.2v3.5l-2.1 0.3V1134h1.7l0.2 0.7c0.8-0.5 1.6-0.9 2.7-0.9 1.7 0 2.6 1 2.6 2.9V1139.6L-1265.6 1139.6zM-1270.6 1140.5c0.6 0.1 1.3 0.2 1.9 0.2 0.8 0 1.1-0.4 1.1-1.1v-3c0-0.7-0.3-1.1-1-1.1 -0.7 0-1.4 0.3-1.9 0.8L-1270.6 1140.5 -1270.6 1140.5z"/>
|
||||
</g>
|
||||
<g class="svg-bg-line">
|
||||
<rect x="-1268" y="1145" width="4.3" height="1"/>
|
||||
<rect x="-1338" y="1145" width="63" height="1"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
|
@ -0,0 +1,4 @@
|
|||
<svg id="svg-download" xmlns="http://www.w3.org/2000/svg" viewBox="-345 275 28 28" style="enable-background:new -345 275 28 28;">
|
||||
<path d="M-319,275h-24c-1.1,0-2,0.9-2,2v24c0,1.1,0.9,2,2,2h24c1.1,0,2-0.9,2-2v-24C-317,275.9-317.9,275-319,275z M-331.2,297.9
|
||||
l-6.8-5.6l2-2.4l3.2,2.6V282h3.2v10.5l3.2-2.6l2,2.4L-331.2,297.9z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 333 B |
|
@ -0,0 +1,7 @@
|
|||
<svg id="svg-download" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14 14" style="enable-background:new 0 0 14 14;">
|
||||
<path d="M13,0H1C0.5,0,0,0.5,0,1v12c0,0.5,0.5,1,1,1h4.7c0,0,0,0,0-0.1c0-0.2,0-0.6,0-1.1c-1.8,0.4-2.2-0.9-2.2-0.9
|
||||
c-0.3-0.8-0.7-1-0.7-1c-0.6-0.4,0-0.4,0-0.4c0.7,0,1,0.7,1,0.7c0.6,1,1.5,0.7,1.9,0.5c0.1-0.4,0.2-0.7,0.4-0.9c-1.5-0.2-3-0.7-3-3.2
|
||||
c0-0.7,0.3-1.3,0.7-1.8C3.7,5.8,3.5,5.1,3.9,4.2c0,0,0.6-0.2,1.8,0.7c0.5-0.1,1.1-0.2,1.6-0.2c0.6,0,1.1,0.1,1.6,0.2
|
||||
c1.3-0.8,1.8-0.7,1.8-0.7c0.4,0.9,0.1,1.6,0.1,1.7c0.4,0.5,0.7,1,0.7,1.8c0,2.5-1.5,3.1-3,3.2C8.7,11.1,9,11.5,9,12.1
|
||||
c0,0.9,0,1.6,0,1.8c0,0,0,0,0,0.1h4c0.5,0,1-0.5,1-1V1C14,0.5,13.5,0,13,0z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 689 B |
|
@ -0,0 +1,7 @@
|
|||
<svg class="svg-logo" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Isolation_Mode" x="0px" y="0px" viewBox="-344 273 29.4 32" xml:space="preserve" enable-background="new -344 273 29.4 32">
|
||||
<g>
|
||||
<polygon points="-326.2 296.7 -321.4 294.1 -321.4 275.8 -326.2 273 -326.2 286.6 -332.4 286.6 -332.4 281.3 -337.3 283.9 -337.3 302.2 -332.4 305 -332.4 291.4 -326.2 291.4 "/>
|
||||
<polygon points="-319.1 277.1 -319.1 295.6 -326.2 299.5 -326.2 305 -314.6 298.3 -314.6 279.7 "/>
|
||||
<polygon points="-332.4 273 -344 279.7 -344 298.3 -339.5 300.9 -339.5 282.4 -332.4 278.6 "/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 635 B |
Loading…
Reference in New Issue