Skip to content

Commit b186b5b

Browse files
adrianrioboclaude
andcommitted
feat(ibmcloud): add GitLab runner support for IBM Power (ppc64le) and IBM Z (s390x)
Extends the GitLab runner integration to cover IBM Cloud offerings: - Add ppc64le and s390x arch types to the gitlab integration package - Make restorecon conditional in snippet-linux.sh for cross-distro compatibility (Ubuntu on IBM Z has no SELinux) - Add IBMPowerGitLabRunnerArgs() and IBMZGitLabRunnerArgs() to params, hardcoding the correct arch per target - Wire --glrunner-* flags and GLRunnerArgs into the ibm-power and ibm-z create commands - Update IBM Power and IBM Z actions to call gitlab.CreateRunner() and inject the runner setup script into cloud-init via ApplyT - Install git and podman on both targets (matching the fedora pattern) - Redirect gitlab-runner stdout/stderr to /var/log/gitlab-runner/runner.log via a systemd drop-in so job execution logs are captured locally and shipped via otelcol independently of GitLab connectivity - Add filelog/gitlab-runner otelcol receiver (when both --glrunner-token and --otel-* flags are set) to include runner job logs in the audit trail - Add unit tests for cloud-config template rendering covering runner-only, otel-only, and combined scenarios Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 82e1b2d commit b186b5b

12 files changed

Lines changed: 437 additions & 73 deletions

File tree

cmd/mapt/cmd/ibmcloud/hosts/ibm-power.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ func ibmPowerCreate() *cobra.Command {
5252
DebugLevel: viper.GetUint(params.DebugLevel),
5353
CirrusPWArgs: params.CirrusPersistentWorkerArgs(),
5454
GHRunnerArgs: params.GithubRunnerArgs(),
55+
GLRunnerArgs: params.IBMPowerGitLabRunnerArgs(),
5556
Tags: viper.GetStringMapString(params.Tags),
5657
},
5758
&ibmpower.PWArgs{
@@ -79,6 +80,7 @@ func ibmPowerCreate() *cobra.Command {
7980
flagSet.StringToStringP(params.OtelExtraAttrs, "", nil, params.OtelExtraAttrsDesc)
8081
params.AddGHActionsFlags(flagSet)
8182
params.AddCirrusFlags(flagSet)
83+
params.AddGitLabRunnerFlags(flagSet)
8284
c.PersistentFlags().AddFlagSet(flagSet)
8385
_ = c.MarkPersistentFlagRequired(params.PIPrivateSubnetID)
8486
_ = c.MarkPersistentFlagRequired(params.WorkspaceID)

cmd/mapt/cmd/ibmcloud/hosts/ibm-z.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ func ibmZCreate() *cobra.Command {
5252
DebugLevel: viper.GetUint(params.DebugLevel),
5353
CirrusPWArgs: params.CirrusPersistentWorkerArgs(),
5454
GHRunnerArgs: params.GithubRunnerArgs(),
55+
GLRunnerArgs: params.IBMZGitLabRunnerArgs(),
5556
Tags: viper.GetStringMapString(params.Tags),
5657
},
5758
&ibmz.ZArgs{
@@ -75,6 +76,7 @@ func ibmZCreate() *cobra.Command {
7576
flagSet.StringToStringP(params.OtelExtraAttrs, "", nil, params.OtelExtraAttrsDesc)
7677
params.AddGHActionsFlags(flagSet)
7778
params.AddCirrusFlags(flagSet)
79+
params.AddGitLabRunnerFlags(flagSet)
7880
c.PersistentFlags().AddFlagSet(flagSet)
7981
return c
8082
}

cmd/mapt/cmd/params/params.go

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ const (
8282
cirrusPWLabelsDesc string = "additional labels to use on the persistent worker (--it-cirrus-pw-labels key1=value1,key2=value2)"
8383

8484
glRunnerToken string = "glrunner-token"
85-
glRunnerTokenDesc string = "GitLab Personal Access Token with api scope"
85+
glRunnerTokenDesc string = "GitLab token with create_runner scope (personal access token, group/project access token, or service account token)"
8686
glRunnerProjectID string = "glrunner-project-id"
8787
glRunnerProjectIDDesc string = "GitLab project ID for project runner registration"
8888
glRunnerGroupID string = "glrunner-group-id"
@@ -271,6 +271,7 @@ func AddGitLabRunnerFlags(fs *pflag.FlagSet) {
271271
fs.StringSlice(glRunnerTags, nil, glRunnerTagsDesc)
272272
}
273273

274+
274275
func CirrusPersistentWorkerArgs() *cirrus.PersistentWorkerArgs {
275276
if viper.IsSet(cirrusPWToken) {
276277
return &cirrus.PersistentWorkerArgs{
@@ -287,7 +288,7 @@ func CirrusPersistentWorkerArgs() *cirrus.PersistentWorkerArgs {
287288
func GitLabRunnerArgs() *gitlab.GitLabRunnerArgs {
288289
if viper.IsSet(glRunnerToken) {
289290
return &gitlab.GitLabRunnerArgs{
290-
GitLabPAT: viper.GetString(glRunnerToken),
291+
GitLabToken: viper.GetString(glRunnerToken),
291292
ProjectID: viper.GetString(glRunnerProjectID),
292293
GroupID: viper.GetString(glRunnerGroupID),
293294
URL: viper.GetString(glRunnerURL),
@@ -338,3 +339,33 @@ func MACArchAsGitLabArch(arch string) *gitlab.Arch {
338339
}
339340
return &gitlab.Arm64
340341
}
342+
343+
func IBMPowerGitLabRunnerArgs() *gitlab.GitLabRunnerArgs {
344+
if viper.IsSet(glRunnerToken) {
345+
return &gitlab.GitLabRunnerArgs{
346+
GitLabToken: viper.GetString(glRunnerToken),
347+
ProjectID: viper.GetString(glRunnerProjectID),
348+
GroupID: viper.GetString(glRunnerGroupID),
349+
URL: viper.GetString(glRunnerURL),
350+
Tags: viper.GetStringSlice(glRunnerTags),
351+
Platform: &gitlab.Linux,
352+
Arch: &gitlab.Ppc64le,
353+
}
354+
}
355+
return nil
356+
}
357+
358+
func IBMZGitLabRunnerArgs() *gitlab.GitLabRunnerArgs {
359+
if viper.IsSet(glRunnerToken) {
360+
return &gitlab.GitLabRunnerArgs{
361+
GitLabToken: viper.GetString(glRunnerToken),
362+
ProjectID: viper.GetString(glRunnerProjectID),
363+
GroupID: viper.GetString(glRunnerGroupID),
364+
URL: viper.GetString(glRunnerURL),
365+
Tags: viper.GetStringSlice(glRunnerTags),
366+
Platform: &gitlab.Linux,
367+
Arch: &gitlab.S390x,
368+
}
369+
}
370+
return nil
371+
}

pkg/integrations/gitlab/glrunner.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ func CreateRunner(ctx *pulumi.Context, args *GitLabRunnerArgs) (pulumi.StringOut
147147

148148
// Configure GitLab provider with PAT
149149
provider, err := gitlab.NewProvider(ctx, "gitlab-provider", &gitlab.ProviderArgs{
150-
Token: pulumi.String(args.GitLabPAT),
150+
Token: pulumi.String(args.GitLabToken),
151151
BaseUrl: pulumi.String(args.URL),
152152
})
153153
if err != nil {

pkg/integrations/gitlab/snippet-linux.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ chmod +x /tmp/gitlab-runner
88
# Move to trusted path
99
sudo mv /tmp/gitlab-runner /usr/bin/gitlab-runner
1010

11-
# Fix SELinux context
12-
sudo restorecon -v /usr/bin/gitlab-runner
11+
# Fix SELinux context (no-op on non-SELinux systems)
12+
sudo restorecon -v /usr/bin/gitlab-runner 2>/dev/null || true
1313

1414
# Register runner
1515
sudo gitlab-runner register \

pkg/integrations/gitlab/types.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ var (
88
Linux Platform = "linux"
99
Darwin Platform = "darwin"
1010

11-
Arm64 Arch = "arm64"
12-
Amd64 Arch = "amd64"
13-
Arm Arch = "arm"
11+
Arm64 Arch = "arm64"
12+
Amd64 Arch = "amd64"
13+
Arm Arch = "arm"
14+
Ppc64le Arch = "ppc64le"
15+
S390x Arch = "s390x"
1416
)
1517

1618
type GitLabRunnerArgs struct {
17-
GitLabPAT string // Personal Access Token for Pulumi GitLab provider (input)
19+
GitLabToken string // Token with create_runner scope (PAT, group/project access token, or service account token)
1820
ProjectID string // GitLab project ID for project runner registration (mutually exclusive with GroupID)
1921
GroupID string // GitLab group ID for group runner registration (mutually exclusive with ProjectID)
2022
URL string // GitLab instance URL (e.g., https://gitlab.com)

pkg/provider/ibmcloud/action/ibm-power/cloud-config

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#cloud-config
2-
{{- if and .AppCode .OtelAuthToken .OtelIndex}}
2+
{{- if or (and .AppCode .OtelAuthToken .OtelIndex) .GitLabRunnerScript}}
33
write_files:
4+
{{- if and .AppCode .OtelAuthToken .OtelIndex}}
45
- path: /etc/otelcol-contrib/config.yaml
56
permissions: '0640'
67
content: |
@@ -72,6 +73,26 @@ write_files:
7273
index: "{{.OtelIndex}}"
7374
_sourceCategory: audit
7475
_sourceHost: ${env:HOSTNAME}
76+
{{- if .GitLabRunnerScript}}
77+
filelog/gitlab-runner:
78+
include:
79+
- /var/log/gitlab-runner/runner.log
80+
start_at: beginning
81+
include_file_path: true
82+
include_file_name: true
83+
operators:
84+
- type: move
85+
id: move_to_source_name
86+
from: attributes["log.file.path"]
87+
to: attributes["_sourceName"]
88+
- type: remove
89+
id: remove_file_name
90+
field: attributes["log.file.name"]
91+
attributes:
92+
index: "{{.OtelIndex}}"
93+
_sourceCategory: gitlab-runner
94+
_sourceHost: ${env:HOSTNAME}
95+
{{- end}}
7596
processors:
7697
filter/drop_null_bytes:
7798
logs:
@@ -109,7 +130,7 @@ write_files:
109130
level: "basic"
110131
pipelines:
111132
logs:
112-
receivers: [filelog/syslog, filelog/secure, filelog/audit]
133+
receivers: [filelog/syslog, filelog/secure, filelog/audit{{if .GitLabRunnerScript}}, filelog/gitlab-runner{{end}}]
113134
processors: [filter/drop_null_bytes, resource, batch]
114135
exporters: [otlphttp]
115136
- path: /etc/otelcol-contrib/auth_token
@@ -124,7 +145,21 @@ write_files:
124145
Environment="HOSTNAME=%H"
125146
EnvironmentFile=/etc/otelcol-contrib/auth_token
126147
{{- end}}
148+
{{- if .GitLabRunnerScript}}
149+
- path: /etc/systemd/system/gitlab-runner.service.d/logging.conf
150+
permissions: '0644'
151+
content: |
152+
[Service]
153+
StandardOutput=append:/var/log/gitlab-runner/runner.log
154+
StandardError=append:/var/log/gitlab-runner/runner.log
155+
- path: /opt/install-glrunner.sh
156+
permissions: '0755'
157+
content: |
158+
{{.GitLabRunnerScript}}
159+
{{- end}}
160+
{{- end}}
127161
runcmd:
162+
- dnf install -y git podman
128163
- |
129164
IFACE=$(ip route show default | awk '/default/ {print $5; exit}')
130165
ip route add 10.0.0.0/8 via {{.Gateway}} dev "$IFACE" 2>/dev/null || true
@@ -147,3 +182,7 @@ runcmd:
147182
systemctl daemon-reload
148183
systemctl enable --now otelcol-contrib
149184
{{- end}}
185+
{{- if .GitLabRunnerScript}}
186+
- mkdir -p /var/log/gitlab-runner
187+
- bash /opt/install-glrunner.sh
188+
{{- end}}

pkg/provider/ibmcloud/action/ibm-power/ibm-power.go

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import (
99
"github.com/pulumi/pulumi-tls/sdk/v5/go/tls"
1010
"github.com/pulumi/pulumi/sdk/v3/go/auto"
1111
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
12+
"github.com/redhat-developer/mapt/pkg/integrations"
13+
"github.com/redhat-developer/mapt/pkg/integrations/gitlab"
1214
"github.com/redhat-developer/mapt/pkg/manager"
1315
mc "github.com/redhat-developer/mapt/pkg/manager/context"
1416
ibmcloudp "github.com/redhat-developer/mapt/pkg/provider/ibmcloud"
@@ -28,14 +30,15 @@ var CloudConfig []byte
2830
var otelColVersion = "0.151.0"
2931

3032
type userDataValues struct {
31-
Gateway string
32-
AppCode string
33-
OtelAuthToken string
34-
OtelEndpoint string
35-
OtelColVersion string
36-
OtelIndex string
37-
OtelArch string
38-
OtelExtraAttrs map[string]string
33+
Gateway string
34+
AppCode string
35+
OtelAuthToken string
36+
OtelEndpoint string
37+
OtelColVersion string
38+
OtelIndex string
39+
OtelArch string
40+
OtelExtraAttrs map[string]string
41+
GitLabRunnerScript string
3942
}
4043

4144
const (
@@ -160,9 +163,33 @@ func (r *pwRequest) deploy(ctx *pulumi.Context) error {
160163
return fmt.Errorf("failed to look up private subnet: %w", err)
161164
}
162165

163-
userData, err := piUserData(subnetInfo.Gateway, r.otelAppCode, r.otelAuthToken, r.otelEndpoint, r.otelIndex, r.otelExtraAttrs)
164-
if err != nil {
165-
return fmt.Errorf("failed to render user data: %w", err)
166+
var piUserDataInput pulumi.StringPtrInput
167+
glRunnerArgs := gitlab.GetRunnerArgs()
168+
if glRunnerArgs != nil {
169+
authToken, err := gitlab.CreateRunner(ctx, glRunnerArgs)
170+
if err != nil {
171+
return err
172+
}
173+
gateway := subnetInfo.Gateway
174+
piUserDataInput = authToken.ApplyT(func(token string) (*string, error) {
175+
gitlab.SetAuthToken(token)
176+
defer gitlab.SetAuthToken("")
177+
glSnippet, err := integrations.GetIntegrationSnippetAsCloudInitWritableFile(gitlab.GetRunnerArgs(), defaultUser)
178+
if err != nil {
179+
return nil, err
180+
}
181+
ud, err := piUserData(gateway, r.otelAppCode, r.otelAuthToken, r.otelEndpoint, r.otelIndex, *glSnippet, r.otelExtraAttrs)
182+
if err != nil {
183+
return nil, err
184+
}
185+
return &ud, nil
186+
}).(pulumi.StringPtrOutput)
187+
} else {
188+
ud, err := piUserData(subnetInfo.Gateway, r.otelAppCode, r.otelAuthToken, r.otelEndpoint, r.otelIndex, "", r.otelExtraAttrs)
189+
if err != nil {
190+
return fmt.Errorf("failed to render user data: %w", err)
191+
}
192+
piUserDataInput = pulumi.StringPtr(ud)
166193
}
167194

168195
imageId, err := icdata.GetImage(r.mCtx,
@@ -187,7 +214,7 @@ func (r *pwRequest) deploy(ctx *pulumi.Context) error {
187214
PiCloudInstanceId: pulumi.String(r.workspaceID),
188215
PiStorageType: pulumi.String(instanceStorageType),
189216
PiKeyPairName: pki.PiKeyName,
190-
PiUserData: pulumi.StringPtr(userData),
217+
PiUserData: piUserDataInput,
191218
PiNetworks: ibmcloud.PiInstancePiNetworkArray{
192219
&ibmcloud.PiInstancePiNetworkArgs{
193220
NetworkId: pulumi.String(r.piPrivateSubnetID),
@@ -352,17 +379,18 @@ func piKey(ctx *pulumi.Context, mCtx *mc.Context, prefix, cId string, cloudInsta
352379

353380
// piUserData renders the cloud-config template and returns it base64-encoded
354381
// for use as PiUserData on a PowerVS instance.
355-
func piUserData(gateway, otelAppCode, otelAuthToken, otelEndpoint, otelIndex string, otelExtraAttrs map[string]string) (string, error) {
382+
func piUserData(gateway, otelAppCode, otelAuthToken, otelEndpoint, otelIndex, glRunnerScript string, otelExtraAttrs map[string]string) (string, error) {
356383
script, err := file.Template(
357384
userDataValues{
358-
Gateway: gateway,
359-
AppCode: otelAppCode,
360-
OtelAuthToken: otelAuthToken,
361-
OtelEndpoint: otelEndpoint,
362-
OtelColVersion: otelColVersion,
363-
OtelIndex: otelIndex,
364-
OtelArch: "ppc64le",
365-
OtelExtraAttrs: otelExtraAttrs,
385+
Gateway: gateway,
386+
AppCode: otelAppCode,
387+
OtelAuthToken: otelAuthToken,
388+
OtelEndpoint: otelEndpoint,
389+
OtelColVersion: otelColVersion,
390+
OtelIndex: otelIndex,
391+
OtelArch: "ppc64le",
392+
OtelExtraAttrs: otelExtraAttrs,
393+
GitLabRunnerScript: glRunnerScript,
366394
},
367395
string(CloudConfig))
368396
if err != nil {

0 commit comments

Comments
 (0)