Skip to content
Snippets Groups Projects
Unverified Commit 90f85b99 authored by Sebastian Poxhofer's avatar Sebastian Poxhofer Committed by GitHub
Browse files

feat(manager/fleet): implement Rancher Fleet manager (#16138)


* feat(manager/fleet): implement Rancher Fleet manager

* Apply suggestions from code review

Co-authored-by: default avatarHonkingGoose <34918129+HonkingGoose@users.noreply.github.com>

* Update lib/modules/manager/fleet/extract.spec.ts

Co-authored-by: default avatarMichael Kriese <michael.kriese@visualon.de>

* docs(fleet): add tsdocs

* fixup test null checks

* docs: add default filematch

* chore: rename tempDep to dep

* apply change requests

* catch exceptions from yaml-js

* trigger yaml parse error

Co-authored-by: default avatarHonkingGoose <34918129+HonkingGoose@users.noreply.github.com>
Co-authored-by: default avatarMichael Kriese <michael.kriese@visualon.de>
parent 8270d551
No related branches found
No related tags found
No related merge requests found
......@@ -21,6 +21,7 @@ import * as depsEdn from './deps-edn';
import * as dockerCompose from './docker-compose';
import * as dockerfile from './dockerfile';
import * as droneci from './droneci';
import * as fleet from './fleet';
import * as flux from './flux';
import * as fvm from './fvm';
import * as gitSubmodules from './git-submodules';
......@@ -97,6 +98,7 @@ api.set('deps-edn', depsEdn);
api.set('docker-compose', dockerCompose);
api.set('dockerfile', dockerfile);
api.set('droneci', droneci);
api.set('fleet', fleet);
api.set('flux', flux);
api.set('fvm', fvm);
api.set('git-submodules', gitSubmodules);
......
defaultNamespace: cert-manager
helm:
chart: cert-manager
repo: https://charts.jetstack.io
releaseName: cert-manager
values:
installCRDs: true
---
defaultNamespace: logging-system
helm:
chart: logging-operator
releaseName: logging-operator
version: 3.17.7
values:
---
defaultNamespace: monitoring
helm:
repo: https://prometheus-community.github.io/helm-charts
releaseName: kube-prometheus
version: 35.4.2
---
defaultNamespace: monitoring
helm:
chart: './charts/example'
releaseName: anExample
version: 35.4.2
kind: GitRepo
apiVersion: fleet.cattle.io/v1alpha1
metadata:
name: renovate
namespace: fleet-local
spec:
revision: 32.89.2
paths:
- simple
---
kind: GitRepo
apiVersion: fleet.cattle.io/v1alpha1
metadata:
name: rancher
namespace: fleet-local
spec:
repo: https://github.com/rancher/rancher
paths:
- simple
defaultNamespace: cert-manager
helm:
chart: cert-manager
repo: https://charts.jetstack.io
releaseName: cert-manager
version: v1.8.0
values:
installCRDs: true
---
defaultNamespace: logging-system
helm:
chart: logging-operator
repo: "https://kubernetes-charts.banzaicloud.com"
releaseName: logging-operator
version: 3.17.7
values:
kind: GitRepo
apiVersion: fleet.cattle.io/v1alpha1
metadata:
name: my-repo
namespace: fleet-local
spec:
repo: https://github.com/rancher/fleet-examples
revision: v0.3.0
paths:
- simple
---
kind: GitRepo
apiVersion: fleet.cattle.io/v1alpha1
metadata:
name: renovate
namespace: fleet-local
spec:
repo: https://github.com/renovatebot/renovate
revision: 32.89.2
paths:
- simple
import { Fixtures } from '../../../../test/fixtures';
import { extractPackageFile } from '.';
const validFleetYaml = Fixtures.get('valid_fleet.yaml');
const inValidFleetYaml = Fixtures.get('invalid_fleet.yaml');
const validGitRepoYaml = Fixtures.get('valid_gitrepo.yaml');
const invalidGitRepoYaml = Fixtures.get('invalid_gitrepo.yaml');
const configMapYaml = Fixtures.get('configmap.yaml', '../kubernetes');
describe('modules/manager/fleet/extract', () => {
afterEach(() => {
jest.restoreAllMocks();
});
describe('extractPackageFile()', () => {
it('should return null if empty content', () => {
const result = extractPackageFile('', 'fleet.yaml');
expect(result).toBeNull();
});
it('should return null if a unknown manifest is supplied', () => {
const result = extractPackageFile(configMapYaml, 'fleet.yaml');
expect(result).toBeNull();
});
describe('fleet.yaml', () => {
it('should return null if content is a malformed YAML', () => {
const result = extractPackageFile(
`apiVersion: v1
kind: Fleet
< `,
'fleet.yaml'
);
expect(result).toBeNull();
});
it('should parse valid configuration', () => {
const result = extractPackageFile(validFleetYaml, 'fleet.yaml');
expect(result).not.toBeNull();
expect(result?.deps).toMatchObject([
{
currentValue: 'v1.8.0',
datasource: 'helm',
depName: 'cert-manager',
registryUrls: ['https://charts.jetstack.io'],
depType: 'fleet',
},
{
currentValue: '3.17.7',
datasource: 'helm',
depName: 'logging-operator',
registryUrls: ['https://kubernetes-charts.banzaicloud.com'],
depType: 'fleet',
},
]);
});
it('should parse parse invalid configurations', () => {
const result = extractPackageFile(inValidFleetYaml, 'fleet.yaml');
expect(result).not.toBeNull();
expect(result?.deps).toMatchObject([
{
skipReason: 'no-version',
datasource: 'helm',
depName: 'cert-manager',
registryUrls: ['https://charts.jetstack.io'],
depType: 'fleet',
},
{
datasource: 'helm',
depName: 'logging-operator',
skipReason: 'no-repository',
depType: 'fleet',
},
{
datasource: 'helm',
skipReason: 'missing-depname',
depType: 'fleet',
},
{
datasource: 'helm',
depName: './charts/example',
skipReason: 'local-chart',
depType: 'fleet',
},
]);
});
});
describe('GitRepo', () => {
it('should return null if content is a malformed YAML', () => {
const result = extractPackageFile(
`apiVersion: v1
kind: GitRepo
< `,
'test.yaml'
);
expect(result).toBeNull();
});
it('should parse valid configuration', () => {
const result = extractPackageFile(validGitRepoYaml, 'test.yaml');
expect(result).not.toBeNull();
expect(result?.deps).toMatchObject([
{
currentValue: 'v0.3.0',
datasource: 'git-tags',
depName: 'https://github.com/rancher/fleet-examples',
depType: 'git_repo',
sourceUrl: 'https://github.com/rancher/fleet-examples',
},
{
currentValue: '32.89.2',
datasource: 'git-tags',
depName: 'https://github.com/renovatebot/renovate',
depType: 'git_repo',
sourceUrl: 'https://github.com/renovatebot/renovate',
},
]);
});
it('should parse invalid configuration', () => {
const result = extractPackageFile(invalidGitRepoYaml, 'test.yaml');
expect(result).not.toBeNull();
expect(result?.deps).toMatchObject([
{
datasource: 'git-tags',
depType: 'git_repo',
skipReason: 'missing-depname',
},
{
datasource: 'git-tags',
depName: 'https://github.com/rancher/rancher',
depType: 'git_repo',
skipReason: 'no-version',
sourceUrl: 'https://github.com/rancher/rancher',
},
]);
});
});
});
});
import is from '@sindresorhus/is';
import { loadAll } from 'js-yaml';
import { logger } from '../../../logger';
import { regEx } from '../../../util/regex';
import { GitTagsDatasource } from '../../datasource/git-tags';
import { HelmDatasource } from '../../datasource/helm';
import { checkIfStringIsPath } from '../terraform/util';
import type { PackageDependency, PackageFile } from '../types';
import type { FleetFile, FleetFileHelm, GitRepo } from './types';
function extractGitRepo(doc: GitRepo): PackageDependency {
const dep: PackageDependency = {
depType: 'git_repo',
datasource: GitTagsDatasource.id,
};
const repo = doc.spec?.repo;
if (!repo) {
return {
...dep,
skipReason: 'missing-depname',
};
}
dep.sourceUrl = repo;
dep.depName = repo;
const currentValue = doc.spec.revision;
if (!currentValue) {
return {
...dep,
skipReason: 'no-version',
};
}
return {
...dep,
currentValue,
};
}
function extractFleetFile(doc: FleetFileHelm): PackageDependency {
const dep: PackageDependency = {
depType: 'fleet',
datasource: HelmDatasource.id,
};
if (!doc.chart) {
return {
...dep,
skipReason: 'missing-depname',
};
}
dep.depName = doc.chart;
if (!doc.repo) {
if (checkIfStringIsPath(doc.chart)) {
return {
...dep,
skipReason: 'local-chart',
};
}
return {
...dep,
skipReason: 'no-repository',
};
}
dep.registryUrls = [doc.repo];
const currentValue = doc.version;
if (!doc.version) {
return {
...dep,
skipReason: 'no-version',
};
}
return {
...dep,
currentValue,
};
}
export function extractPackageFile(
content: string,
packageFile: string
): PackageFile | null {
if (!content) {
return null;
}
const deps: PackageDependency[] = [];
try {
if (regEx('fleet.ya?ml').test(packageFile)) {
// TODO: fix me (#9610)
const docs = loadAll(content, null, { json: true }) as FleetFile[];
const fleetDeps = docs
.filter((doc) => is.truthy(doc?.helm))
.flatMap((doc) => extractFleetFile(doc.helm));
deps.push(...fleetDeps);
} else {
// TODO: fix me (#9610)
const docs = loadAll(content, null, { json: true }) as GitRepo[];
const gitRepoDeps = docs
.filter((doc) => doc.kind === 'GitRepo') // ensure only GitRepo manifests are processed
.flatMap((doc) => extractGitRepo(doc));
deps.push(...gitRepoDeps);
}
} catch (err) {
logger.error({ error: err, packageFile }, 'Failed to parse fleet YAML');
}
return deps.length ? { deps } : null;
}
import { GitTagsDatasource } from '../../datasource/git-tags';
import { HelmDatasource } from '../../datasource/helm';
export { extractPackageFile } from './extract';
export const defaultConfig = {
fileMatch: ['(^|/)fleet.ya?ml'],
};
export const supportedDatasources = [GitTagsDatasource.id, HelmDatasource.id];
Can upgrade bundle definitions and GitRepo YAML manifests of Rancher Fleet.
By default, only bundles with Helm references will be upgraded.
To enable GitRepo updates you have to extend your [`fileMatch`](https://docs.renovatebot.com/configuration-options/#filematch) configuration.
```json
{
"fileMatch": ["'(^|/)fleet.ya?ml", "myGitRepoManifests\\.yaml"]
}
```
/**
Represent a GitRepo Kubernetes manifest of Fleet.
@link https://fleet.rancher.io/gitrepo-add/#create-gitrepo-instance
*/
export interface GitRepo {
metadata: {
name: string;
};
kind: string;
spec: {
repo: string;
revision?: string;
};
}
/**
Represent a Bundle configuration of Fleet, which is located in `fleet.yaml` files.
@link https://fleet.rancher.io/gitrepo-structure/#fleetyaml
*/
export interface FleetFile {
helm: FleetFileHelm;
}
export interface FleetFileHelm {
chart: string;
repo?: string;
version: string;
releaseName: string;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment