new: podman

This commit is contained in:
lollipopkit
2024-01-21 15:12:43 +08:00
parent 7156f08eb8
commit 50bcabbc54
36 changed files with 1097 additions and 795 deletions

View File

@@ -20,7 +20,7 @@ class Backup {
final List<ServerPrivateInfo> spis;
final List<Snippet> snippets;
final List<PrivateKeyInfo> keys;
final Map<String, dynamic> dockerHosts;
final Map<String, dynamic> container;
final Map<String, dynamic> settings;
final Map<String, dynamic> history;
final int? lastModTime;
@@ -31,7 +31,7 @@ class Backup {
required this.spis,
required this.snippets,
required this.keys,
required this.dockerHosts,
required this.container,
required this.settings,
required this.history,
this.lastModTime,
@@ -48,7 +48,7 @@ class Backup {
keys = (json['keys'] as List)
.map((e) => PrivateKeyInfo.fromJson(e))
.toList(),
dockerHosts = json['dockerHosts'] ?? {},
container = json['container'] ?? {},
settings = json['settings'] ?? {},
lastModTime = json['lastModTime'],
history = json['history'] ?? {};
@@ -59,7 +59,7 @@ class Backup {
'spis': spis,
'snippets': snippets,
'keys': keys,
'dockerHosts': dockerHosts,
'container': container,
'settings': settings,
'lastModTime': lastModTime,
'history': history,
@@ -71,7 +71,7 @@ class Backup {
spis = Stores.server.fetch(),
snippets = Stores.snippet.fetch(),
keys = Stores.key.fetch(),
dockerHosts = Stores.docker.box.toJson(),
container = Stores.docker.box.toJson(),
settings = Stores.setting.box.toJson(),
lastModTime = Stores.lastModTime,
history = Stores.history.box.toJson();
@@ -110,8 +110,8 @@ class Backup {
for (final s in history.keys) {
Stores.history.box.put(s, history[s]);
}
for (final k in dockerHosts.keys) {
final val = dockerHosts[k];
for (final k in container.keys) {
final val = container[k];
if (val != null && val is String && val.isNotEmpty) {
Stores.docker.put(k, val);
}

View File

@@ -33,7 +33,7 @@ class SSHErr extends Err<SSHErrType> {
}
}
enum DockerErrType {
enum ContainerErrType {
unknown,
noClient,
notInstalled,
@@ -45,12 +45,12 @@ enum DockerErrType {
parseStats,
}
class DockerErr extends Err<DockerErrType> {
DockerErr({required super.type, super.message}) : super(from: ErrFrom.docker);
class ContainerErr extends Err<ContainerErrType> {
ContainerErr({required super.type, super.message}) : super(from: ErrFrom.docker);
@override
String toString() {
return 'DockerErr<$type>: $message';
return 'ContainerErr<$type>: $message';
}
}

View File

@@ -1,10 +1,10 @@
import 'package:flutter/material.dart';
import 'package:toolbox/core/extension/context/locale.dart';
enum ServerTabMenuType {
enum ServerTabMenu {
terminal,
sftp,
docker,
container,
process,
pkg,
//snippet,
@@ -12,40 +12,40 @@ enum ServerTabMenuType {
IconData get icon {
switch (this) {
case ServerTabMenuType.sftp:
case ServerTabMenu.sftp:
return Icons.insert_drive_file;
//case ServerTabMenuType.snippet:
//return Icons.code;
case ServerTabMenuType.pkg:
case ServerTabMenu.pkg:
return Icons.system_security_update;
case ServerTabMenuType.docker:
case ServerTabMenu.container:
return Icons.view_agenda;
case ServerTabMenuType.process:
case ServerTabMenu.process:
return Icons.list_alt_outlined;
case ServerTabMenuType.terminal:
case ServerTabMenu.terminal:
return Icons.terminal;
}
}
String get toStr {
switch (this) {
case ServerTabMenuType.sftp:
case ServerTabMenu.sftp:
return 'SFTP';
//case ServerTabMenuType.snippet:
//return l10n.snippet;
case ServerTabMenuType.pkg:
case ServerTabMenu.pkg:
return l10n.pkg;
case ServerTabMenuType.docker:
return 'Docker';
case ServerTabMenuType.process:
case ServerTabMenu.container:
return l10n.container;
case ServerTabMenu.process:
return l10n.process;
case ServerTabMenuType.terminal:
case ServerTabMenu.terminal:
return l10n.terminal;
}
}
}
enum DockerMenuType {
enum ContainerMenu {
start,
stop,
restart,
@@ -55,7 +55,7 @@ enum DockerMenuType {
//stats,
;
static List<DockerMenuType> items(bool running) {
static List<ContainerMenu> items(bool running) {
if (running) {
return [
stop,
@@ -72,17 +72,17 @@ enum DockerMenuType {
IconData get icon {
switch (this) {
case DockerMenuType.start:
case ContainerMenu.start:
return Icons.play_arrow;
case DockerMenuType.stop:
case ContainerMenu.stop:
return Icons.stop;
case DockerMenuType.restart:
case ContainerMenu.restart:
return Icons.restart_alt;
case DockerMenuType.rm:
case ContainerMenu.rm:
return Icons.delete;
case DockerMenuType.logs:
case ContainerMenu.logs:
return Icons.logo_dev;
case DockerMenuType.terminal:
case ContainerMenu.terminal:
return Icons.terminal;
// case DockerMenuType.stats:
// return Icons.bar_chart;
@@ -91,24 +91,24 @@ enum DockerMenuType {
String get toStr {
switch (this) {
case DockerMenuType.start:
case ContainerMenu.start:
return l10n.start;
case DockerMenuType.stop:
case ContainerMenu.stop:
return l10n.stop;
case DockerMenuType.restart:
case ContainerMenu.restart:
return l10n.restart;
case DockerMenuType.rm:
case ContainerMenu.rm:
return l10n.delete;
case DockerMenuType.logs:
case ContainerMenu.logs:
return l10n.log;
case DockerMenuType.terminal:
case ContainerMenu.terminal:
return l10n.terminal;
// case DockerMenuType.stats:
// return s.stats;
}
}
PopupMenuItem<DockerMenuType> get widget => _build(this, icon, toStr);
PopupMenuItem<ContainerMenu> get widget => _build(this, icon, toStr);
}
PopupMenuItem<T> _build<T>(T t, IconData icon, String text) {

View File

@@ -224,30 +224,6 @@ const _statusCmds = [
'nvidia-smi -q -x',
];
enum DockerCmdType {
version,
ps,
//stats,
images,
;
String get exec {
switch (this) {
case DockerCmdType.version:
return 'docker version';
case DockerCmdType.ps:
return 'docker ps -a';
// case DockerCmdType.stats:
// return 'docker stats --no-stream';
case DockerCmdType.images:
return 'docker image ls';
}
}
static final execAll =
values.map((e) => e.exec).join(' && echo $seperator && ');
}
enum BSDStatusCmdType {
echo,
time,

View File

@@ -0,0 +1,115 @@
import 'dart:convert';
import 'package:toolbox/core/extension/numx.dart';
import 'package:toolbox/data/model/container/type.dart';
abstract final class ContainerImg {
final String? repository = null;
final String? tag = null;
final String? id = null;
String? get sizeMB;
int? get containersCount;
factory ContainerImg.fromRawJson(String s, ContainerType typ) => typ.img(s);
}
final class PodmanImg implements ContainerImg {
@override
final String? repository;
@override
final String? tag;
@override
final String? id;
final int? created;
final int? size;
final int? containers;
PodmanImg({
this.repository,
this.tag,
this.id,
this.created,
this.size,
this.containers,
});
@override
String? get sizeMB => size?.convertBytes;
@override
int? get containersCount => containers;
factory PodmanImg.fromRawJson(String str) =>
PodmanImg.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory PodmanImg.fromJson(Map<String, dynamic> json) => PodmanImg(
repository: json["repository"],
tag: json["tag"],
id: json["Id"],
created: json["Created"],
size: json["Size"],
containers: json["Containers"],
);
Map<String, dynamic> toJson() => {
"repository": repository,
"tag": tag,
"Id": id,
"Created": created,
"Size": size,
"Containers": containers,
};
}
final class DockerImg implements ContainerImg {
final String containers;
final String createdAt;
@override
final String id;
@override
final String repository;
final String size;
@override
final String tag;
DockerImg({
required this.containers,
required this.createdAt,
required this.id,
required this.repository,
required this.size,
required this.tag,
});
@override
String? get sizeMB => size;
@override
int? get containersCount =>
containers == 'N/A' ? 0 : int.tryParse(containers);
factory DockerImg.fromRawJson(String str) =>
DockerImg.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory DockerImg.fromJson(Map<String, dynamic> json) => DockerImg(
containers: json["Containers"],
createdAt: json["CreatedAt"],
id: json["ID"],
repository: json["Repository"],
size: json["Size"],
tag: json["Tag"],
);
Map<String, dynamic> toJson() => {
"Containers": containers,
"CreatedAt": createdAt,
"ID": id,
"Repository": repository,
"Size": size,
"Tag": tag,
};
}

View File

@@ -0,0 +1,127 @@
import 'dart:convert';
import 'package:toolbox/data/model/container/type.dart';
abstract final class ContainerPs {
final String? id = null;
final String? image = null;
String? get name;
String? get cmd;
bool get running;
factory ContainerPs.fromRawJson(String s, ContainerType typ) => typ.ps(s);
}
final class PodmanPs implements ContainerPs {
final List<String>? command;
final DateTime? created;
final bool? exited;
@override
final String? id;
@override
final String? image;
final List<String>? names;
final int? startedAt;
PodmanPs({
this.command,
this.created,
this.exited,
this.id,
this.image,
this.names,
this.startedAt,
});
@override
String? get name => names?.firstOrNull;
@override
String? get cmd => command?.firstOrNull;
@override
bool get running => exited != true;
factory PodmanPs.fromRawJson(String str) =>
PodmanPs.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory PodmanPs.fromJson(Map<String, dynamic> json) => PodmanPs(
command: json["Command"] == null
? []
: List<String>.from(json["Command"]!.map((x) => x)),
created:
json["Created"] == null ? null : DateTime.parse(json["Created"]),
exited: json["Exited"],
id: json["Id"],
image: json["Image"],
names: json["Names"] == null
? []
: List<String>.from(json["Names"]!.map((x) => x)),
startedAt: json["StartedAt"],
);
Map<String, dynamic> toJson() => {
"Command":
command == null ? [] : List<dynamic>.from(command!.map((x) => x)),
"Created": created?.toIso8601String(),
"Exited": exited,
"Id": id,
"Image": image,
"Names": names == null ? [] : List<dynamic>.from(names!.map((x) => x)),
"StartedAt": startedAt,
};
}
final class DockerPs implements ContainerPs {
final String? command;
final String? createdAt;
@override
final String? id;
@override
final String? image;
final String? names;
final String? state;
DockerPs({
this.command,
this.createdAt,
this.id,
this.image,
this.names,
this.state,
});
@override
String? get name => names;
@override
String? get cmd => command;
@override
bool get running => state == 'running';
factory DockerPs.fromRawJson(String str) =>
DockerPs.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory DockerPs.fromJson(Map<String, dynamic> json) => DockerPs(
command: json["Command"],
createdAt: json["CreatedAt"],
id: json["ID"],
image: json["Image"],
names: json["Names"],
state: json["State"],
);
Map<String, dynamic> toJson() => {
"Command": command,
"CreatedAt": createdAt,
"ID": id,
"Image": image,
"Names": names,
"State": state,
};
}

View File

@@ -0,0 +1,18 @@
import 'package:toolbox/data/model/container/image.dart';
import 'package:toolbox/data/model/container/ps.dart';
enum ContainerType {
docker,
podman,
;
ContainerPs Function(String str) get ps => switch (this) {
ContainerType.docker => DockerPs.fromRawJson,
ContainerType.podman => PodmanPs.fromRawJson,
};
ContainerImg Function(String str) get img => switch (this) {
ContainerType.docker => DockerImg.fromRawJson,
ContainerType.podman => PodmanImg.fromRawJson,
};
}

View File

@@ -0,0 +1,69 @@
import 'dart:convert';
class Containerd {
final ContainerdClient client;
Containerd({
required this.client,
});
factory Containerd.fromRawJson(String str) => Containerd.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory Containerd.fromJson(Map<String, dynamic> json) => Containerd(
client: ContainerdClient.fromJson(json["Client"]),
);
Map<String, dynamic> toJson() => {
"Client": client.toJson(),
};
}
class ContainerdClient {
final String apiVersion;
final String version;
final String goVersion;
final String gitCommit;
final String builtTime;
final int built;
final String osArch;
final String os;
ContainerdClient({
required this.apiVersion,
required this.version,
required this.goVersion,
required this.gitCommit,
required this.builtTime,
required this.built,
required this.osArch,
required this.os,
});
factory ContainerdClient.fromRawJson(String str) => ContainerdClient.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory ContainerdClient.fromJson(Map<String, dynamic> json) => ContainerdClient(
apiVersion: json["APIVersion"],
version: json["Version"],
goVersion: json["GoVersion"],
gitCommit: json["GitCommit"],
builtTime: json["BuiltTime"],
built: json["Built"],
osArch: json["OsArch"],
os: json["Os"],
);
Map<String, dynamic> toJson() => {
"APIVersion": apiVersion,
"Version": version,
"GoVersion": goVersion,
"GitCommit": gitCommit,
"BuiltTime": builtTime,
"Built": built,
"OsArch": osArch,
"Os": os,
};
}

View File

@@ -1,47 +0,0 @@
final _dockerImageReg = RegExp(r'(\S+) +(\S+) +(\S+) +(.+) +(\S+)');
class DockerImage {
final String repo;
final String tag;
final String id;
final String created;
final String size;
static final Map<String, DockerImage> _cache = <String, DockerImage>{};
DockerImage({
required this.repo,
required this.tag,
required this.id,
required this.created,
required this.size,
});
Map<String, dynamic> toJson() {
return {
'repo': repo,
'tag': tag,
'id': id,
'created': created,
'size': size,
};
}
factory DockerImage.fromRawStr(String raw) {
return _cache.putIfAbsent(raw, () => _parse(raw));
}
static DockerImage _parse(String raw) {
final match = _dockerImageReg.firstMatch(raw);
if (match == null) {
throw Exception('Invalid docker image: $raw');
}
return DockerImage(
repo: match.group(1)!,
tag: match.group(2)!,
id: match.group(3)!,
created: match.group(4)!,
size: match.group(5)!,
);
}
}

View File

@@ -1,64 +0,0 @@
final _seperator = RegExp(' +');
class DockerPsItem {
late String containerId;
late String image;
late String command;
late String created;
late String status;
late String ports;
late String name;
// String? cpu;
// String? mem;
// String? net;
// String? disk;
DockerPsItem(
this.containerId,
this.image,
this.command,
this.created,
this.status,
this.ports,
this.name,
);
DockerPsItem.fromRawString(String rawString) {
List<String> parts = rawString.split(_seperator);
parts = parts.map((e) => e.trim()).toList();
containerId = parts[0];
image = parts[1];
command = parts[2].trim();
created = parts[3];
status = parts[4];
if (running && parts.length > 6) {
ports = parts[5];
name = parts[6];
} else {
ports = '';
name = parts[5];
}
}
// void parseStats(String rawString) {
// if (rawString.isEmpty) {
// return;
// }
// final parts = rawString.split(_seperator);
// if (parts.length != 8) {
// return;
// }
// cpu = parts[2];
// mem = parts[3];
// net = parts[5];
// disk = parts[6];
// }
bool get running => status.contains('Up ');
@override
String toString() {
return 'DockerPsItem<$containerId@$name>';
}
}