update agent
This commit is contained in:
@@ -71,7 +71,7 @@ CREATE TABLE dbo.Packages
|
||||
CONSTRAINT DF_Packages_IsActive DEFAULT 1,
|
||||
CONSTRAINT FK_Packages_CreatedByUser
|
||||
FOREIGN KEY (CreatedByUserId) REFERENCES dbo.Users(Id),
|
||||
CONSTRAINT CK_Packages_PackageType CHECK (PackageType IN (N'deb', N'docker')),
|
||||
CONSTRAINT CK_Packages_PackageType CHECK (PackageType IN (N'deb', N'apt', N'docker')),
|
||||
CONSTRAINT CK_Packages_PackageCode_NotBlank CHECK (LEN(LTRIM(RTRIM(PackageCode))) > 0),
|
||||
CONSTRAINT CK_Packages_PackageName_NotBlank CHECK (LEN(LTRIM(RTRIM(PackageName))) > 0)
|
||||
);
|
||||
|
||||
@@ -204,10 +204,14 @@ function helpers() {
|
||||
return statusClassMap[status] || 'badge-muted';
|
||||
},
|
||||
packageTypeLabel(type) {
|
||||
return type === 'docker' ? 'Docker' : '.deb';
|
||||
if (type === 'docker') return 'Docker';
|
||||
if (type === 'apt') return 'APT';
|
||||
return '.deb';
|
||||
},
|
||||
packageTypeClass(type) {
|
||||
return type === 'docker' ? 'badge-info' : 'badge-primary';
|
||||
if (type === 'docker') return 'badge-info';
|
||||
if (type === 'apt') return 'badge-warning';
|
||||
return 'badge-primary';
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -848,7 +852,8 @@ function requireAdmin(req, res, next) {
|
||||
}
|
||||
|
||||
function normalizePackageType(value) {
|
||||
return String(value || 'deb').toLowerCase() === 'docker' ? 'docker' : 'deb';
|
||||
const packageType = String(value || 'deb').toLowerCase();
|
||||
return ['deb', 'apt', 'docker'].includes(packageType) ? packageType : 'deb';
|
||||
}
|
||||
|
||||
function normalizeApplicationStatus(value) {
|
||||
@@ -1694,8 +1699,13 @@ app.get('/packages/export.csv', asyncRoute(async (req, res) => {
|
||||
|
||||
app.post('/packages', upload.single('packageFile'), asyncRoute(async (req, res) => {
|
||||
try {
|
||||
const artifact = await getArtifactFromUpload(req.file);
|
||||
const packageType = normalizePackageType(req.body.packageType);
|
||||
if (packageType === 'apt' && req.file) {
|
||||
await removeUploadedFile(req.file);
|
||||
}
|
||||
const artifact = packageType === 'apt'
|
||||
? { filePath: null, checksum: null, fileSizeBytes: null }
|
||||
: await getArtifactFromUpload(req.file);
|
||||
const packageCode = String(req.body.packageCode || '').trim();
|
||||
const packageName = String(req.body.packageName || '').trim();
|
||||
const version = String(req.body.version || '').trim();
|
||||
@@ -1742,7 +1752,14 @@ app.post('/packages', upload.single('packageFile'), asyncRoute(async (req, res)
|
||||
createdByUserId: req.currentUser.id
|
||||
});
|
||||
|
||||
redirectWithNotice(res, '/packages', 'success', 'Đã upload package và lưu vào database.');
|
||||
redirectWithNotice(
|
||||
res,
|
||||
'/packages',
|
||||
'success',
|
||||
packageType === 'apt'
|
||||
? 'Đã tạo APT package metadata; không cần upload artifact.'
|
||||
: 'Đã upload package và lưu vào database.'
|
||||
);
|
||||
} catch (error) {
|
||||
await removeUploadedFile(req.file);
|
||||
if (error.code === 'DUPLICATE_PACKAGE') {
|
||||
@@ -1758,7 +1775,6 @@ app.post('/package-versions', upload.single('packageFile'), asyncRoute(async (re
|
||||
let versionInput = null;
|
||||
|
||||
try {
|
||||
const artifact = await getArtifactFromUpload(req.file);
|
||||
const version = String(req.body.version || '').trim();
|
||||
|
||||
if (!req.body.packageId || !version) {
|
||||
@@ -1780,6 +1796,13 @@ app.post('/package-versions', upload.single('packageFile'), asyncRoute(async (re
|
||||
return;
|
||||
}
|
||||
|
||||
if (packageItem.type === 'apt' && req.file) {
|
||||
await removeUploadedFile(req.file);
|
||||
}
|
||||
const artifact = packageItem.type === 'apt'
|
||||
? { filePath: null, checksum: null, fileSizeBytes: null }
|
||||
: await getArtifactFromUpload(req.file);
|
||||
|
||||
if (packageItem.type === 'deb') {
|
||||
const metadataMessage = await getDebUploadMetadataValidationMessage(req.file, packageItem.code, version);
|
||||
if (metadataMessage) {
|
||||
|
||||
@@ -10,6 +10,7 @@ const EMAIL_CONFIRMATION_EXPIRES_MS = Number(process.env.EMAIL_CONFIRMATION_EXPI
|
||||
|
||||
let emailConfirmationSchemaPromise;
|
||||
let applicationOpenUrlSchemaPromise;
|
||||
let packageTypeSchemaPromise;
|
||||
|
||||
function padDatePart(value) {
|
||||
return String(value).padStart(2, '0');
|
||||
@@ -326,6 +327,37 @@ LEFT JOIN dbo.PackageVersions AS pv
|
||||
return applicationOpenUrlSchemaPromise;
|
||||
}
|
||||
|
||||
async function ensurePackageTypeSchema() {
|
||||
if (!packageTypeSchemaPromise) {
|
||||
packageTypeSchemaPromise = getPool().then((pool) => pool.request().query(`
|
||||
IF EXISTS (
|
||||
SELECT 1
|
||||
FROM sys.check_constraints
|
||||
WHERE name = N'CK_Packages_PackageType'
|
||||
AND parent_object_id = OBJECT_ID(N'dbo.Packages')
|
||||
AND definition NOT LIKE N'%apt%'
|
||||
)
|
||||
BEGIN
|
||||
ALTER TABLE dbo.Packages DROP CONSTRAINT CK_Packages_PackageType;
|
||||
END;
|
||||
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM sys.check_constraints
|
||||
WHERE name = N'CK_Packages_PackageType'
|
||||
AND parent_object_id = OBJECT_ID(N'dbo.Packages')
|
||||
)
|
||||
BEGIN
|
||||
ALTER TABLE dbo.Packages WITH CHECK
|
||||
ADD CONSTRAINT CK_Packages_PackageType
|
||||
CHECK (PackageType IN (N'deb', N'apt', N'docker'));
|
||||
END;
|
||||
`));
|
||||
}
|
||||
|
||||
return packageTypeSchemaPromise;
|
||||
}
|
||||
|
||||
function normalizePackageStatus(isActive) {
|
||||
return isActive ? 'Active' : 'Archived';
|
||||
}
|
||||
@@ -850,6 +882,7 @@ async function deleteUser(userId) {
|
||||
}
|
||||
|
||||
async function listPackages() {
|
||||
await ensurePackageTypeSchema();
|
||||
const pool = await getPool();
|
||||
const result = await pool.request().query(`
|
||||
SELECT *
|
||||
@@ -996,7 +1029,10 @@ async function getApplicationById(id) {
|
||||
}
|
||||
|
||||
async function getApplicationManifest(appCode, version, baseUrl) {
|
||||
await ensureApplicationOpenUrlSchema();
|
||||
await Promise.all([
|
||||
ensureApplicationOpenUrlSchema(),
|
||||
ensurePackageTypeSchema()
|
||||
]);
|
||||
const pool = await getPool();
|
||||
const appResult = await pool.request()
|
||||
.input('AppCode', sql.NVarChar(100), String(appCode || '').trim())
|
||||
@@ -1048,6 +1084,17 @@ async function getApplicationManifest(appCode, version, baseUrl) {
|
||||
const components = componentResult.recordset.map((row) => {
|
||||
const installOrder = Number(row.InstallOrder || 10);
|
||||
|
||||
if (row.PackageType === 'apt') {
|
||||
return {
|
||||
componentId: row.PackageCode,
|
||||
type: 'apt',
|
||||
installOrder,
|
||||
required: true,
|
||||
packageName: row.PackageCode,
|
||||
version: row.Version || undefined
|
||||
};
|
||||
}
|
||||
|
||||
if (row.PackageType === 'docker') {
|
||||
return {
|
||||
componentId: row.PackageCode,
|
||||
@@ -1167,6 +1214,7 @@ async function getPackageVersionDownload(packageVersionId) {
|
||||
}
|
||||
|
||||
async function createPackageWithVersion(input) {
|
||||
await ensurePackageTypeSchema();
|
||||
const pool = await getPool();
|
||||
const transaction = new sql.Transaction(pool);
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
<select data-filter-select data-filter-column="type" data-filter-table="packagesTable">
|
||||
<option value="">Tất cả</option>
|
||||
<option value="deb">.deb</option>
|
||||
<option value="apt">APT</option>
|
||||
<option value="docker">Docker</option>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
<span>Package type</span>
|
||||
<select name="packageType">
|
||||
<option value="deb">.deb</option>
|
||||
<option value="apt">APT (Ubuntu repository)</option>
|
||||
<option value="docker">Docker</option>
|
||||
</select>
|
||||
</label>
|
||||
@@ -60,6 +61,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-field full">
|
||||
<small>APT packages only store metadata and do not need an uploaded file. Package code must be an Agent-allowlisted APT name, for example <code>postgresql</code>.</small>
|
||||
</div>
|
||||
<label class="form-field full">
|
||||
<span>Docker image/tag</span>
|
||||
<input type="text" name="dockerImage" placeholder="registry.local/robot/fleet-agent:1.9.0">
|
||||
|
||||
Reference in New Issue
Block a user