Author SHA1 Message Date
josh f991c2fe15 feat: update
Release Chart / release (push) Successful in 5s
deploy / build (push) Successful in 2m29s
2026-08-01 12:26:59 +03:30
josh cf30022133 ci: switch release pipelines to gitea only
Release Chart / release (push) Successful in 5s
Release / release (push) Successful in 4s
deploy / build (push) Successful in 2m27s
2026-08-01 07:45:36 +03:30
josh 1ce335d3db fix: send service ports on lb allocate
deploy / build (push) Successful in 3m7s
Release / release (push) Failing after 4s
2026-08-01 07:25:02 +03:30
josh 10d741ceb6 ci: push images to kloude-public namespace
Release Chart / release (push) Successful in 14s
deploy / build (push) Successful in 5m30s
2026-07-23 02:54:25 +03:30
josh 23ee9db817 fix: change kloud.team to kloude.ir
Release Chart / release (push) Successful in 23s
deploy / build (push) Successful in 2m45s
2026-07-22 23:37:54 +03:30
josh e6054bc8ea ci: do not fail release when oci chart push fails
Release Chart / release (push) Successful in 4s
deploy / build (push) Canceled after 3m32s
2026-07-22 23:34:26 +03:30
josh 3935f5e2e8 ci: add resilient helm oci push fallbacks
Release Chart / release (push) Failing after 30s
deploy / build (push) Canceled after 1m30s
2026-07-22 23:32:49 +03:30
josh 1a5d6c8b37 ci: pass oci creds directly to helm push
Release Chart / release (push) Failing after 17s
deploy / build (push) Canceled after 1m50s
2026-07-22 23:31:14 +03:30
josh c40db0d85f ci: use plain-http for helm oci publish
Release Chart / release (push) Failing after 10s
deploy / build (push) Canceled after 28s
2026-07-22 23:30:06 +03:30
josh 6ba3ad4281 ci: use registry credentials for helm oci push
Release Chart / release (push) Failing after 12s
deploy / build (push) Canceled after 48s
2026-07-22 23:29:13 +03:30
14 changed files with 150 additions and 116 deletions
+1 -10
View File
@@ -20,8 +20,7 @@ jobs:
- name: Container image name
run: |
owner=$(echo "${GITHUB_REPOSITORY_OWNER}" | tr '[:upper:]' '[:lower:]')
echo "IMAGE_NAME=${REGISTRY_HOST}/kloude/kks-provider-plugin" >> "$GITHUB_ENV"
echo "IMAGE_NAME=${REGISTRY_HOST}/kloude-public/kks-provider-plugin" >> "$GITHUB_ENV"
echo "APP_VERSION=$(grep '^appVersion:' charts/kks-provider-plugin/Chart.yaml | awk '{print $2}' | tr -d '\"')" >> "$GITHUB_ENV"
- uses: docker/setup-buildx-action@v3
@@ -52,11 +51,3 @@ jobs:
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: Make container image public
if: github.event_name != 'pull_request'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
owner=$(echo "${GITHUB_REPOSITORY_OWNER}" | tr '[:upper:]' '[:lower:]')
gh api --method PATCH "/orgs/${owner}/packages/container/kks-provider-plugin/visibility" -f visibility=public || true
+12 -15
View File
@@ -96,27 +96,24 @@ jobs:
"${api}/releases/${release_id}/assets?name=${file_name}"
done
- name: Log in to registry
uses: docker/login-action@v3
with:
registry: registry.kloude.ir
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Push chart to OCI registry
run: |
set -euo pipefail
shopt -s nullglob
charts=(.cr-release-packages/*.tgz)
if [ ${#charts[@]} -eq 0 ]; then
echo "No packaged charts to push"
exit 0
fi
for chart in "${charts[@]}"; do
helm push "$chart" "oci://registry.kloude.ir/kloude/kks-provider-plugin-charts"
done
- name: Make OCI chart public
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh api --method PATCH "/orgs/kloude/kks-provider-plugin/packages/container/charts%2Fkks-provider-plugin/visibility" -f visibility=public || true
repo="oci://registry.kloude.ir/kloude-public/kks-provider-plugin-charts"
for chart in "${charts[@]}"; do
if ! helm push --plain-http \
--username "${{ secrets.REGISTRY_USER }}" \
--password "${{ secrets.REGISTRY_PASS }}" \
"$chart" "$repo"; then
echo "OCI push failed for $chart (registry token realm/protocol issue). Continuing because chart artifact is already published to Gitea release assets."
fi
done
+33 -70
View File
@@ -48,52 +48,8 @@ jobs:
helm package "${chart_dir}" --destination dist
echo "CHART_PACKAGE=dist/kks-provider-plugin-${version}.tgz" >> "$GITHUB_ENV"
- name: Build changelog
id: changelog
uses: mikepenz/release-changelog-builder-action@v5
with:
configurationJson: |
{
"template": "#{{CHANGELOG}}\n\n**Full Changelog**: #{{RELEASE_DIFF}}",
"categories": [
{
"title": "## Features",
"commits": ["^feat", "^feature"]
},
{
"title": "## Bug Fixes",
"commits": ["^fix", "^Fix"]
},
{
"title": "## Other Changes",
"commits": [".*"]
}
]
}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create or update GitHub release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ github.ref_name }}
CHANGELOG: ${{ steps.changelog.outputs.changelog }}
run: |
if gh release view "$TAG" >/dev/null 2>&1; then
gh release edit "$TAG" --notes "$CHANGELOG"
else
gh release create "$TAG" --title "$TAG" --notes "$CHANGELOG"
fi
- name: Upload Helm chart to release
if: steps.version.outputs.is_app_release == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ github.ref_name }}
run: gh release upload "$TAG" "$CHART_PACKAGE" --clobber
- name: Upload Helm chart artifact to Gitea release
if: steps.version.outputs.is_app_release == 'true' && secrets.GITEA_TOKEN != ''
- name: Create or update Gitea release
if: secrets.GITEA_TOKEN != ''
env:
GITEA_BASE_URL: https://git.kloude.ir
GITEA_REPO: kloude/kks-provider-plugin
@@ -102,13 +58,9 @@ jobs:
run: |
set -euo pipefail
if [ ! -f "$CHART_PACKAGE" ]; then
echo "Chart package not found: $CHART_PACKAGE"
exit 1
fi
api="${GITEA_BASE_URL}/api/v1/repos/${GITEA_REPO}"
file_name=$(basename "$CHART_PACKAGE")
release_name="$TAG"
release_body="Release ${TAG}"
release_json=$(curl -fsS \
-H "Authorization: token ${GITEA_TOKEN}" \
@@ -119,10 +71,30 @@ jobs:
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"${api}/releases" \
-d "{\"tag_name\":\"${TAG}\",\"name\":\"${TAG}\",\"target_commitish\":\"${GITHUB_SHA}\"}")
-d "{\"tag_name\":\"${TAG}\",\"name\":\"${release_name}\",\"body\":\"${release_body}\",\"target_commitish\":\"${GITHUB_SHA}\"}")
else
release_id=$(python3 -c 'import json,sys; print(json.loads(sys.stdin.read())["id"])' <<< "$release_json")
curl -fsS -X PATCH \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"${api}/releases/${release_id}" \
-d "{\"name\":\"${release_name}\",\"body\":\"${release_body}\"}" >/dev/null
release_json=$(curl -fsS \
-H "Authorization: token ${GITEA_TOKEN}" \
"${api}/releases/tags/${TAG}")
fi
if [ "${{ steps.version.outputs.is_app_release }}" != "true" ]; then
exit 0
fi
if [ ! -f "$CHART_PACKAGE" ]; then
echo "Chart package not found: $CHART_PACKAGE"
exit 1
fi
release_id=$(python3 -c 'import json,sys; print(json.loads(sys.stdin.read())["id"])' <<< "$release_json")
file_name=$(basename "$CHART_PACKAGE")
existing_assets=$(curl -fsS \
-H "Authorization: token ${GITEA_TOKEN}" \
@@ -142,24 +114,15 @@ jobs:
--data-binary "@${CHART_PACKAGE}" \
"${api}/releases/${release_id}/assets?name=${file_name}"
- name: Log in to registry
if: steps.version.outputs.is_app_release == 'true'
uses: docker/login-action@v3
with:
registry: registry.kloude.ir
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Push chart to OCI registry
if: steps.version.outputs.is_app_release == 'true'
run: |
owner=$(echo "${GITHUB_REPOSITORY_OWNER}" | tr '[:upper:]' '[:lower:]')
helm push "$CHART_PACKAGE" "oci://registry.kloude.ir/kloude/kks-provider-plugin-charts"
set -euo pipefail
repo="oci://registry.kloude.ir/kloude-public/kks-provider-plugin-charts"
- name: Make OCI chart public
if: steps.version.outputs.is_app_release == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
owner=$(echo "${GITHUB_REPOSITORY_OWNER}" | tr '[:upper:]' '[:lower:]')
gh api --method PATCH "/orgs/${owner}/packages/container/charts%2Fkks-provider-plugin/visibility" -f visibility=public || true
if ! helm push --plain-http \
--username "${{ secrets.REGISTRY_USER }}" \
--password "${{ secrets.REGISTRY_PASS }}" \
"$CHART_PACKAGE" "$repo"; then
echo "OCI push failed (registry token realm/protocol issue). Continuing because chart artifact is already published to Gitea release assets."
fi
+2 -2
View File
@@ -19,9 +19,9 @@ Example install:
helm install kks-provider-plugin https://github.com/kubelancloud/kks-provider-plugin/releases/download/v1.0.0/kks-provider-plugin-1.0.0.tgz \
--namespace kube-system \
--create-namespace \
--set lb.serverURL=https://lb.example.kloud.team \
--set lb.serverURL=https://lb.example.kloude.ir \
--set lb.accessToken="$LB_TOKEN" \
--set csi.serverURL=https://csi.example.kloud.team \
--set csi.serverURL=https://csi.example.kloude.ir \
--set csi.accessToken="$CSI_TOKEN"
```
+2 -2
View File
@@ -2,8 +2,8 @@ apiVersion: v2
name: kks-provider-plugin
description: Combined Kloud provider plugin chart (LoadBalancer + CSI) for kks clusters
type: application
version: 1.1.2
appVersion: "1.1.0"
version: 1.2.4
appVersion: "1.1.1"
kubeVersion: ">=1.28.0-0"
home: https://github.com/KubelanCloud/kks-provider-plugin
sources:
+6 -6
View File
@@ -6,14 +6,14 @@ nameOverride: ""
fullnameOverride: ""
image:
repository: registry.kloud.team/kks/kubelancloud/kks-provider-plugin
repository: registry.kloude.ir/kloude-public/kks-provider-plugin:latest
tag: "latest"
pullPolicy: IfNotPresent
imagePullSecrets: []
lb:
serverURL: "https://lb.kloud.team"
serverURL: "https://lb.kloude.ir"
accessToken: ""
existingSecret: ""
existingSecretAccessTokenKey: access-token
@@ -47,16 +47,16 @@ csi:
name: storage.csi.onkksmanagement.addresslist.cloud
sidecars:
provisioner:
repository: registry.kloud.team/kks/sig-storage/csi-provisioner
repository: registry.kloude.ir/kks/sig-storage/csi-provisioner
tag: v5.1.0
attacher:
repository: registry.kloud.team/kks/sig-storage/csi-attacher
repository: registry.kloude.ir/kks/sig-storage/csi-attacher
tag: v4.7.0
registrar:
repository: registry.kloud.team/kks/sig-storage/csi-node-driver-registrar
repository: registry.kloude.ir/kks/sig-storage/csi-node-driver-registrar
tag: v2.12.0
livenessProbe:
repository: registry.kloud.team/kks/sig-storage/livenessprobe
repository: registry.kloude.ir/kks/sig-storage/livenessprobe
tag: v2.13.1
storageClass:
enabled: true
+2 -2
View File
@@ -93,10 +93,10 @@ func (c *Config) normalize() error {
}
if c.Driver.Name == "" {
c.Driver.Name = "storage.csi.kloud.team"
c.Driver.Name = "storage.csi.kloude.ir"
}
if c.Driver.Endpoint == "" {
c.Driver.Endpoint = "unix:///var/lib/kubelet/plugins/storage.csi.kloud.team/csi.sock"
c.Driver.Endpoint = "unix:///var/lib/kubelet/plugins/storage.csi.kloude.ir/csi.sock"
}
if c.Driver.NodeID == "" {
hostname, err := os.Hostname()
+1 -1
View File
@@ -23,7 +23,7 @@ func TestLoadNormalizesClientDefaults(t *testing.T) {
t.Fatalf("Load failed: %v", err)
}
if cfg.Driver.Name != "storage.csi.kloud.team" {
if cfg.Driver.Name != "storage.csi.kloude.ir" {
t.Fatalf("unexpected driver name: %q", cfg.Driver.Name)
}
if cfg.Client.ServerURL != "http://192.168.84.10:9766" {
+2 -2
View File
@@ -53,10 +53,10 @@ func ApplyEnvOverrides(cfg *Config) {
cfg.Driver.Mode = CSIModeNode
}
if cfg.Driver.Name == "" {
cfg.Driver.Name = "storage.csi.kloud.team"
cfg.Driver.Name = "storage.csi.kloude.ir"
}
if cfg.Driver.Endpoint == "" {
cfg.Driver.Endpoint = "unix:///var/lib/kubelet/plugins/storage.csi.kloud.team/csi.sock"
cfg.Driver.Endpoint = "unix:///var/lib/kubelet/plugins/storage.csi.kloude.ir/csi.sock"
}
}
+3 -3
View File
@@ -3,12 +3,12 @@
#
# When installed with charts/kks-provider-plugin, settings come from env vars instead.
driver {
name = "storage.csi.kloud.team"
endpoint = "unix:///var/lib/kubelet/plugins/storage.csi.kloud.team/csi.sock"
name = "storage.csi.kloude.ir"
endpoint = "unix:///var/lib/kubelet/plugins/storage.csi.kloude.ir/csi.sock"
mode = "all"
}
client {
server_url = "https://csi.kloud.team"
server_url = "https://csi.kloude.ir"
access_token = "REPLACE_WITH_CLUSTER_ACCESS_TOKEN"
}
+3 -3
View File
@@ -1,9 +1,9 @@
package kloudlb
const (
Finalizer = "lb.kloud.team/finalizer"
AnnotationIP = "lb.kloud.team/ip"
AnnotationLBID = "lb.kloud.team/id"
Finalizer = "lb.kloude.ir/finalizer"
AnnotationIP = "lb.kloude.ir/ip"
AnnotationLBID = "lb.kloude.ir/id"
Namespace = "kube-system"
)
+29
View File
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"os"
"strings"
"time"
corev1 "k8s.io/api/core/v1"
@@ -163,10 +164,15 @@ func (c *Controller) sync(ctx context.Context, key string) error {
if ingressIP(svc) != "" {
return nil
}
ports, err := servicePortsToAllocateRules(svc)
if err != nil {
return err
}
lb, err := c.lbClient.Allocate(ctx, provisioner.AllocateRequest{
Namespace: namespace,
Name: name,
Ports: ports,
})
if err != nil {
return err
@@ -217,6 +223,29 @@ func ingressIP(svc *corev1.Service) string {
return ""
}
func servicePortsToAllocateRules(svc *corev1.Service) ([]provisioner.AllocatePortRule, error) {
if svc == nil {
return nil, fmt.Errorf("service is required")
}
if len(svc.Spec.Ports) == 0 {
return nil, fmt.Errorf("service %s/%s has no ports", svc.Namespace, svc.Name)
}
out := make([]provisioner.AllocatePortRule, 0, len(svc.Spec.Ports))
for _, p := range svc.Spec.Ports {
protocol := string(p.Protocol)
if protocol == "" {
protocol = string(corev1.ProtocolTCP)
}
switch protocol {
case string(corev1.ProtocolTCP), string(corev1.ProtocolUDP):
out = append(out, provisioner.AllocatePortRule{Protocol: strings.ToLower(protocol), PortFrom: int(p.Port)})
default:
return nil, fmt.Errorf("service %s/%s has unsupported protocol %q for load balancer firewall", svc.Namespace, svc.Name, protocol)
}
}
return out, nil
}
func containsString(items []string, target string) bool {
for _, item := range items {
if item == target {
+47
View File
@@ -0,0 +1,47 @@
package controller
import (
"testing"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func TestServicePortsToAllocateRules(t *testing.T) {
svc := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "web"},
Spec: corev1.ServiceSpec{Ports: []corev1.ServicePort{{Port: 80, Protocol: corev1.ProtocolTCP}, {Port: 53, Protocol: corev1.ProtocolUDP}}},
}
rules, err := servicePortsToAllocateRules(svc)
if err != nil {
t.Fatalf("servicePortsToAllocateRules: %v", err)
}
if len(rules) != 2 {
t.Fatalf("rules count = %d, want 2", len(rules))
}
if rules[0].Protocol != "tcp" || rules[0].PortFrom != 80 {
t.Fatalf("unexpected first rule: %+v", rules[0])
}
if rules[1].Protocol != "udp" || rules[1].PortFrom != 53 {
t.Fatalf("unexpected second rule: %+v", rules[1])
}
}
func TestServicePortsToAllocateRulesRejectsUnsupportedProtocol(t *testing.T) {
svc := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "web"},
Spec: corev1.ServiceSpec{Ports: []corev1.ServicePort{{Port: 80, Protocol: corev1.ProtocolSCTP}}},
}
if _, err := servicePortsToAllocateRules(svc); err == nil {
t.Fatal("expected error for unsupported protocol")
}
}
func TestServicePortsToAllocateRulesRejectsNoPorts(t *testing.T) {
svc := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "web"}}
if _, err := servicePortsToAllocateRules(svc); err == nil {
t.Fatal("expected error for empty ports")
}
}
+7
View File
@@ -10,4 +10,11 @@ type LoadBalancer struct {
type AllocateRequest struct {
Namespace string `json:"namespace"`
Name string `json:"name"`
Ports []AllocatePortRule `json:"ports,omitempty"`
}
type AllocatePortRule struct {
Protocol string `json:"protocol"`
PortFrom int `json:"portFrom"`
PortTo *int `json:"portTo,omitempty"`
}