Skip to content

Commit

Permalink
create orb-agent container (#85)
Browse files Browse the repository at this point in the history
* Dockerfile for orb-agent
* configuration updates for env variable config
* CI for orb-agent
  • Loading branch information
weyrick authored Aug 5, 2021
1 parent 8d3f732 commit 1e574a9
Show file tree
Hide file tree
Showing 9 changed files with 157 additions and 85 deletions.
7 changes: 6 additions & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,12 @@ jobs:
docker push ns1labs/orb-sinks:${{ env.REF_TAG }}
docker push ns1labs/orb-prom-sink:${{ env.REF_TAG }}
# agent
- name: Build + push orb-agent
env:
IMAGE_NAME: ns1labs/orb-agent
run: |
make agent
docker push ${{ env.IMAGE_NAME }}:${{ env.REF_TAG }}
- name: Build + push orb-ui
env:
Expand Down
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ endef

all: $(SERVICES)

.PHONY: all $(SERVICES) dockers dockers_dev ui services agent
.PHONY: all $(SERVICES) dockers dockers_dev ui services agent agent_bin

clean:
rm -rf ${BUILD_DIR}
Expand Down Expand Up @@ -87,8 +87,11 @@ dockers_dev: $(DOCKERS_DEV)
run:
docker-compose -f docker/docker-compose.yml up -d

agent_bin:
$(call compile_service_linux,agent)

agent:
$(call compile_service,agent)
docker build --tag=$(DOCKERHUB_REPO)/$(DOCKER_IMAGE_NAME_PREFIX)-agent:$(REF_TAG) -f agent/docker/Dockerfile .

ui:
cd ui/ && docker build --tag=$(DOCKERHUB_REPO)/$(DOCKER_IMAGE_NAME_PREFIX)-ui:$(REF_TAG) -f docker/Dockerfile .
Expand Down
8 changes: 1 addition & 7 deletions agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,7 @@ type orbAgent struct {
var _ Agent = (*orbAgent)(nil)

func New(logger *zap.Logger, c config.Config) (Agent, error) {
var dbFile string
if _, ok := c.OrbAgent.DB["file"]; !ok {
dbFile = "orb-agent.db"
} else {
dbFile = c.OrbAgent.DB["file"]
}
db, err := sqlx.Connect("sqlite3", dbFile)
db, err := sqlx.Connect("sqlite3", c.OrbAgent.DB.File)
if err != nil {
return nil, err
}
Expand Down
63 changes: 19 additions & 44 deletions agent/cloud_config/cloud_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (
"io/ioutil"
"net/http"
"os"
"strconv"
"strings"
"time"
)
Expand Down Expand Up @@ -119,8 +118,8 @@ func (cc *cloudConfigManager) autoProvision(apiAddress string, token string) (co
Name string `json:"name"`
}

aname, haveAname := cc.config.OrbAgent.Cloud["config"]["agent_name"]
if !haveAname {
aname := cc.config.OrbAgent.Cloud.Config.AgentName
if aname == "" {
hostname, err := os.Hostname()
if err != nil {
return config.MQTTConfig{}, err
Expand Down Expand Up @@ -159,49 +158,28 @@ func (cc *cloudConfigManager) autoProvision(apiAddress string, token string) (co

func (cc *cloudConfigManager) GetCloudConfig() (config.MQTTConfig, error) {

// if MQTT is specified in the config file, always use that
mqttAddress, haveMqttAddress := cc.config.OrbAgent.Cloud["mqtt"]["address"]
apiAddress, haveApiAddress := cc.config.OrbAgent.Cloud["api"]["address"]
id, haveId := cc.config.OrbAgent.Cloud["mqtt"]["id"]
key, haveKey := cc.config.OrbAgent.Cloud["mqtt"]["key"]
channel, haveChannel := cc.config.OrbAgent.Cloud["mqtt"]["channel_id"]

// currently we require address to be specified, it cannot be auto provisioned.
// this may change in the future
if !haveMqttAddress {
return config.MQTTConfig{}, errors.New("cloud.mqtt.address must be specified in configuration")
}
mqtt := cc.config.OrbAgent.Cloud.MQTT

if haveMqttAddress && haveId && haveKey && haveChannel {
if len(mqtt.Id) > 0 && len(mqtt.Key) > 0 && len(mqtt.ChannelID) > 0 {
cc.logger.Info("using explicitly specified cloud configuration",
zap.String("address", mqttAddress),
zap.String("id", id))
zap.String("address", mqtt.Address),
zap.String("id", mqtt.Id))
return config.MQTTConfig{
Address: mqttAddress,
Id: id,
Key: key,
ChannelID: channel,
Address: mqtt.Address,
Id: mqtt.Id,
Key: mqtt.Key,
ChannelID: mqtt.ChannelID,
}, nil
}

// if full config is not available, possibly attempt auto provision configuration
var ap bool
var err error
apConfig, haveAutoProvision := cc.config.OrbAgent.Cloud["config"]["auto_provision"]
if haveAutoProvision {
ap, err = strconv.ParseBool(apConfig)
if err != nil {
return config.MQTTConfig{}, err
}
} else {
ap = true
}

if !ap {
if !cc.config.OrbAgent.Cloud.Config.AutoProvision {
return config.MQTTConfig{}, errors.New("valid cloud MQTT config was not specified, and auto_provision was disabled")
}

err = cc.migrateDB()
err := cc.migrateDB()
if err != nil {
return config.MQTTConfig{}, err
}
Expand All @@ -215,29 +193,26 @@ func (cc *cloudConfigManager) GetCloudConfig() (config.MQTTConfig, error) {
}
} else {
// successfully loaded previous auto provision
dba.Address = mqttAddress
dba.Address = mqtt.Address
cc.logger.Info("using previous auto provisioned cloud configuration loaded from local storage",
zap.String("address", mqttAddress),
zap.String("address", mqtt.Address),
zap.String("id", dba.Id))
return dba, nil
}

// attempt a live auto provision
if !haveApiAddress {
return config.MQTTConfig{}, errors.New("wanted to auto provision, but no API address was available")
}
token, haveToken := cc.config.OrbAgent.Cloud["api"]["token"]
if !haveToken {
apiConfig := cc.config.OrbAgent.Cloud.API
if len(apiConfig.Token) == 0 {
return config.MQTTConfig{}, errors.New("wanted to auto provision, but no API token was available")
}

result, err := cc.autoProvision(apiAddress, token)
result, err := cc.autoProvision(apiConfig.Address, apiConfig.Token)
if err != nil {
return config.MQTTConfig{}, err
}
result.Address = mqttAddress
result.Address = mqtt.Address
cc.logger.Info("using auto provisioned cloud configuration",
zap.String("address", mqttAddress),
zap.String("address", mqtt.Address),
zap.String("id", result.Id))

return result, nil
Expand Down
33 changes: 24 additions & 9 deletions agent/config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,39 @@ type TLS struct {
Verify bool `mapstructure:"verify"`
}

type OrbAPIConfig struct {
Address string
Token string
type APIConfig struct {
Address string `mapstructure:"address"`
Token string `mapstructure:"token"`
}

type DBConfig struct {
File string `mapstructure:"file"`
}

type MQTTConfig struct {
Address string
Id string
Key string
ChannelID string
Address string `mapstructure:"address"`
Id string `mapstructure:"id"`
Key string `mapstructure:"key"`
ChannelID string `mapstructure:"channel_id"`
}

type CloudConfig struct {
AgentName string `mapstructure:"agent_name"`
AutoProvision bool `mapstructure:"auto_provision"`
}

type Cloud struct {
Config CloudConfig `mapstructure:"config"`
API APIConfig `mapstructure:"api"`
MQTT MQTTConfig `mapstructure:"mqtt"`
}

type OrbAgent struct {
Backends map[string]map[string]string `mapstructure:"backends"`
Tags map[string]string `mapstructure:"tags"`
Cloud map[string]map[string]string `mapstructure:"cloud"`
Cloud Cloud `mapstructure:"cloud"`
TLS TLS `mapstructure:"tls"`
DB map[string]string `mapstructure:"db"`
DB DBConfig `mapstructure:"db"`
}

type Config struct {
Expand Down
46 changes: 46 additions & 0 deletions agent/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
ARG PKTVISOR_TAG=develop
FROM debian:bullseye-slim AS builder

ENV BUILD_DEPS "g++ cmake make git pkgconf jq python3-pip python3-setuptools ca-certificates golang"

RUN \
apt-get update && \
apt-get upgrade --yes --force-yes && \
apt-get install --yes --force-yes --no-install-recommends ${BUILD_DEPS} && \
pip3 install conan

WORKDIR /
RUN \
git clone https://github.com/ns1labs/pktvisor.git /pktvisor-src && \
cd /pktvisor-src && git checkout ${PKTVISOR_TAG}

WORKDIR /tmp/build
RUN \
conan profile new --detect default && \
conan profile update settings.compiler.libcxx=libstdc++11 default && \
conan config set general.revisions_enabled=1

RUN \
PKG_CONFIG_PATH=/local/lib/pkgconfig cmake -DCMAKE_BUILD_TYPE=Release /pktvisor-src && \
make all test -j 4

WORKDIR /go/src/github.com/ns1labs/orb
COPY . .

RUN CGO_ENABLED=1 make agent_bin && mv build/orb-agent /tmp/build/orb-agent

FROM debian:bullseye-slim AS runtime

ENV RUNTIME_DEPS "curl ca-certificates"

RUN \
apt-get update && \
apt-get upgrade --yes --force-yes && \
apt-get install --yes --force-yes --no-install-recommends ${RUNTIME_DEPS} && \
rm -rf /var/lib/apt

COPY --from=builder /tmp/build/bin/pktvisord /usr/local/sbin/pktvisord
COPY --from=builder /tmp/build/orb-agent /usr/local/bin/orb-agent
COPY --from=builder /go/src/github.com/ns1labs/orb/agent/docker/agent.yaml /etc/orb/agent.yaml

ENTRYPOINT [ "/usr/local/bin/orb-agent" ]
10 changes: 10 additions & 0 deletions agent/docker/agent.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: "1.0"

visor:
taps:

orb:
backends:
pktvisor:
binary: "/usr/local/sbin/pktvisord"
config_file: "/etc/orb/agent.yaml"
39 changes: 22 additions & 17 deletions cmd/agent/config.example.yaml
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@
version: "1.0"

pktvisor:
binary: "/bin/pktvisord"
visor:
taps:
anycast:
type: pcap
mydefault:
input_type: pcap
config:
iface: eth0
sinks:
iface: "eth0"

orb:
vitals:
backends:
pktvisor:
binary: "/usr/local/sbin/pktvisord"
config_file: "/etc/orb/agent.yaml"
tags:
region: EU
pop: ams02
node_type: dns
mqtt:
# MQTT address
address: tls://127.0.0.1:8883
# agent id
id: "e342be9c-e70e-45e0-a1b1-31fe6e5954e1"
# agent key
key: "2b5f5f6f-dab8-4239-915e-77262b7b2da2"
# agent RPC channel ID
channel_id: "35a416a4-dc5f-4dca-b319-a6f1cc87bca7"
cloud:
config:
#agent_name: auto-provisioned
auto_provision: true
api:
address: https://api.orb.live
token: TOKEN
mqtt:
address: tls://127.0.0.1:8883
# id: "f420a133-7651-412d-852a-6141fafeaea5"
# key: "14ae65ae-092f-4fdc-be6a-0cfb378119dc"
# channel_id: "9610b0a4-b05f-46e5-a32d-000d8a2ec1fd"
# optional TLS config
tls:
verify: false
verify: true
29 changes: 24 additions & 5 deletions cmd/agent/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ import (
"go.uber.org/zap"
"os"
"os/signal"
"strings"
"syscall"
)

const (
envPrefix = "orb_agent"
defaultConfig = "/etc/orb/agent.yaml"
)

Expand Down Expand Up @@ -48,7 +48,11 @@ func Run(cmd *cobra.Command, args []string) {

// configuration
var config config2.Config
viper.Unmarshal(&config)
err = viper.Unmarshal(&config)
if err != nil {
logger.Error("agent start up error (config)", zap.Error(err))
os.Exit(1)
}

config.Debug = Debug

Expand Down Expand Up @@ -96,6 +100,24 @@ func init() {
func mergeOrError(path string) {
v := viper.New()
v.SetConfigFile(path)
v.SetConfigType("yaml")

v.AutomaticEnv()
replacer := strings.NewReplacer(".", "_")
v.SetEnvKeyReplacer(replacer)

// note: viper seems to require a default (or a BindEnv) to be overridden by environment variables
v.SetDefault("orb.cloud.api.address", "https://api.orb.live")
v.SetDefault("orb.cloud.api.token", "")
v.SetDefault("orb.cloud.config.agent_name", "")
v.SetDefault("orb.cloud.config.auto_provision", true)
v.SetDefault("orb.cloud.mqtt.address", "tls://mqtt.orb.live:8883")
v.SetDefault("orb.cloud.mqtt.id", "")
v.SetDefault("orb.cloud.mqtt.key", "")
v.SetDefault("orb.cloud.mqtt.channel_id", "")
v.SetDefault("orb.db.file", "./orb-agent.db")
v.SetDefault("orb.tls.verify", true)

cobra.CheckErr(v.ReadInConfig())

var fZero float64
Expand All @@ -117,9 +139,6 @@ func mergeOrError(path string) {

// initConfig reads in config file and ENV variables if set.
func initConfig() {
viper.SetConfigType("yaml")
viper.SetEnvPrefix(envPrefix)
viper.AutomaticEnv() // read in environment variables that match

if len(cfgFiles) == 0 {
mergeOrError(defaultConfig)
Expand Down

0 comments on commit 1e574a9

Please sign in to comment.