Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 40 additions & 2 deletions .github/workflows/devstack.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,16 @@ jobs:
run: ./stack.sh
working-directory: ./devstack

- name: Fix Designate root_helper
# root_helper defaults to "sudo designate-rootwrap ..." in designate/conf/base.py.
# designate-rootwrap lives in the devstack venv (/opt/stack/data/venv/bin) which
# is not in sudo's secure_path -> every rndc addzone fails -> zones PENDING->ERROR.
# Insert the absolute path immediately after [DEFAULT] so oslo.config picks it up.
run: |
sudo sed -i '/^\[DEFAULT\]/a root_helper = sudo /opt/stack/data/venv/bin/designate-rootwrap /etc/designate/rootwrap.conf' \
/etc/designate/designate.conf
shell: bash

- name: Restart Designate
run: sudo systemctl restart "devstack@designate-*.service"

Expand All @@ -79,7 +89,7 @@ jobs:

- name: Wait for zone creation
run: |
while [ "$(openstack zone list -f csv | grep PENDING)" != "" ]; do date; openstack zone list -f value; sleep 1; done
while [ "$(openstack zone list -f value --status PENDING)" != "" ]; do date; openstack zone list -f value; sleep 1; done

- name: Start external-dns-openstack-webhook in background
run: |
Expand All @@ -94,7 +104,7 @@ jobs:

- name: Wait for PENDING
run: |
while [ "$(openstack zone list -f csv | grep PENDING)" != "" ]; do date; openstack zone list -f value; sleep 1; done
while [ "$(openstack zone list -f value --status PENDING)" != "" ]; do date; openstack zone list -f value; sleep 1; done

- name: Show created entries
run: |
Expand All @@ -107,3 +117,31 @@ jobs:
run: |
if [ $(openstack recordset list all -f value | grep -c " TXT ") -ne 10 ]; then exit 1; fi
if [ $(openstack recordset list all -f value | grep -c " A ") -ne 10 ]; then exit 2; fi

- name: Create zone all-projects.test in alt_demo project
run: |
openstack --os-cloud devstack-alt zone create --email admin@example.com all-projects.test.

- name: Wait for all-projects.test zone creation
run: |
while [ "$(openstack --os-cloud devstack-admin zone list -f value --status PENDING --all-projects)" != "" ]; do date; openstack --os-cloud devstack-admin zone list -f value --all-projects; sleep 1; done

- name: Kill external-dns-openstack-webhook
run: pkill -f external-dns-openstack-webhook || true

- name: Start external-dns-openstack-webhook as admin with --all-projects
run: |
OS_CLOUD=devstack-admin ./build/bin/external-dns-openstack-webhook --all-projects --domain-filter all-projects.test >/tmp/external-dns-openstack-webhook-all-projects.log 2>&1 &
for i in $(seq 30); do curl -sf http://127.0.0.1:8888 > /dev/null 2>&1 && break; sleep 1; done
curl -sf http://127.0.0.1:8888 > /dev/null || { cat /tmp/external-dns-openstack-webhook-all-projects.log; exit 1; }

- name: Run external-dns against all-projects.test as admin user
run: ./build/external-dns --txt-owner-id all-projects-cluster-id --provider webhook --source fake --fqdn-template=all-projects.test --log-level=debug --once 2>&1
working-directory: ./external-dns

- name: Show /tmp/external-dns-openstack-webhook-all-projects.log
run: cat /tmp/external-dns-openstack-webhook-all-projects.log

- name: Check all-projects created entries in all-projects.test
run: |
if [ $(openstack --os-cloud devstack-admin recordset list all-projects.test. --all-projects -f value | grep -c "all-projects-cluster-id") -ne 10 ]; then exit 1; fi
12 changes: 9 additions & 3 deletions cmd/webhook/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,19 @@ import (
)

const (
webhookServerAddr = "127.0.0.1:8888"
statusServerAddr = "0.0.0.0:8080"
defaultWebhookServerAddr = "127.0.0.1:8888"
defaultStatusServerAddr = "0.0.0.0:8080"
)

func main() {
var domainFilters []string
var allProjects bool
var webhookServerAddr string
var statusServerAddr string
pflag.StringArrayVar(&domainFilters, "domain-filter", []string{}, "List of domains to work on (can be specified multiple times)")
pflag.BoolVar(&allProjects, "all-projects", false, "Manage all zones and recordsets regardless of the project the service user resides in (requires an admin or appropriately scoped token)")
pflag.StringVar(&webhookServerAddr, "webhook-server-address", defaultWebhookServerAddr, "Address to bind the webhook server to")
pflag.StringVar(&statusServerAddr, "status-server-address", defaultStatusServerAddr, "Address to bind the status and metrics server to")
Comment thread
frittentheke marked this conversation as resolved.
pflag.Parse()

log.SetLevel(log.DebugLevel)
Expand Down Expand Up @@ -61,7 +67,7 @@ func main() {
}()

epf := endpoint.NewDomainFilter(domainFilters)
dp, err := provider.NewDesignateProvider(*epf, false)
dp, err := provider.NewDesignateProvider(*epf, allProjects, false)
if err != nil {
log.Fatalf("NewDesignateProvider: %v", err)
metrics.OpenstackConnectionMetric.Set(0)
Expand Down
15 changes: 9 additions & 6 deletions internal/designate/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,16 @@ type DesignateClientInterface interface {
// implementation of the DesignateClientInterface
type designateClient struct {
serviceClient *gophercloud.ServiceClient
allProjects bool
}

// factory function for the DesignateClientInterface
func NewDesignateClient() (DesignateClientInterface, error) {
func NewDesignateClient(allProjects bool) (DesignateClientInterface, error) {
serviceClient, err := createDesignateServiceClient()
if err != nil {
return nil, err
}
return &designateClient{serviceClient}, nil
return &designateClient{serviceClient: serviceClient, allProjects: allProjects}, nil
}

// authenticate in OpenStack and obtain Designate service endpoint
Expand Down Expand Up @@ -136,10 +137,10 @@ func (c designateClient) ForEachZone(ctx context.Context, filters []string, hand

var err error
if len(filters) == 0 {
err = doList(zones.ListOpts{})
err = doList(zones.ListOpts{AllProjects: c.allProjects})
} else {
for _, f := range filters {
if err = doList(zones.ListOpts{Name: f + "."}); err != nil {
if err = doList(zones.ListOpts{Name: f + ".", AllProjects: c.allProjects}); err != nil {
break
}
}
Expand All @@ -162,7 +163,7 @@ func (c designateClient) ForEachZone(ctx context.Context, filters []string, hand
func (c designateClient) ForEachRecordSet(ctx context.Context, zoneID string, handler func(recordSet *recordsets.RecordSet) error) error {
startTime := time.Now()

pager := recordsets.ListByZone(c.serviceClient, zoneID, recordsets.ListOpts{})
pager := recordsets.ListByZone(c.serviceClient, zoneID, recordsets.ListOpts{AllProjects: c.allProjects})
var pageCount int
var recordCount int

Expand Down Expand Up @@ -209,6 +210,7 @@ func (c designateClient) CreateRecordSet(ctx context.Context, zoneID string, opt

log.Debugf("→ Creating recordset: %s (%s) with %d targets", opts.Name, opts.Type, len(opts.Records))

opts.AllProjects = c.allProjects
r, err := recordsets.Create(ctx, c.serviceClient, zoneID, opts).Extract()

duration := time.Since(startTime)
Expand All @@ -235,6 +237,7 @@ func (c designateClient) UpdateRecordSet(ctx context.Context, zoneID, recordSetI
}
log.Debugf("→ Updating recordset: %s with %d targets", recordSetID, recordCount)

opts.AllProjects = c.allProjects
_, err := recordsets.Update(ctx, c.serviceClient, zoneID, recordSetID, opts).Extract()

duration := time.Since(startTime)
Expand All @@ -257,7 +260,7 @@ func (c designateClient) DeleteRecordSet(ctx context.Context, zoneID, recordSetI

log.Debugf("→ Deleting recordset: %s", recordSetID)

err := recordsets.Delete(ctx, c.serviceClient, zoneID, recordSetID).ExtractErr()
err := recordsets.DeleteWithOpts(ctx, c.serviceClient, zoneID, recordSetID, recordsets.DeleteOpts{AllProjects: c.allProjects}).ExtractErr()

duration := time.Since(startTime)
metrics.ApiCallLatency.WithLabelValues("DeleteRecordSet").Observe(duration.Seconds())
Expand Down
4 changes: 2 additions & 2 deletions internal/designate/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ type designateProvider struct {
}

// NewDesignateProvider is a factory function for OpenStack designate providers
func NewDesignateProvider(domainFilter endpoint.DomainFilter, dryRun bool) (provider.Provider, error) {
client, err := client.NewDesignateClient()
func NewDesignateProvider(domainFilter endpoint.DomainFilter, allProjects, dryRun bool) (provider.Provider, error) {
client, err := client.NewDesignateClient(allProjects)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion internal/designate/provider/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ clouds:
os.Setenv("OS_CLOUD", "unittest")
os.Setenv("OS_CACERT", tmpfile.Name())

if _, err := NewDesignateProvider(endpoint.DomainFilter{}, true); err != nil {
if _, err := NewDesignateProvider(endpoint.DomainFilter{}, false, true); err != nil {
t.Fatalf("Failed to initialize Designate provider: %s", err)
}
}
Expand Down