Skip to content

Commit 3871ea3

Browse files
Feature/#21232 Refactor license system NG (#42) (#43)
* fix logrus import path in glide.lock and main.go * enable network access for RPM build process * update redborder-dswatcher.spec to disable debug package creation and enhance service restart on upgrade * fix %postun condition to ensure ldconfig runs only on package removal * add ensureBlockedField method to manage 'blocked' attribute in nodes * add RPM build workflow and version file for automated packaging * refactor AllowLicense method to simplify license check and improve readability * If the license/s are empty or expired execute BlockOrganization Co-authored-by: Rafa Gómez <rgomez@redborder.com>
1 parent 0bd7171 commit 3871ea3

8 files changed

Lines changed: 178 additions & 30 deletions

File tree

.github/workflows/rpm.yml

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
name: RPM Build and Upload
2+
3+
on:
4+
push:
5+
branches:
6+
- 'master'
7+
- 'main'
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
13+
env:
14+
TAG: $(cat ./VERSION)
15+
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
16+
17+
steps:
18+
- name: Checkout Repository
19+
uses: actions/checkout@v2
20+
with:
21+
fetch-depth: 0
22+
23+
- name: Create tag based on metadata.rb
24+
id: create_tag
25+
run: |
26+
TAG=$(cat ./VERSION)
27+
echo "TAG=$TAG" >> $GITHUB_ENV
28+
shell: bash
29+
30+
- name: Check if Tag Exists
31+
id: check_tag
32+
run: |
33+
if git rev-parse "refs/tags/${{ env.TAG }}" >/dev/null 2>&1; then
34+
echo "Tag ${{ env.TAG }} already exists, exiting."
35+
exit 1
36+
fi
37+
shell: bash
38+
39+
- name: Set Version
40+
if: success()
41+
run: echo "VERSION=${{ env.TAG }}" >> $GITHUB_ENV
42+
43+
- name: Run Docker Container
44+
if: success()
45+
run: docker run --privileged -d --name builder --network host rockylinux:9 /bin/sleep infinity
46+
47+
- name: Install build tools RPM
48+
if: success()
49+
run: |
50+
docker cp ./ builder:/build
51+
docker exec builder bash -c "yum install -y epel-release && yum install -y make git mock"
52+
docker exec builder bash -c "rm -rf /etc/mock/default.cfg"
53+
54+
- name: Setup SDK
55+
if: success()
56+
run: |
57+
docker exec builder bash -c "curl https://raw.githubusercontent.com/redBorder/repoinit/master/sdk9.cfg > /build/sdk9.cfg"
58+
docker exec builder bash -c "echo \"config_opts['use_host_resolv'] = True\" >> /build/sdk9.cfg"
59+
docker exec builder bash -c "ln -s /build/sdk9.cfg /etc/mock/default.cfg"
60+
61+
- name: Build RPM using mock
62+
if: success()
63+
run: |
64+
docker exec builder bash -c "git config --global --add safe.directory /build"
65+
docker exec builder bash -c "cd /build/ && VERSION=${{ env.TAG }} make rpm"
66+
67+
- name: Copy RPMS
68+
if: success()
69+
run: |
70+
docker cp builder:/build/packaging/rpm/pkgs/. ./rpms
71+
72+
- name: Delete non-.rpm files
73+
if: success()
74+
run: |
75+
find ./rpms -type f -not -name '*.rpm' -exec rm {} \;
76+
77+
- name: Release
78+
if: success()
79+
uses: softprops/action-gh-release@v1
80+
with:
81+
files: ./rpms/*
82+
tag_name: ${{ env.TAG }}
83+
env:
84+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

VERSION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.0.0

cmd/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ import (
2626
"sync"
2727
"time"
2828

29-
"github.com/Sirupsen/logrus"
3029
"github.com/redBorder/dswatcher/internal/consumer"
3130
"github.com/redBorder/dswatcher/internal/decoder"
3231
"github.com/redBorder/dswatcher/internal/updater"
32+
"github.com/sirupsen/logrus"
3333
prefixed "github.com/x-cray/logrus-prefixed-formatter"
3434
)
3535

@@ -120,7 +120,7 @@ func main() {
120120
LicenseUUIDPath: config.Updater.LicenseUUIDPath,
121121
DataBagName: config.Updater.DataBagName,
122122
DataBagItem: config.Updater.DataBagItem,
123-
SkipSSL: config.Updater.SkipSSL,
123+
SkipSSL: config.Updater.SkipSSL,
124124
})
125125
if err != nil {
126126
log.Fatal("Error creating Chef API client: " + err.Error())

glide.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/consumer/kafka_consumer.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,9 @@ func (kc *KafkaConsumer) ConsumeNetflow() (chan FlowData, chan string) {
128128
// "messages" channel receives actual messages and "info" channel receives
129129
// notifications from the Kafka broker.
130130
//
131-
// - "limit_reached": All sensors belonging to an organization are blocked.
132-
// - "allowed_licenses": All sensors are blocked and the only the sensors
133-
// with a valid license are allowed.
131+
// - "limit_reached": All sensors belonging to an organization are blocked.
132+
// - "allowed_licenses": All sensors are blocked and the only the sensors
133+
// with a valid license are allowed.
134134
func (kc *KafkaConsumer) ConsumeLimits() (chan Message, chan string) {
135135
messages := make(chan Message)
136136
inputMessages, info := receiveLoop(kc.LimitsConsumer, kc.terminate)
@@ -150,6 +150,10 @@ func (kc *KafkaConsumer) ConsumeLimits() (chan Message, chan string) {
150150
case "limit_reached":
151151
messages <- BlockOrganization(data.UUID)
152152

153+
// If the license/s are empty or expired
154+
case "unknown_uuid":
155+
messages <- BlockOrganization(data.UUID)
156+
153157
case "allowed_licenses":
154158
messages <- ResetSensors{}
155159
for _, license := range data.Licenses {

internal/updater/chef_updater.go

Lines changed: 61 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,17 @@ package updater
1919

2020
import (
2121
"errors"
22+
"fmt"
2223
"net"
2324
"strconv"
2425
"strings"
2526

2627
"github.com/go-chef/chef"
28+
"github.com/sirupsen/logrus"
29+
)
30+
31+
var (
32+
log = logrus.New()
2733
)
2834

2935
///////////////
@@ -131,12 +137,17 @@ func (cu *ChefUpdater) FetchNodes() error {
131137
return errors.New("Error getting node info: " + err.Error())
132138
}
133139

134-
attributes, err := getParent(node.NormalAttributes, cu.SerialNumberPath)
140+
// Ensure redborder.blocked exists
141+
cu.ensureBlockedField(n, &node)
142+
143+
// Get parent of sensor UUID path
144+
parentAttrs, err := getParent(node.NormalAttributes, cu.SensorUUIDPath)
135145
if err != nil {
136-
return errors.New("Error getting node info: " + err.Error())
146+
return fmt.Errorf("Failed to get parent attributes for node %s: %v", n, err)
137147
}
138148

139-
sensorUUID, ok := attributes[getKeyFromPath(cu.SensorUUIDPath)].(string)
149+
sensorKey := getKeyFromPath(cu.SensorUUIDPath)
150+
sensorUUID, ok := parentAttrs[sensorKey].(string)
140151
if !ok {
141152
continue
142153
}
@@ -223,6 +234,8 @@ func (cu *ChefUpdater) BlockOrganization(organization string, productType uint32
223234
pType := getKeyFromPath(cu.ProductTypePath)
224235

225236
for _, node := range cu.nodes {
237+
log.Infof("Blocking node: %s", node.Name)
238+
226239
attributes, err := getParent(node.NormalAttributes, cu.BlockedStatusPath)
227240
if err != nil {
228241
errs = append(errs, err)
@@ -238,20 +251,22 @@ func (cu *ChefUpdater) BlockOrganization(organization string, productType uint32
238251
nodeProductType, err := strconv.ParseUint(nodeProductTypeStr, 10, 32)
239252
if err != nil || uint32(nodeProductType) == productType {
240253
if err != nil {
241-
errs = append(errs, errors.New(
242-
"Blocking sensor with unknown product type"),
243-
)
254+
errs = append(errs, errors.New("Blocking sensor with unknown product type"))
244255
}
245256

246257
attributes[blocked] = true
247258

248259
if cu.client != nil {
249-
cu.client.Nodes.Put(*node)
260+
_, err := cu.client.Nodes.Put(*node)
261+
if err != nil {
262+
errs = append(errs, err)
263+
} else {
264+
log.Infof("Successfully blocked and updated node %s", node.Name)
265+
}
250266
}
251267
}
252268
}
253269
}
254-
255270
return errs
256271
}
257272

@@ -260,7 +275,6 @@ func (cu *ChefUpdater) BlockOrganization(organization string, productType uint32
260275
func (cu *ChefUpdater) AllowLicense(license string) []error {
261276
var errs []error
262277
blocked := getKeyFromPath(cu.BlockedStatusPath)
263-
lic := getKeyFromPath(cu.LicenseUUIDPath)
264278

265279
for _, node := range cu.nodes {
266280
attributes, err := getParent(node.NormalAttributes, cu.BlockedStatusPath)
@@ -269,12 +283,10 @@ func (cu *ChefUpdater) AllowLicense(license string) []error {
269283
continue
270284
}
271285

272-
if attributes[lic] == license {
273-
attributes[blocked] = false
286+
attributes[blocked] = false
274287

275-
if cu.client != nil {
276-
cu.client.Nodes.Put(*node)
277-
}
288+
if cu.client != nil {
289+
cu.client.Nodes.Put(*node)
278290
}
279291
}
280292

@@ -306,18 +318,27 @@ func (cu *ChefUpdater) ResetAllSensors() error {
306318
// node and returns the inner object given a path
307319
func getParent(root map[string]interface{}, path string) (map[string]interface{}, error) {
308320
keys := strings.Split(path, "/")
309-
var ok bool
321+
if len(keys) == 0 {
322+
return nil, fmt.Errorf("invalid path: %q", path)
323+
}
310324

311-
attrs := root
312-
for i, key := range keys {
313-
if i < len(keys)-1 {
314-
if attrs, ok = attrs[key].(map[string]interface{}); !ok || attrs == nil {
315-
return nil, errors.New("Cannot find key: " + path)
316-
}
325+
current := root
326+
327+
for _, key := range keys[:len(keys)-1] {
328+
next, ok := current[key]
329+
if !ok {
330+
return nil, fmt.Errorf("key %q not found in path %q", key, path)
331+
}
332+
333+
nextMap, ok := next.(map[string]interface{})
334+
if !ok {
335+
return nil, fmt.Errorf("expected map[string]interface{} at key %q but got %T", key, next)
317336
}
337+
338+
current = nextMap
318339
}
319340

320-
return attrs, nil
341+
return current, nil
321342
}
322343

323344
func findNode(keyPath string, value string, nodes map[string]*chef.Node,
@@ -342,3 +363,21 @@ func getKeyFromPath(path string) string {
342363
keys := strings.Split(path, "/")
343364
return keys[len(keys)-1]
344365
}
366+
367+
// Create blocked (redborder -> blocked) field if it doesn't exist in the passed node as parameter
368+
func (cu *ChefUpdater) ensureBlockedField(n string, node *chef.Node) {
369+
redborderAttrs, ok := node.NormalAttributes["redborder"].(map[string]interface{})
370+
if !ok || redborderAttrs == nil {
371+
redborderAttrs = make(map[string]interface{})
372+
node.NormalAttributes["redborder"] = redborderAttrs
373+
}
374+
375+
if _, exists := redborderAttrs["blocked"]; !exists {
376+
log.Infof("Adding missing 'blocked: false' field to node %s", n)
377+
redborderAttrs["blocked"] = false
378+
379+
if _, err := cu.client.Nodes.Put(*node); err != nil {
380+
log.Errorf("Failed to update node %s: %v", n, err)
381+
}
382+
}
383+
}

packaging/rpm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ srpm: build_prepare
4040
rpm: srpm
4141
/usr/bin/mock \
4242
-r $(MOCK_CONFIG) \
43+
--enable-network \
4344
--define "__version $(VERSION)"\
4445
--define "__release $(BUILD_NUMBER)"\
4546
--resultdir=$(RESULT_DIR) \

packaging/rpm/redborder-dswatcher.spec

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ Requires: librd0 librdkafka
1212
Summary: Dynamic Sensors Watcher
1313
Group: Development/Libraries/Go
1414

15+
%global debug_package %{nil}
16+
1517
%description
1618
%{summary}
1719

@@ -53,9 +55,24 @@ getent passwd redborder-dswatcher >/dev/null || \
5355
-c "User of redborder-dswatcher service" redborder-dswatcher
5456
exit 0
5557

56-
%post -p /sbin/ldconfig
57-
%postun -p /sbin/ldconfig
58+
%post
59+
/sbin/ldconfig
5860
systemctl daemon-reload
61+
case "$1" in
62+
1)
63+
# Initial install
64+
:
65+
;;
66+
2)
67+
# Upgrade: Try to restart only if it was running to apply new config
68+
systemctl try-restart redborder-dswatcher.service >/dev/null 2>&1 || :
69+
;;
70+
esac
71+
72+
%postun
73+
if [ "$1" -eq 0 ]; then
74+
/sbin/ldconfig
75+
fi
5976

6077
%files
6178
%defattr(755,root,root)
@@ -65,6 +82,8 @@ systemctl daemon-reload
6582
/usr/lib/systemd/system/redborder-dswatcher.service
6683

6784
%changelog
85+
* Tue May 20 2025 Rafael Gómez <rgomez@redborder.com> - 3.0.0-1
86+
- Disable debug package creation and restarting redborder-dswatcher.service when upgrading to apply new config.
6887
* Wed Oct 04 2023 David Vanhoucke <dvanhoucke@redborder.com> - 2.0.0-1
6988
- adapt for go mod
7089
* Mon Oct 04 2021 Miguel Negrón <manegron@redborder.com> & David Vanhoucke <dvanhoucke@redborder.com> - 1.0.0-1

0 commit comments

Comments
 (0)