mirror of
https://github.com/actions/actions-runner-controller.git
synced 2026-03-04 16:02:23 +08:00
Compare commits
2 Commits
nikola-jok
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
708ea5e421 | ||
|
|
1f615c1a33 |
2
.github/workflows/arc-publish-chart.yaml
vendored
2
.github/workflows/arc-publish-chart.yaml
vendored
@@ -79,7 +79,7 @@ jobs:
|
||||
|
||||
- name: Create kind cluster
|
||||
if: steps.list-changed.outputs.changed == 'true'
|
||||
uses: helm/kind-action@92086f6be054225fa813e0a4b13787fc9088faab
|
||||
uses: helm/kind-action@ef37e7f390d99f746eb8b610417061a60e82a6cc
|
||||
|
||||
# We need cert-manager already installed in the cluster because we assume the CRDs exist
|
||||
- name: Install cert-manager
|
||||
|
||||
2
.github/workflows/arc-validate-chart.yaml
vendored
2
.github/workflows/arc-validate-chart.yaml
vendored
@@ -70,7 +70,7 @@ jobs:
|
||||
ct lint --config charts/.ci/ct-config.yaml
|
||||
|
||||
- name: Create kind cluster
|
||||
uses: helm/kind-action@92086f6be054225fa813e0a4b13787fc9088faab
|
||||
uses: helm/kind-action@ef37e7f390d99f746eb8b610417061a60e82a6cc
|
||||
if: steps.list-changed.outputs.changed == 'true'
|
||||
|
||||
# We need cert-manager already installed in the cluster because we assume the CRDs exist
|
||||
|
||||
6
.github/workflows/gha-publish-chart.yaml
vendored
6
.github/workflows/gha-publish-chart.yaml
vendored
@@ -75,7 +75,7 @@ jobs:
|
||||
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435
|
||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f
|
||||
with:
|
||||
# Pinning v0.9.1 for Buildx and BuildKit v0.10.6
|
||||
# BuildKit v0.11 which has a bug causing intermittent
|
||||
@@ -84,14 +84,14 @@ jobs:
|
||||
driver-opts: image=moby/buildkit:v0.10.6
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build & push controller image
|
||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
|
||||
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8
|
||||
with:
|
||||
file: Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
||||
6
.github/workflows/gha-validate-chart.yaml
vendored
6
.github/workflows/gha-validate-chart.yaml
vendored
@@ -67,13 +67,13 @@ jobs:
|
||||
ct lint --config charts/.ci/ct-config-gha.yaml
|
||||
|
||||
- name: Set up docker buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435
|
||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f
|
||||
if: steps.list-changed.outputs.changed == 'true'
|
||||
with:
|
||||
version: latest
|
||||
|
||||
- name: Build controller image
|
||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
|
||||
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8
|
||||
if: steps.list-changed.outputs.changed == 'true'
|
||||
with:
|
||||
file: Dockerfile
|
||||
@@ -88,7 +88,7 @@ jobs:
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
- name: Create kind cluster
|
||||
uses: helm/kind-action@92086f6be054225fa813e0a4b13787fc9088faab
|
||||
uses: helm/kind-action@ef37e7f390d99f746eb8b610417061a60e82a6cc
|
||||
if: steps.list-changed.outputs.changed == 'true'
|
||||
with:
|
||||
cluster_name: chart-testing
|
||||
|
||||
6
.github/workflows/global-publish-canary.yaml
vendored
6
.github/workflows/global-publish-canary.yaml
vendored
@@ -93,7 +93,7 @@ jobs:
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -113,13 +113,13 @@ jobs:
|
||||
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435
|
||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f
|
||||
with:
|
||||
version: latest
|
||||
|
||||
# Unstable builds - run at your own risk
|
||||
- name: Build and Push
|
||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
|
||||
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
|
||||
2
.github/workflows/go.yaml
vendored
2
.github/workflows/go.yaml
vendored
@@ -69,7 +69,7 @@ jobs:
|
||||
mocks:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: "go.mod"
|
||||
|
||||
@@ -28,6 +28,9 @@ const (
|
||||
LabelKeyKubernetesComponent = "app.kubernetes.io/component"
|
||||
LabelKeyKubernetesVersion = "app.kubernetes.io/version"
|
||||
|
||||
// Well-known Kubernetes node labels
|
||||
LabelKeyKubernetesOS = "kubernetes.io/os"
|
||||
|
||||
// Github labels
|
||||
LabelKeyGitHubScaleSetName = "actions.github.com/scale-set-name"
|
||||
LabelKeyGitHubScaleSetNamespace = "actions.github.com/scale-set-namespace"
|
||||
|
||||
@@ -244,6 +244,9 @@ func (b *ResourceBuilder) newScaleSetListenerPod(autoscalingListener *v1alpha1.A
|
||||
terminationGracePeriodSeconds := int64(60)
|
||||
podSpec := corev1.PodSpec{
|
||||
ServiceAccountName: serviceAccount.Name,
|
||||
NodeSelector: map[string]string{
|
||||
LabelKeyKubernetesOS: "linux",
|
||||
},
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Name: autoscalingListenerContainerName,
|
||||
@@ -353,13 +356,16 @@ func mergeListenerPodWithTemplate(pod *corev1.Pod, tmpl *corev1.PodTemplateSpec)
|
||||
pod.Spec.ImagePullSecrets = tmpl.Spec.ImagePullSecrets
|
||||
}
|
||||
|
||||
if tmpl.Spec.NodeSelector != nil {
|
||||
pod.Spec.NodeSelector = tmpl.Spec.NodeSelector
|
||||
}
|
||||
|
||||
pod.Spec.Volumes = append(pod.Spec.Volumes, tmpl.Spec.Volumes...)
|
||||
pod.Spec.InitContainers = tmpl.Spec.InitContainers
|
||||
pod.Spec.EphemeralContainers = tmpl.Spec.EphemeralContainers
|
||||
pod.Spec.TerminationGracePeriodSeconds = tmpl.Spec.TerminationGracePeriodSeconds
|
||||
pod.Spec.ActiveDeadlineSeconds = tmpl.Spec.ActiveDeadlineSeconds
|
||||
pod.Spec.DNSPolicy = tmpl.Spec.DNSPolicy
|
||||
pod.Spec.NodeSelector = tmpl.Spec.NodeSelector
|
||||
pod.Spec.NodeName = tmpl.Spec.NodeName
|
||||
pod.Spec.HostNetwork = tmpl.Spec.HostNetwork
|
||||
pod.Spec.HostPID = tmpl.Spec.HostPID
|
||||
|
||||
@@ -242,3 +242,111 @@ func TestOwnershipRelationships(t *testing.T) {
|
||||
assert.Equal(t, true, *ownerRef.Controller, "Controller flag should be true")
|
||||
assert.Equal(t, true, *ownerRef.BlockOwnerDeletion, "BlockOwnerDeletion flag should be true")
|
||||
}
|
||||
|
||||
func TestListenerPodNodeSelector(t *testing.T) {
|
||||
autoscalingRunnerSet := v1alpha1.AutoscalingRunnerSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-scale-set",
|
||||
Namespace: "test-ns",
|
||||
Labels: map[string]string{
|
||||
LabelKeyKubernetesPartOf: labelValueKubernetesPartOf,
|
||||
LabelKeyKubernetesVersion: "0.2.0",
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
runnerScaleSetIDAnnotationKey: "1",
|
||||
AnnotationKeyGitHubRunnerGroupName: "test-group",
|
||||
AnnotationKeyGitHubRunnerScaleSetName: "test-scale-set",
|
||||
},
|
||||
},
|
||||
Spec: v1alpha1.AutoscalingRunnerSetSpec{
|
||||
GitHubConfigUrl: "https://github.com/org/repo",
|
||||
},
|
||||
}
|
||||
|
||||
b := ResourceBuilder{}
|
||||
ephemeralRunnerSet, err := b.newEphemeralRunnerSet(&autoscalingRunnerSet)
|
||||
require.NoError(t, err)
|
||||
|
||||
listener, err := b.newAutoScalingListener(&autoscalingRunnerSet, ephemeralRunnerSet, autoscalingRunnerSet.Namespace, "test:latest", nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
listenerServiceAccount := &corev1.ServiceAccount{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test",
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("default listener pod has linux nodeSelector", func(t *testing.T) {
|
||||
pod, err := b.newScaleSetListenerPod(listener, &corev1.Secret{}, listenerServiceAccount, nil)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, pod.Spec.NodeSelector)
|
||||
assert.Equal(t, "linux", pod.Spec.NodeSelector[LabelKeyKubernetesOS],
|
||||
"listener pod should default to linux nodeSelector")
|
||||
})
|
||||
|
||||
t.Run("nil listenerTemplate preserves linux nodeSelector", func(t *testing.T) {
|
||||
listenerNoTemplate := listener.DeepCopy()
|
||||
listenerNoTemplate.Spec.Template = nil
|
||||
|
||||
pod, err := b.newScaleSetListenerPod(listenerNoTemplate, &corev1.Secret{}, listenerServiceAccount, nil)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, pod.Spec.NodeSelector)
|
||||
assert.Equal(t, "linux", pod.Spec.NodeSelector[LabelKeyKubernetesOS],
|
||||
"listener pod should keep linux nodeSelector when no template is provided")
|
||||
})
|
||||
|
||||
t.Run("listenerTemplate with nil nodeSelector preserves linux default", func(t *testing.T) {
|
||||
listenerWithTemplate := listener.DeepCopy()
|
||||
listenerWithTemplate.Spec.Template = &corev1.PodTemplateSpec{
|
||||
Spec: corev1.PodSpec{
|
||||
// NodeSelector intentionally nil
|
||||
Tolerations: []corev1.Toleration{
|
||||
{Key: "example.com/test", Operator: corev1.TolerationOpExists},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
pod, err := b.newScaleSetListenerPod(listenerWithTemplate, &corev1.Secret{}, listenerServiceAccount, nil)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, pod.Spec.NodeSelector,
|
||||
"linux nodeSelector should not be cleared by template with nil nodeSelector")
|
||||
assert.Equal(t, "linux", pod.Spec.NodeSelector[LabelKeyKubernetesOS])
|
||||
assert.Len(t, pod.Spec.Tolerations, 1, "other template fields should still be applied")
|
||||
})
|
||||
|
||||
t.Run("listenerTemplate with explicit nodeSelector overrides default", func(t *testing.T) {
|
||||
listenerWithTemplate := listener.DeepCopy()
|
||||
listenerWithTemplate.Spec.Template = &corev1.PodTemplateSpec{
|
||||
Spec: corev1.PodSpec{
|
||||
NodeSelector: map[string]string{
|
||||
LabelKeyKubernetesOS: "linux",
|
||||
"custom-label/pool": "listeners",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
pod, err := b.newScaleSetListenerPod(listenerWithTemplate, &corev1.Secret{}, listenerServiceAccount, nil)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, pod.Spec.NodeSelector)
|
||||
assert.Equal(t, "linux", pod.Spec.NodeSelector[LabelKeyKubernetesOS])
|
||||
assert.Equal(t, "listeners", pod.Spec.NodeSelector["custom-label/pool"],
|
||||
"explicit template nodeSelector should be applied")
|
||||
})
|
||||
|
||||
t.Run("listenerTemplate with empty nodeSelector overrides default", func(t *testing.T) {
|
||||
listenerWithTemplate := listener.DeepCopy()
|
||||
listenerWithTemplate.Spec.Template = &corev1.PodTemplateSpec{
|
||||
Spec: corev1.PodSpec{
|
||||
NodeSelector: map[string]string{},
|
||||
},
|
||||
}
|
||||
|
||||
pod, err := b.newScaleSetListenerPod(listenerWithTemplate, &corev1.Secret{}, listenerServiceAccount, nil)
|
||||
require.NoError(t, err)
|
||||
// An explicitly set empty map is non-nil, so it overrides the default.
|
||||
// This is intentional: the user explicitly opted out of nodeSelector constraints.
|
||||
assert.NotNil(t, pod.Spec.NodeSelector)
|
||||
assert.Empty(t, pod.Spec.NodeSelector,
|
||||
"explicitly empty nodeSelector should override the linux default")
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user