Merge remote-tracking branch 'upstream/develop' into gobgp_integration

This commit is contained in:
Emil Palm 2019-02-21 15:30:49 +01:00
commit 166a3f0fcf
23 changed files with 2313 additions and 8598 deletions

3
.gitignore vendored
View File

@ -28,9 +28,8 @@ DIST/
var/
etc/alicelg/alice.conf
etc/alice-lg/alice.conf
.DS_Store
*coverage*

View File

@ -10,7 +10,7 @@ ARCH=amd64
SYSTEM_INIT=systemd
# == END BUILD CONFIGURATION ==
# == END BUILD CONFIGURATION ==
VERSION=$(shell cat ./VERSION)
@ -45,16 +45,16 @@ dev:
backend_prod: client_prod
$(MAKE) -C backend/ bundle
$(MAKE) -C backend/ linux
alice: client_prod backend_prod
mv backend/alice-lg-* bin/
dist: clean alice
dist: clean alice
mkdir -p $(DIST)opt/ecix/alicelg/bin
mkdir -p $(DIST)etc/alicelg
mkdir -p $(DIST)opt/alice-lg/alice-lg/bin
mkdir -p $(DIST)etc/alice-lg
# Adding post install script
cp install/scripts/after_install $(DIST)/.
@ -70,10 +70,10 @@ else
endif
# Copy example configuration
cp etc/alicelg/alice.example.conf $(DIST)/etc/alicelg/alice.example.conf
cp etc/alice-lg/alice.example.conf $(DIST)/etc/alice-lg/alice.example.conf
# Copy application
cp bin/$(PROG)-linux-$(ARCH) DIST/opt/ecix/alicelg/bin/.
cp bin/$(PROG)-linux-$(ARCH) DIST/opt/ecix/alice-lg/bin/.
rpm: dist
@ -84,7 +84,7 @@ rpm: dist
# Create RPM from dist
fpm -s dir -t rpm -n $(PROG) -v $(VERSION) -C $(DIST) \
--architecture $(ARCH) \
--config-files /etc/alicelg/alice.example.conf \
--config-files /etc/alice-lg/alice.example.conf \
--after-install $(DIST)/after_install \
opt/ etc/
@ -105,7 +105,7 @@ remote_rpm: build_server dist
scp -r $(DIST) $(BUILD_SERVER):$(REMOTE_DIST)
ssh $(BUILD_SERVER) -- fpm -s dir -t rpm -n $(PROG) -v $(VERSION) -C $(REMOTE_DIST) \
--architecture $(ARCH) \
--config-files /etc/alicelg/alice.example.conf \
--config-files /etc/alice-lg/alice.example.conf \
--after-install $(REMOTE_DIST)/after_install \
opt/ etc/

View File

@ -3,7 +3,7 @@ __"No, no! The adventures first, explanations take such a dreadful time."__
_Lewis Carroll, Alice's Adventures in Wonderland & Through the Looking-Glass_
Take a look at an Alice-LG production examples at:
- https://lg-beta.de-cix.net/
- https://lg.de-cix.net/
- https://lg.ecix.net/
And checkout the API at:
@ -23,7 +23,7 @@ Currently Alice-LG supports the following APIs:
Normally you would first install the [birdwatcher API](https://github.com/ecix/birdwatcher) directly on the machine(s) where you run [BIRD](http://bird.network.cz/) on
and then install Alice-LG on a seperate public facing server and point her to the afore mentioned [birdwatcher API](https://github.com/ecix/birdwatcher).
This project was a direct result of the [RIPE IXP Tools Hackathon](https://atlas.ripe.net/hackathon/ixp-tools/)
This project was a direct result of the [RIPE IXP Tools Hackathon](https://atlas.ripe.net/hackathon/ixp-tools/)
just prior to [RIPE73](https://ripe73.ripe.net/) in Madrid, Spain.
Major thanks to Barry O'Donovan who built the original [INEX Bird's Eye](https://github.com/inex/birdseye) BIRD API of which Alice-LG is a spinnoff
@ -63,17 +63,17 @@ Your Alice-LG source will now be located at `~/go/src/github.com/alice-lg/alice-
## Configuration
An example configuration can be found at
[etc/alicelg/alice.example.conf](https://github.com/ecix/alice-lg/blob/readme_update/etc/alicelg/alice.example.conf).
An example configuration can be found at
[etc/alice-lg/alice.example.conf](https://github.com/alice-lg/alice-lg/blob/readme_update/etc/alice-lg/alice.example.conf).
You can copy it to any of the following locations:
etc/alicelg/alice.conf # local
etc/alicelg/alice.local.conf # local
/etc/alicelg/alice.conf # global
etc/alice-lg/alice.conf # local
etc/alice-lg/alice.local.conf # local
/etc/alice-lg/alice.conf # global
You will have to edit the configuration file as you need to point Alice-LG to the correct [APIs](https://github.com/ecix/birdwatcher):
You will have to edit the configuration file as you need to point Alice-LG to the correct [APIs](https://github.com/alice-lg/birdwatcher):
```ini
[source.0]
@ -127,15 +127,15 @@ In your alice.conf, you now can specify a theme by setting:
with the optional parameter (the "mountpoint" of the theme)
url_base = /theme
You can put assets (images, fonts, javscript, css) in
You can put assets (images, fonts, javscript, css) in
this folder.
Stylesheets and Javascripts are automatically included in
the client's html and are served from the backend.
Alice provides early stages of an extension API, which is for now
Alice provides early stages of an extension API, which is for now
only used to modify the content of the welcome screen,
by providing a javascript in your theme containing:
@ -146,7 +146,7 @@ Alice.updateContent({
tagline: "powered by Alice"
}
});
```
For an example check out: https://github.com/alice-lg/alice-theme-example
@ -154,7 +154,7 @@ For an example check out: https://github.com/alice-lg/alice-theme-example
## Hacking
The client is a Single Page React Application.
All sources are available in `client/`.
All sources are available in `client/`.
Install build tools as needed:

View File

@ -1 +1 @@
3.4.2
3.4.4

View File

@ -51,9 +51,9 @@ func endpoint(wrapped apiEndpoint) httprouter.Handle {
}
// Make error response
result = apiErrorResponse(rsId, err)
result, status := apiErrorResponse(rsId, err)
payload, _ := json.Marshal(result)
http.Error(res, string(payload), http.StatusInternalServerError)
http.Error(res, string(payload), status)
return
}

View File

@ -20,7 +20,12 @@ func apiStatus(_req *http.Request, params httprouter.Params) (api.Response, erro
if err != nil {
return nil, err
}
source := AliceConfig.SourceById(rsId).getInstance()
source := AliceConfig.SourceInstanceById(rsId)
if source == nil {
return nil, SOURCE_NOT_FOUND_ERROR
}
result, err := source.Status()
if err != nil {
apiLogSourceError("status", rsId, err)

View File

@ -37,7 +37,11 @@ func apiNeighborsList(_req *http.Request, params httprouter.Params) (api.Respons
Neighbours: neighbors,
}
} else {
source := AliceConfig.SourceById(rsId).getInstance()
source := AliceConfig.SourceInstanceById(rsId)
if source == nil {
return nil, SOURCE_NOT_FOUND_ERROR
}
neighborsResponse, err = source.Neighbours()
if err != nil {
apiLogSourceError("neighbors", rsId, err)

View File

@ -15,7 +15,12 @@ func apiRoutesList(_req *http.Request, params httprouter.Params) (api.Response,
return nil, err
}
neighborId := params.ByName("neighborId")
source := AliceConfig.SourceById(rsId).getInstance()
source := AliceConfig.SourceInstanceById(rsId)
if source == nil {
return nil, SOURCE_NOT_FOUND_ERROR
}
result, err := source.Routes(neighborId)
if err != nil {
apiLogSourceError("routes", rsId, neighborId, err)
@ -38,7 +43,11 @@ func apiRoutesListReceived(
}
neighborId := params.ByName("neighborId")
source := AliceConfig.SourceById(rsId).getInstance()
source := AliceConfig.SourceInstanceById(rsId)
if source == nil {
return nil, SOURCE_NOT_FOUND_ERROR
}
result, err := source.RoutesReceived(neighborId)
if err != nil {
apiLogSourceError("routes_received", rsId, neighborId, err)
@ -107,7 +116,11 @@ func apiRoutesListFiltered(
}
neighborId := params.ByName("neighborId")
source := AliceConfig.SourceById(rsId).getInstance()
source := AliceConfig.SourceInstanceById(rsId)
if source == nil {
return nil, SOURCE_NOT_FOUND_ERROR
}
result, err := source.RoutesFiltered(neighborId)
if err != nil {
apiLogSourceError("routes_filtered", rsId, neighborId, err)
@ -176,7 +189,11 @@ func apiRoutesListNotExported(
}
neighborId := params.ByName("neighborId")
source := AliceConfig.SourceById(rsId).getInstance()
source := AliceConfig.SourceInstanceById(rsId)
if source == nil {
return nil, SOURCE_NOT_FOUND_ERROR
}
result, err := source.RoutesNotExported(neighborId)
if err != nil {
apiLogSourceError("routes_not_exported", rsId, neighborId, err)

View File

@ -6,30 +6,51 @@ package main
// to internal IP addresses.
import (
"net/http"
"net/url"
"strings"
"github.com/alice-lg/alice-lg/backend/api"
)
type ResourceNotFoundError struct{}
func (self *ResourceNotFoundError) Error() string {
return "resource not found"
}
var SOURCE_NOT_FOUND_ERROR = &ResourceNotFoundError{}
const (
GENERIC_ERROR_TAG = "GENERIC_ERROR"
CONNECTION_REFUSED_TAG = "CONNECTION_REFUSED"
CONNECTION_TIMEOUT_TAG = "CONNECTION_TIMEOUT"
RESOURCE_NOT_FOUND_TAG = "NOT_FOUND"
)
const (
GENERIC_ERROR_CODE = 42
CONNECTION_REFUSED_CODE = 100
CONNECTION_TIMEOUT_CODE = 101
RESOURCE_NOT_FOUND_CODE = 404
)
func apiErrorResponse(routeserverId string, err error) api.ErrorResponse {
const (
ERROR_STATUS = http.StatusInternalServerError
RESOURCE_NOT_FOUND_STATUS = http.StatusNotFound
)
func apiErrorResponse(routeserverId string, err error) (api.ErrorResponse, int) {
code := GENERIC_ERROR_CODE
message := err.Error()
tag := GENERIC_ERROR_TAG
status := ERROR_STATUS
switch e := err.(type) {
case *ResourceNotFoundError:
tag = RESOURCE_NOT_FOUND_TAG
code = RESOURCE_NOT_FOUND_CODE
status = RESOURCE_NOT_FOUND_STATUS
case *url.Error:
if strings.Contains(message, "connection refused") {
tag = CONNECTION_REFUSED_TAG
@ -47,5 +68,5 @@ func apiErrorResponse(routeserverId string, err error) api.ErrorResponse {
Tag: tag,
Message: message,
RouteserverId: routeserverId,
}
}, status
}

View File

@ -9,7 +9,7 @@ import (
// Helper: Validate source Id
func validateSourceId(id string) (string, error) {
if len(id) > 15 {
if len(id) > 42 {
return "unknown", fmt.Errorf("Source ID too long with length: %d", len(id))
}
return id, nil

View File

@ -115,6 +115,17 @@ func (self *Config) SourceById(sourceId string) *SourceConfig {
return nil
}
// Get instance by id
func (self *Config) SourceInstanceById(sourceId string) sources.Source {
sourceConfig := self.SourceById(sourceId)
if sourceConfig == nil {
return nil // Nothing to do here.
}
// Get instance from config
return sourceConfig.getInstance()
}
// Get sources keys form ini
func getSourcesKeys(config *ini.File) []string {
sources := []string{}
@ -624,9 +635,9 @@ func getSources(config *ini.File) ([]*SourceConfig, error) {
// Try to load configfiles as specified in the files
// list. For example:
//
// ./etc/alicelg/alice.conf
// /etc/alicelg/alice.conf
// ./etc/alicelg/alice.local.conf
// ./etc/alice-lg/alice.conf
// /etc/alice-lg/alice.conf
// ./etc/alice-lg/alice.local.conf
//
func loadConfig(file string) (*Config, error) {

View File

@ -9,7 +9,7 @@ import (
func TestLoadConfigs(t *testing.T) {
config, err := loadConfig("../etc/alicelg/alice.example.conf")
config, err := loadConfig("../etc/alice-lg/alice.example.conf")
if err != nil {
t.Error("Could not load test config:", err)
}
@ -39,7 +39,7 @@ func TestLoadConfigs(t *testing.T) {
func TestSourceConfigDefaultsOverride(t *testing.T) {
config, err := loadConfig("../etc/alicelg/alice.example.conf")
config, err := loadConfig("../etc/alice-lg/alice.example.conf")
if err != nil {
t.Error("Could not load test config:", err)
}
@ -70,7 +70,7 @@ func TestSourceConfigDefaultsOverride(t *testing.T) {
}
func TestRejectAndNoexportReasons(t *testing.T) {
config, err := loadConfig("../etc/alicelg/alice.example.conf")
config, err := loadConfig("../etc/alice-lg/alice.example.conf")
if err != nil {
t.Error("Could not load test config:", err)
}
@ -97,7 +97,7 @@ func TestRejectAndNoexportReasons(t *testing.T) {
}
func TestBlackholeParsing(t *testing.T) {
config, err := loadConfig("../etc/alicelg/alice.example.conf")
config, err := loadConfig("../etc/alice-lg/alice.example.conf")
if err != nil {
t.Error("Could not load test config:", err)
}
@ -116,7 +116,7 @@ func TestBlackholeParsing(t *testing.T) {
}
func TestOwnASN(t *testing.T) {
config, err := loadConfig("../etc/alicelg/alice.example.conf")
config, err := loadConfig("../etc/alice-lg/alice.example.conf")
if err != nil {
t.Error("Could not load test config:", err)
}
@ -127,7 +127,7 @@ func TestOwnASN(t *testing.T) {
}
func TestRpkiConfig(t *testing.T) {
config, err := loadConfig("../etc/alicelg/alice.example.conf")
config, err := loadConfig("../etc/alice-lg/alice.example.conf")
if err != nil {
t.Error("Could not load test config:", err)
}
@ -157,7 +157,7 @@ func TestRpkiConfig(t *testing.T) {
}
func TestRejectCandidatesConfig(t *testing.T) {
config, err := loadConfig("../etc/alicelg/alice.example.conf")
config, err := loadConfig("../etc/alice-lg/alice.example.conf")
if err != nil {
t.Error("Could not load test config:", err)
return

View File

@ -17,7 +17,7 @@ func main() {
// Handle commandline parameters
configFilenameFlag := flag.String(
"config", "/etc/alicelg/alice.conf",
"config", "/etc/alice-lg/alice.conf",
"Alice looking glass configuration file",
)

View File

@ -119,6 +119,10 @@ func parseBirdwatcherStatus(bird ClientResponse, config Config) (api.Status, err
config.Timezone,
)
if config.ShowLastReboot == false {
lastReboot = time.Time{}
}
lastReconfig, _ := parseServerTime(
birdStatus["last_reconfig"],
config.ServerTimeExt,

View File

@ -4,9 +4,9 @@
# Use node:10 as base image
#
FROM node:10
FROM node:11
RUN npm install -g gulp
RUN npm install -g gulp@4.0.0
RUN npm install -g gulp-cli

View File

@ -14,7 +14,7 @@ image:
docker build . -t $(DOCKER_IMAGE)
deps: image
$(DOCKER_EXEC) "npm install"
$(DOCKER_EXEC) "yarn install"
client: stop deps
@echo "Building alice UI"

View File

@ -175,22 +175,26 @@ class RoutesPage extends React.Component {
<RoutesViewEmpty routes={this.props.routes}
loadNotExported={this.props.loadNotExported} />
<RoutesView
type={ROUTES_FILTERED}
routeserverId={this.props.params.routeserverId}
protocolId={this.props.params.protocolId} />
{this.props.receivedLoading && <RoutesLoadingIndicator />}
<RoutesView
type={ROUTES_RECEIVED}
routeserverId={this.props.params.routeserverId}
protocolId={this.props.params.protocolId} />
{this.props.notExportedLoading && <RoutesLoadingIndicator />}
<RoutesView
type={ROUTES_NOT_EXPORTED}
routeserverId={this.props.params.routeserverId}
protocolId={this.props.params.protocolId} />
<RoutesLoadingIndicator />
</div>
<div className="col-lg-3 col-md-12 col-aside-details">
@ -290,7 +294,12 @@ export default connect(
filtersApplied: filtersApplied,
},
relatedPeers: relatedPeers
relatedPeers: relatedPeers,
// Loding indicator helper
receivedLoading: state.routes.receivedLoading,
filteredLoading: state.routes.filteredLoading,
notExportedLoading: state.routes.notExportedLoading
});
}
)(RoutesPage);

7639
client/package-lock.json generated

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -5,12 +5,11 @@
# Create the required user and set permissions
#
SERVICE=alicelg
SERVICE=alice-lg
echo "[i] Post install $SERVICE"
echo "[i] Creating user and updating permissions"
useradd --system -d /opt/ecix/$SERVICE $SERVICE
useradd --system -d /opt/alice-lg/$SERVICE $SERVICE
echo "[i] Fixing permissions"
chown -R $SERVICE:$SERVICE /opt/ecix/$SERVICE
chown -R $SERVICE:$SERVICE /opt/alice-lg/$SERVICE

View File

@ -5,8 +5,8 @@ After=network.target
[Service]
Type=simple
User=alicelg
ExecStart=/opt/ecix/alicelg/bin/alice-lg-linux-amd64
User=alice-lg
ExecStart=/opt/alice-lg/alice-lg/bin/alice-lg-linux-amd64
[Install]
WantedBy=multi-user.target

View File

@ -1,5 +1,5 @@
# Alice Looking Glass
# Alice Looking Glass
description "Alice Looking Glass"
author "Matthias Hannig <mha@ecix.net>"
@ -10,5 +10,4 @@ respawn limit 20 10
start on runlevel [2345]
stop on runlevel [!2345]
exec su -l alicelg -c /opt/ecix/alicelg/bin/alice-lg-linux-amd64 2>&1 | logger -i -t 'ALICE LG'
exec su -l alice-lg -c /opt/alice-lg/alice-lg/bin/alice-lg-linux-amd64 2>&1 | logger -i -t 'ALICE LG'