Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
S
servicereg
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Model registry
Operate
Environments
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
This is an archived project. Repository and other project resources are read-only.
Show more breadcrumbs
ale
servicereg
Commits
ed01814b
Commit
ed01814b
authored
8 years ago
by
ale
Browse files
Options
Downloads
Patches
Plain Diff
various minor fixes
Fix the way DNS names are built. Add the --use-dbus option. Expand the README a bit.
parent
dcc61419
Branches
Branches containing commit
No related tags found
No related merge requests found
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
README.md
+30
-2
30 additions, 2 deletions
README.md
servicereg.go
+82
-26
82 additions, 26 deletions
servicereg.go
with
112 additions
and
28 deletions
README.md
+
30
−
2
View file @
ed01814b
servicereg
==========
Register services with
[
SkyDNS
](
https://github.com/skynetservices/skydns
)
by
interfacing with the local systemd.
Register services with
[
SkyDNS
](
https://github.com/skynetservices/skydns
)
by interfacing with
the local systemd.
To register a service running on this host, create a JSON-encoded file
in
`/etc/servicereg`
, using the LSB naming convention (so, no dots in
the file name). This should contain the name of the monitored service
and the port it runs on, for example:
{
"service": "etcd.service",
"port": 2679
}
This will register a service named
*etcd*
running on port 2679. The
`.service`
suffix is automatically removed from the service name to
generate the DNS name, or you can set the
`name`
attribute explicitly.
When the
*etcd.service*
systemd unit is active, servicereg will create
an object in etcd at
`/skydns/DOMAIN/etcd/HOSTNAME`
(depending on your
settings for the domain and hostname), pointing at the local host,
which will be picked up by SkyDNS. As long as the unit is running, the
object will be kept fresh with a periodic heartbeat request. Services
that are no longer running will be removed by etcd itself when the TTL
on the DNS object expires (5 seconds by default).
Options can be set with command line flags, or using environment
variables named as the uppercase flag with a
`SERVICEREG_`
prefix.
The program should be run as root if you want to bypass DBus and use a
direct connection to systemd. Use the
`--use-dbus`
flag otherwise.
This diff is collapsed.
Click to expand it.
servicereg.go
+
82
−
26
View file @
ed01814b
...
...
@@ -16,19 +16,29 @@ import (
"syscall"
"time"
"golang.org/x/net/context"
etcdclient
"github.com/coreos/etcd/client"
"github.com/coreos/go-systemd/dbus"
"golang.org/x/net/context"
)
var
(
domainName
=
flag
.
String
(
"domain"
,
"
example.com
"
,
"domain name to advertise"
)
domainName
=
flag
.
String
(
"domain"
,
""
,
"domain name to advertise"
)
configDir
=
flag
.
String
(
"config-dir"
,
"/etc/servicereg"
,
"config directory"
)
etcdURLs
=
flag
.
String
(
"etcd-urls"
,
"http://localhost:2379"
,
"etcd URLs (comma separated)"
)
hostTag
=
flag
.
String
(
"tag"
,
localHostname
(),
"host tag"
)
publicIP
=
flag
.
String
(
"ip"
,
localIP
(),
"public IP for this host"
)
useDbus
=
flag
.
Bool
(
"use-dbus"
,
false
,
"use DBus instead of a private connection to systemd"
)
stop
=
make
(
chan
struct
{})
defaultTTL
=
5
*
time
.
Second
presencePeriod
=
2
*
time
.
Second
configCheckPeriod
=
5
*
time
.
Second
etcdTimeout
=
3
*
time
.
Second
etcdConnectTimeout
=
10
*
time
.
Second
etcdKeepaliveTimeout
=
5
*
time
.
Second
)
// Try to guess this machine's IP.
...
...
@@ -64,21 +74,22 @@ func newEtcdClient(endpoints []string) (etcdclient.Client, error) {
Endpoints
:
endpoints
,
Transport
:
&
http
.
Transport
{
Dial
:
(
&
net
.
Dialer
{
Timeout
:
5
*
time
.
Second
,
KeepAlive
:
5
*
time
.
Second
,
Timeout
:
etcdConnectTimeout
,
KeepAlive
:
etcdKeepaliveTimeout
,
})
.
Dial
,
},
})
}
type
Service
struct
{
Name
string
`json:"name"`
Service
string
`json:"service"`
Name
string
`json:"name,omitempty"`
Port
int
`json:"port"`
Tag
string
`json:"tag,omitempty"`
}
func
(
s
Service
)
Valid
()
bool
{
return
s
.
Nam
e
!=
""
&&
s
.
Port
>
0
return
s
.
Servic
e
!=
""
&&
s
.
Port
>
0
}
type
DNSEntry
struct
{
...
...
@@ -107,12 +118,20 @@ func dnsPath(domain string) string {
return
strings
.
Join
(
tmp
,
"/"
)
}
func
stripService
(
s
string
)
string
{
return
strings
.
TrimSuffix
(
s
,
".service"
)
}
func
makeDNSEntry
(
service
*
Service
)
*
DNSEntry
{
tag
:=
service
.
Tag
if
tag
==
""
{
tag
=
*
hostTag
}
path
:=
dnsPath
(
fmt
.
Sprintf
(
"%s.%s"
,
tag
,
*
domainName
))
name
:=
service
.
Name
if
name
==
""
{
name
=
stripService
(
service
.
Service
)
}
path
:=
dnsPath
(
fmt
.
Sprintf
(
"%s.%s.%s"
,
tag
,
name
,
*
domainName
))
return
&
DNSEntry
{
Path
:
path
,
Host
:
*
hostTag
,
...
...
@@ -120,14 +139,28 @@ func makeDNSEntry(service *Service) *DNSEntry {
}
}
const
updateConcurrency
=
5
var
updateSem
=
make
(
chan
struct
{},
updateConcurrency
)
func
updatePresence
(
keysAPI
etcdclient
.
KeysAPI
,
entry
*
DNSEntry
)
{
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
5
*
time
.
Second
)
updateSem
<-
struct
{}{}
defer
func
()
{
<-
updateSem
}()
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
etcdTimeout
)
defer
cancel
()
key
:=
"/skydns"
+
entry
.
Path
// We track the 'created' state in the DNSEntry itself, to optimize the
// default case, but the state is cleared on config reload, so this
// function tries to detect existing state (file exists or not) by
// checking the etcd error code.
if
!
entry
.
created
{
_
,
err
:=
keysAPI
.
Set
(
ctx
,
key
,
entry
.
Serialize
(),
&
etcdclient
.
SetOptions
{
TTL
:
5
*
time
.
Second
,
TTL
:
defaultTTL
,
PrevExist
:
etcdclient
.
PrevNoExist
,
})
if
err
!=
nil
{
...
...
@@ -141,7 +174,7 @@ func updatePresence(keysAPI etcdclient.KeysAPI, entry *DNSEntry) {
// No else because the ErrorCodeNotFound case above must be able to fall through.
if
entry
.
created
{
_
,
err
:=
keysAPI
.
Set
(
ctx
,
key
,
entry
.
Serialize
(),
&
etcdclient
.
SetOptions
{
TTL
:
5
*
time
.
Second
,
TTL
:
defaultTTL
,
PrevExist
:
etcdclient
.
PrevExist
,
Refresh
:
true
,
})
...
...
@@ -154,21 +187,27 @@ func updatePresence(keysAPI etcdclient.KeysAPI, entry *DNSEntry) {
func
runPresence
(
etcd
etcdclient
.
Client
,
ch
<-
chan
dnsOp
)
{
keysAPI
:=
etcdclient
.
NewKeysAPI
(
etcd
)
entries
:=
make
(
map
[
string
]
*
DNSEntry
)
tick
:=
time
.
NewTicker
(
1
*
time
.
Secon
d
)
tick
:=
time
.
NewTicker
(
presencePerio
d
)
for
{
select
{
case
<-
tick
.
C
:
var
wg
sync
.
WaitGroup
for
_
,
e
:=
range
entries
{
wg
.
Add
(
1
)
go
func
(
e
*
DNSEntry
)
{
updatePresence
(
keysAPI
,
e
)
wg
.
Done
()
}(
e
)
}
wg
.
Wait
()
case
op
:=
<-
ch
:
if
op
.
flush
{
entries
=
make
(
map
[
string
]
*
DNSEntry
)
}
else
if
op
.
ok
{
entries
[
op
.
service
.
Nam
e
]
=
makeDNSEntry
(
op
.
service
)
entries
[
op
.
service
.
Servic
e
]
=
makeDNSEntry
(
op
.
service
)
}
else
{
delete
(
entries
,
op
.
service
.
Nam
e
)
delete
(
entries
,
op
.
service
.
Servic
e
)
}
case
<-
stop
:
...
...
@@ -189,9 +228,11 @@ func watchSystemd(configCh <-chan map[string]*Service, opCh chan dnsOp) {
var
conn
*
dbus
.
Conn
var
services
map
[
string
]
*
Service
// Listen to systemd events, and to configuration
// updates. When the configuration is updated, re-create the
// systemd connection with the new listener setup.
// Listen to systemd events, and to configuration updates. Whenever the
// configuration changes, we disconnect and reconnect from systemd: this
// is important because the subscriber gives us the initial status of
// the service when it is first started, and we use it to populate the
// presence map for new services.
for
{
select
{
case
services
=
<-
configCh
:
...
...
@@ -201,13 +242,17 @@ func watchSystemd(configCh <-chan map[string]*Service, opCh chan dnsOp) {
opCh
<-
dnsOp
{
flush
:
true
}
var
err
error
if
*
useDbus
{
conn
,
err
=
dbus
.
New
()
}
else
{
conn
,
err
=
dbus
.
NewSystemdConnection
()
}
if
err
!=
nil
{
log
.
Fatal
(
"error connecting to systemd: %v"
,
err
)
log
.
Fatal
f
(
"error connecting to systemd: %v"
,
err
)
}
if
err
=
conn
.
Subscribe
();
err
!=
nil
{
log
.
Fatal
(
"could not subscribe to systemd events: %v"
,
err
)
log
.
Fatal
f
(
"could not subscribe to systemd events: %v"
,
err
)
}
log
.
Printf
(
"watching %d services"
,
len
(
services
))
...
...
@@ -279,21 +324,20 @@ func loadConfig(dir string) (map[string]*Service, error) {
log
.
Printf
(
"error reading %s: invalid (empty) service"
,
name
)
continue
}
svcmap
[
svc
.
Nam
e
]
=
&
svc
svcmap
[
svc
.
Servic
e
]
=
&
svc
}
return
svcmap
,
nil
}
func
watchConfig
(
dir
string
,
ch
chan
map
[
string
]
*
Service
)
{
var
lastMtime
time
.
Time
tick
:=
time
.
NewTicker
(
5
*
time
.
Secon
d
)
tick
:=
time
.
NewTicker
(
configCheckPerio
d
)
for
{
select
{
case
<-
tick
.
C
:
stat
,
err
:=
os
.
Stat
(
dir
)
if
err
!=
nil
{
log
.
Printf
(
"error opening %s: %v"
,
dir
,
err
)
continue
log
.
Fatal
(
err
)
}
if
m
:=
stat
.
ModTime
();
m
.
After
(
lastMtime
)
{
log
.
Printf
(
"detected config change, reloading..."
)
...
...
@@ -308,8 +352,20 @@ func watchConfig(dir string, ch chan map[string]*Service) {
}
}
// Set defaults for command-line flags using variables from the environment.
func
defaultsFromEnv
()
{
flag
.
VisitAll
(
func
(
f
*
flag
.
Flag
)
{
envVar
:=
"SERVICEREG_"
+
strings
.
ToUpper
(
strings
.
Replace
(
f
.
Name
,
"-"
,
"_"
,
-
1
))
if
value
:=
os
.
Getenv
(
envVar
);
value
!=
""
{
f
.
DefValue
=
value
f
.
Value
.
Set
(
value
)
}
})
}
func
main
()
{
log
.
SetFlags
(
0
)
defaultsFromEnv
()
flag
.
Parse
()
// Verify that required args are set.
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment